VirtualBox

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

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

SUPDrvTracing: display more info on argument list bugs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.3 KB
Line 
1/* $Id: SUPDrvTracer.cpp 40886 2012-04-12 00:13:37Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Tracer Interface.
4 */
5
6/*
7 * Copyright (C) 2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#define LOG_GROUP LOG_GROUP_SUP_DRV
32#define SUPDRV_AGNOSTIC
33#include "SUPDrvInternal.h"
34
35#include <VBox/err.h>
36#include <VBox/log.h>
37#include <VBox/VBoxTpG.h>
38
39#include <iprt/assert.h>
40#include <iprt/ctype.h>
41#include <iprt/list.h>
42#include <iprt/mem.h>
43#include <iprt/semaphore.h>
44#include <iprt/thread.h>
45
46
47/*******************************************************************************
48* Structures and Typedefs *
49*******************************************************************************/
50/**
51 * Data for a tracepoint provider.
52 */
53typedef struct SUPDRVTPPROVIDER
54{
55 /** The entry in the provider list for this image. */
56 RTLISTNODE ListEntry;
57
58 /** The core structure. */
59 SUPDRVVDTPROVIDERCORE Core;
60
61 /** Pointer to the image this provider resides in. NULL if it's a
62 * driver. */
63 PSUPDRVLDRIMAGE pImage;
64 /** The session this provider is associated with if registered via
65 * SUPR0VtgRegisterDrv. NULL if pImage is set. */
66 PSUPDRVSESSION pSession;
67
68 /** Used to indicate that we've called pfnProviderDeregistered already and it
69 * failed because the provider was busy. Next time we must try
70 * pfnProviderDeregisterZombie.
71 *
72 * @remarks This does not necessiarly mean the provider is in the zombie
73 * list. See supdrvTracerCommonDeregisterImpl. */
74 bool fZombie;
75 /** Set if the provider has been successfully registered with the
76 * tracer. */
77 bool fRegistered;
78 /** The provider name (for logging purposes). */
79 char szName[1];
80} SUPDRVTPPROVIDER;
81/** Pointer to the data for a tracepoint provider. */
82typedef SUPDRVTPPROVIDER *PSUPDRVTPPROVIDER;
83
84
85/*******************************************************************************
86* Defined Constants And Macros *
87*******************************************************************************/
88/** 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 {
322 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - iProbe=%u cArgs=%u\n", i, pArgList->fHaveLargeArgs, pArgList->cArgs);
323 return VERR_SUPDRV_VTG_BAD_ARGLIST;
324 }
325 if (pArgList->fHaveLargeArgs >= 2)
326 {
327 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - iProbe=%u fHaveLargeArgs=%d\n", i, pArgList->fHaveLargeArgs);
328 return VERR_SUPDRV_VTG_BAD_ARGLIST;
329 }
330 if ( pArgList->abReserved[0]
331 || pArgList->abReserved[1])
332 {
333 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - reserved MBZ iProbe=%u\n", i);
334 return VERR_SUPDRV_VTG_BAD_ARGLIST;
335 }
336 fHaveLargeArgs = false;
337 iArg = pArgList->cArgs;
338 while (iArg-- > 0)
339 {
340 uint32_t const fType = pArgList->aArgs[iArg].fType;
341 if (fType & ~VTG_TYPE_VALID_MASK)
342 {
343 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - fType=%#x iArg=%u iProbe=%u (#0)\n", fType, iArg, i);
344 return VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
345 }
346
347 switch (pArgList->aArgs[iArg].fType & VTG_TYPE_SIZE_MASK)
348 {
349 case 0:
350 if (pArgList->aArgs[iArg].fType & VTG_TYPE_FIXED_SIZED)
351 {
352 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - fType=%#x iArg=%u iProbe=%u (#1)\n", fType, iArg, i);
353 return VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
354 }
355 break;
356 case 1: case 2: case 4: case 8:
357 break;
358 default:
359 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - fType=%#x iArg=%u iProbe=%u (#2)\n", fType, iArg, i);
360 return VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
361 }
362 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
363 fHaveLargeArgs = true;
364
365 MY_VALIDATE_STR(pArgList->aArgs[iArg].offType);
366 }
367 if ((uint8_t)fHaveLargeArgs != pArgList->fHaveLargeArgs)
368 {
369 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - iProbe=%u fHaveLargeArgs=%d expected %d\n",
370 i, pArgList->fHaveLargeArgs, fHaveLargeArgs);
371 return VERR_SUPDRV_VTG_BAD_PROBE;
372 }
373 }
374
375 /*
376 * Check that pafProbeEnabled is all zero.
377 */
378 i = pVtgHdr->cbProbeEnabled;
379 while (i-- > 0)
380 if (pVtgHdr->pafProbeEnabled[0])
381 return VERR_SUPDRV_VTG_BAD_PROBE_ENABLED;
382
383 /*
384 * Probe locations.
385 */
386 i = pVtgHdr->paProbLocsEnd - pVtgHdr->paProbLocs;
387 while (i-- > 0)
388 {
389 if (pVtgHdr->paProbLocs[i].uLine >= _1G)
390 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
391 if (pVtgHdr->paProbLocs[i].fEnabled)
392 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
393 if (pVtgHdr->paProbLocs[i].idProbe != UINT32_MAX)
394 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
395 MY_WITHIN_IMAGE(pVtgHdr->paProbLocs[i].pszFunction, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
396 offTmp = (uintptr_t)pVtgHdr->paProbLocs[i].pbProbe - (uintptr_t)pVtgHdr->paProbes;
397 if (offTmp >= pVtgHdr->cbProbes)
398 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
399 if (offTmp / sizeof(VTGDESCPROBE) * sizeof(VTGDESCPROBE) != offTmp)
400 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
401 }
402
403 return VINF_SUCCESS;
404#undef MY_VALIDATE_STR
405#undef MY_VALIDATE_PTR
406#undef MY_WITHIN_IMAGE
407}
408
409
410/**
411 * Gets a string from the string table.
412 *
413 * @returns Pointer to the string.
414 * @param pVtgHdr The VTG object header.
415 * @param offStrTab The string table offset.
416 */
417static const char *supdrvVtgGetString(PVTGOBJHDR pVtgHdr, uint32_t offStrTab)
418{
419 Assert(offStrTab < pVtgHdr->cbStrTab);
420 return &pVtgHdr->pachStrTab[offStrTab];
421}
422
423
424/**
425 * Frees the provider structure and associated resources.
426 *
427 * @param pProv The provider to free.
428 */
429static void supdrvTracerFreeProvider(PSUPDRVTPPROVIDER pProv)
430{
431 LOG_TRACER(("Freeing tracepoint provider '%s' / %p\n", pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
432 pProv->fRegistered = false;
433 pProv->fZombie = true;
434 pProv->Core.pDesc = NULL;
435 pProv->Core.pHdr = NULL;
436 RT_ZERO(pProv->Core.TracerData);
437 RTMemFree(pProv);
438}
439
440
441/**
442 * Deregisters a provider.
443 *
444 * If the provider is still busy, it will be put in the zombie list.
445 *
446 * @param pDevExt The device extension.
447 * @param pProv The provider.
448 *
449 * @remarks The caller owns mtxTracer.
450 */
451static void supdrvTracerDeregisterVtgObj(PSUPDRVDEVEXT pDevExt, PSUPDRVTPPROVIDER pProv)
452{
453 int rc;
454 if (!pProv->fRegistered || !pDevExt->pTracerOps)
455 rc = VINF_SUCCESS;
456 else
457 rc = pDevExt->pTracerOps->pfnProviderDeregister(pDevExt->pTracerOps, &pProv->Core);
458 if (RT_SUCCESS(rc))
459 {
460 supdrvTracerFreeProvider(pProv);
461 return;
462 }
463
464 pProv->fZombie = true;
465 RTListAppend(&pDevExt->TracerProviderZombieList, &pProv->ListEntry);
466 LOG_TRACER(("Invalidated provider '%s' / %p and put it on the zombie list (rc=%Rrc)\n",
467 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
468}
469
470
471/**
472 * Processes the zombie list.
473 *
474 * @param pDevExt The device extension.
475 */
476static void supdrvTracerProcessZombies(PSUPDRVDEVEXT pDevExt)
477{
478 PSUPDRVTPPROVIDER pProv, pProvNext;
479
480 RTSemFastMutexRequest(pDevExt->mtxTracer);
481 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
482 {
483 int rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
484 if (RT_SUCCESS(rc))
485 {
486 RTListNodeRemove(&pProv->ListEntry);
487 supdrvTracerFreeProvider(pProv);
488 }
489 }
490 RTSemFastMutexRelease(pDevExt->mtxTracer);
491}
492
493
494/**
495 * Unregisters all providers, including zombies, waiting for busy providers to
496 * go idle and unregister smoothly.
497 *
498 * This may block.
499 *
500 * @param pDevExt The device extension.
501 */
502static void supdrvTracerRemoveAllProviders(PSUPDRVDEVEXT pDevExt)
503{
504 uint32_t i;
505 PSUPDRVTPPROVIDER pProv;
506 PSUPDRVTPPROVIDER pProvNext;
507
508 /*
509 * Unregister all probes (there should only be one).
510 */
511 RTSemFastMutexRequest(pDevExt->mtxTracer);
512 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
513 {
514 RTListNodeRemove(&pProv->ListEntry);
515 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
516 }
517 RTSemFastMutexRelease(pDevExt->mtxTracer);
518
519 /*
520 * Try unregister zombies now, sleep on busy ones and tracer opens.
521 */
522 for (i = 0; ; i++)
523 {
524 bool fEmpty;
525
526 RTSemFastMutexRequest(pDevExt->mtxTracer);
527
528 /* Zombies */
529 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
530 {
531 int rc;
532 LOG_TRACER(("supdrvTracerRemoveAllProviders: Attemting to unregister '%s' / %p...\n",
533 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
534
535 if (pDevExt->pTracerOps)
536 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
537 else
538 rc = VINF_SUCCESS;
539 if (!rc)
540 {
541 RTListNodeRemove(&pProv->ListEntry);
542 supdrvTracerFreeProvider(pProv);
543 }
544 else if (!(i & 0xf))
545 SUPR0Printf("supdrvTracerRemoveAllProviders: Waiting on busy provider '%s' / %p (rc=%d)\n",
546 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
547 else
548 LOG_TRACER(("supdrvTracerRemoveAllProviders: Failed to unregister provider '%s' / %p - rc=%d\n",
549 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
550 }
551
552 fEmpty = RTListIsEmpty(&pDevExt->TracerProviderZombieList);
553
554 /* Tracer opens. */
555 if ( pDevExt->cTracerOpens
556 && pDevExt->pTracerOps)
557 {
558 fEmpty = false;
559 if (!(i & 0xf))
560 SUPR0Printf("supdrvTracerRemoveAllProviders: Waiting on %u opens\n", pDevExt->cTracerOpens);
561 else
562 LOG_TRACER(("supdrvTracerRemoveAllProviders: Waiting on %u opens\n", pDevExt->cTracerOpens));
563 }
564
565 RTSemFastMutexRelease(pDevExt->mtxTracer);
566
567 if (fEmpty)
568 break;
569
570 /* Delay...*/
571 RTThreadSleep(1000);
572 }
573}
574
575
576/**
577 * Registers the VTG tracepoint providers of a driver.
578 *
579 * @returns VBox status code.
580 * @param pszName The driver name.
581 * @param pVtgHdr The VTG object header.
582 * @param pVtgObj The size of the VTG object.
583 * @param pImage The image if applicable.
584 * @param pSession The session if applicable.
585 * @param pszModName The module name.
586 */
587static int supdrvTracerRegisterVtgObj(PSUPDRVDEVEXT pDevExt, PVTGOBJHDR pVtgHdr, size_t cbVtgObj, PSUPDRVLDRIMAGE pImage,
588 PSUPDRVSESSION pSession, const char *pszModName)
589{
590 int rc;
591 uintptr_t i;
592 PSUPDRVTPPROVIDER pProv;
593
594 /*
595 * Validate input.
596 */
597 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
598 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
599 AssertPtrNullReturn(pImage, VERR_INVALID_POINTER);
600 AssertPtrNullReturn(pSession, VERR_INVALID_POINTER);
601 AssertPtrReturn(pszModName, VERR_INVALID_POINTER);
602
603 if (pImage)
604 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, (const uint8_t *)pImage->pvImage, pImage->cbImageBits);
605 else
606 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, NULL, 0);
607 if (RT_FAILURE(rc))
608 return rc;
609
610 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
611 if (RT_FAILURE(rc))
612 return rc;
613 RTListForEach(&pDevExt->TracerProviderList, pProv, SUPDRVTPPROVIDER, ListEntry)
614 {
615 if (pProv->Core.pHdr == pVtgHdr)
616 {
617 rc = VERR_SUPDRV_VTG_ALREADY_REGISTERED;
618 break;
619 }
620 if ( pProv->pSession == pSession
621 && pProv->pImage == pImage)
622 {
623 rc = VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION;
624 break;
625 }
626 }
627 RTSemFastMutexRelease(pDevExt->mtxTracer);
628 if (RT_FAILURE(rc))
629 return rc;
630
631 /*
632 * Register the providers.
633 */
634 i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
635 while (i-- > 0)
636 {
637 PVTGDESCPROVIDER pDesc = &pVtgHdr->paProviders[i];
638 const char *pszName = supdrvVtgGetString(pVtgHdr, pDesc->offName);
639 size_t const cchName = strlen(pszName);
640 pProv = (PSUPDRVTPPROVIDER)RTMemAllocZ(RT_OFFSETOF(SUPDRVTPPROVIDER, szName[cchName + 1]));
641 if (pProv)
642 {
643 pProv->Core.pDesc = pDesc;
644 pProv->Core.pHdr = pVtgHdr;
645 pProv->Core.pszName = &pProv->szName[0];
646 pProv->Core.pszModName = pszModName;
647 pProv->pImage = pImage;
648 pProv->pSession = pSession;
649 pProv->fZombie = false;
650 pProv->fRegistered = true;
651 memcpy(&pProv->szName[0], pszName, cchName + 1);
652
653 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
654 if (RT_SUCCESS(rc))
655 {
656 if ( pDevExt->pTracerOps
657 && !pDevExt->fTracerUnloading)
658 rc = pDevExt->pTracerOps->pfnProviderRegister(pDevExt->pTracerOps, &pProv->Core);
659 else
660 {
661 pProv->fRegistered = false;
662 rc = VINF_SUCCESS;
663 }
664 if (RT_SUCCESS(rc))
665 {
666 RTListAppend(&pDevExt->TracerProviderList, &pProv->ListEntry);
667 RTSemFastMutexRelease(pDevExt->mtxTracer);
668 LOG_TRACER(("Registered tracepoint provider '%s' in '%s' -> %p\n",
669 pProv->szName, pszModName, pProv->Core.TracerData.DTrace.idProvider));
670 }
671 else
672 {
673 RTSemFastMutexRelease(pDevExt->mtxTracer);
674 LOG_TRACER(("Failed to register tracepoint provider '%s' in '%s' -> %Rrc\n",
675 pProv->szName, pszModName, rc));
676 RTMemFree(pProv);
677 }
678 }
679 }
680 else
681 rc = VERR_NO_MEMORY;
682
683 if (RT_FAILURE(rc))
684 {
685 PSUPDRVTPPROVIDER pProvNext;
686 supdrvTracerFreeProvider(pProv);
687
688 RTSemFastMutexRequest(pDevExt->mtxTracer);
689 RTListForEachReverseSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
690 {
691 if (pProv->Core.pHdr == pVtgHdr)
692 {
693 RTListNodeRemove(&pProv->ListEntry);
694 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
695 }
696 }
697 RTSemFastMutexRelease(pDevExt->mtxTracer);
698 return rc;
699 }
700 }
701
702 return VINF_SUCCESS;
703}
704
705
706/**
707 * Registers the VTG tracepoint providers of a driver.
708 *
709 * @returns VBox status code.
710 * @param pSession The support driver session handle.
711 * @param pVtgHdr The VTG header.
712 * @param pszName The driver name.
713 */
714SUPR0DECL(int) SUPR0TracerRegisterDrv(PSUPDRVSESSION pSession, PVTGOBJHDR pVtgHdr, const char *pszName)
715{
716 int rc;
717
718 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
719 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
720 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
721 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
722 LOG_TRACER(("SUPR0TracerRegisterDrv: pSession=%p pVtgHdr=%p pszName=%s\n", pSession, pVtgHdr, pszName));
723
724 rc = supdrvTracerRegisterVtgObj(pSession->pDevExt, pVtgHdr, _1M, NULL /*pImage*/, pSession, pszName);
725
726 /*
727 * Try unregister zombies while we have a chance.
728 */
729 supdrvTracerProcessZombies(pSession->pDevExt);
730
731 return rc;
732}
733
734
735/**
736 * Deregister the VTG tracepoint providers of a driver.
737 *
738 * @param pSession The support driver session handle.
739 * @param pVtgHdr The VTG header.
740 */
741SUPR0DECL(void) SUPR0TracerDeregisterDrv(PSUPDRVSESSION pSession)
742{
743 PSUPDRVTPPROVIDER pProv, pProvNext;
744 PSUPDRVDEVEXT pDevExt;
745 AssertReturnVoid(SUP_IS_SESSION_VALID(pSession));
746 AssertReturnVoid(pSession->R0Process == NIL_RTR0PROCESS);
747 LOG_TRACER(("SUPR0TracerDeregisterDrv: pSession=%p\n", pSession));
748
749 pDevExt = pSession->pDevExt;
750
751 /*
752 * Search for providers belonging to this driver session.
753 */
754 RTSemFastMutexRequest(pDevExt->mtxTracer);
755 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
756 {
757 if (pProv->pSession == pSession)
758 {
759 RTListNodeRemove(&pProv->ListEntry);
760 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
761 }
762 }
763 RTSemFastMutexRelease(pDevExt->mtxTracer);
764
765 /*
766 * Try unregister zombies while we have a chance.
767 */
768 supdrvTracerProcessZombies(pDevExt);
769}
770
771
772/**
773 * Registers the VTG tracepoint providers of a module loaded by
774 * the support driver.
775 *
776 * This should be called from the ModuleInit code.
777 *
778 * @returns VBox status code.
779 * @param hMod The module handle.
780 * @param pVtgHdr The VTG header.
781 */
782SUPR0DECL(int) SUPR0TracerRegisterModule(void *hMod, PVTGOBJHDR pVtgHdr)
783{
784 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
785 PSUPDRVDEVEXT pDevExt;
786 uintptr_t cbVtgObj;
787 int rc;
788
789 LOG_TRACER(("SUPR0TracerRegisterModule: %p\n", pVtgHdr));
790
791 /*
792 * Validate input and context.
793 */
794 AssertPtrReturn(pImage, VERR_INVALID_HANDLE);
795 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
796
797 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
798 pDevExt = pImage->pDevExt;
799 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
800 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
801 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
802
803 /*
804 * Calculate the max VTG object size and hand it over to the common code.
805 */
806 cbVtgObj = (uintptr_t)pVtgHdr - (uintptr_t)pImage->pvImage;
807 AssertMsgReturn(cbVtgObj /*off*/ < pImage->cbImageBits,
808 ("pVtgHdr=%p offVtgObj=%p cbImageBits=%p\n", pVtgHdr, cbVtgObj, pImage->cbImageBits),
809 VERR_INVALID_PARAMETER);
810 cbVtgObj = pImage->cbImageBits - cbVtgObj;
811
812 rc = supdrvTracerRegisterVtgObj(pDevExt, pVtgHdr, cbVtgObj, pImage, NULL, pImage->szName);
813 LOG_TRACER(("SUPR0TracerRegisterModule: rc=%d\n", rc));
814
815 /*
816 * Try unregister zombies while we have a chance.
817 */
818 supdrvTracerProcessZombies(pDevExt);
819
820 return rc;
821}
822
823
824/**
825 * Registers the tracer implementation.
826 *
827 * This should be called from the ModuleInit code or from a ring-0 session.
828 *
829 * @returns VBox status code.
830 * @param hMod The module handle.
831 * @param pSession Ring-0 session handle.
832 * @param pReg Pointer to the tracer registration structure.
833 * @param ppHlp Where to return the tracer helper method table.
834 */
835SUPR0DECL(int) SUPR0TracerRegisterImpl(void *hMod, PSUPDRVSESSION pSession, PCSUPDRVTRACERREG pReg, PCSUPDRVTRACERHLP *ppHlp)
836{
837 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
838 PSUPDRVDEVEXT pDevExt;
839 PSUPDRVTPPROVIDER pProv;
840 int rc;
841
842 /*
843 * Validate input and context.
844 */
845 AssertPtrReturn(ppHlp, VERR_INVALID_POINTER);
846 *ppHlp = NULL;
847 AssertPtrReturn(pReg, VERR_INVALID_HANDLE);
848
849 if (pImage)
850 {
851 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
852 AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
853 pDevExt = pImage->pDevExt;
854 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
855 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
856 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
857 }
858 else
859 {
860 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
861 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
862 pDevExt = pSession->pDevExt;
863 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
864 }
865
866 AssertReturn(pReg->u32Magic == SUPDRVTRACERREG_MAGIC, VERR_INVALID_MAGIC);
867 AssertReturn(pReg->u32Version == SUPDRVTRACERREG_VERSION, VERR_VERSION_MISMATCH);
868 AssertReturn(pReg->uEndMagic == SUPDRVTRACERREG_MAGIC, VERR_VERSION_MISMATCH);
869 AssertPtrReturn(pReg->pfnProbeFireKernel, VERR_INVALID_POINTER);
870 AssertPtrReturn(pReg->pfnProbeFireUser, VERR_INVALID_POINTER);
871 AssertPtrReturn(pReg->pfnTracerOpen, VERR_INVALID_POINTER);
872 AssertPtrReturn(pReg->pfnTracerIoCtl, VERR_INVALID_POINTER);
873 AssertPtrReturn(pReg->pfnTracerClose, VERR_INVALID_POINTER);
874 AssertPtrReturn(pReg->pfnProviderRegister, VERR_INVALID_POINTER);
875 AssertPtrReturn(pReg->pfnProviderDeregister, VERR_INVALID_POINTER);
876 AssertPtrReturn(pReg->pfnProviderDeregisterZombie, VERR_INVALID_POINTER);
877
878 /*
879 * Do the job.
880 */
881 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
882 if (RT_SUCCESS(rc))
883 {
884 if (!pDevExt->pTracerOps)
885 {
886 LOG_TRACER(("SUPR0TracerRegisterImpl: pReg=%p\n", pReg));
887 pDevExt->pTracerOps = pReg;
888 pDevExt->pTracerSession = pSession;
889 pDevExt->pTracerImage = pImage;
890
891 g_pfnSupdrvProbeFireKernel = (PFNRT)pDevExt->pTracerOps->pfnProbeFireKernel;
892
893 *ppHlp = &pDevExt->TracerHlp;
894 rc = VINF_SUCCESS;
895
896 /*
897 * Iterate the already loaded modules and register their providers.
898 */
899 RTListForEach(&pDevExt->TracerProviderList, pProv, SUPDRVTPPROVIDER, ListEntry)
900 {
901 Assert(!pProv->fRegistered);
902 pProv->fRegistered = true;
903 int rc2 = pDevExt->pTracerOps->pfnProviderRegister(pDevExt->pTracerOps, &pProv->Core);
904 if (RT_FAILURE(rc2))
905 {
906 pProv->fRegistered = false;
907 SUPR0Printf("SUPR0TracerRegisterImpl: Failed to register provider %s::%s - rc=%d\n",
908 pProv->Core.pszModName, pProv->szName, rc2);
909 }
910 }
911 }
912 else
913 rc = VERR_SUPDRV_TRACER_ALREADY_REGISTERED;
914 RTSemFastMutexRelease(pDevExt->mtxTracer);
915 }
916
917 return rc;
918
919}
920
921
922/**
923 * Common tracer implementation deregistration code.
924 *
925 * The caller sets fTracerUnloading prior to calling this function.
926 *
927 * @param pDevExt The device extension structure.
928 */
929static void supdrvTracerCommonDeregisterImpl(PSUPDRVDEVEXT pDevExt)
930{
931 uint32_t i;
932 PSUPDRVTPPROVIDER pProv;
933 PSUPDRVTPPROVIDER pProvNext;
934
935 RTSemFastMutexRequest(pDevExt->mtxTracer);
936
937 /*
938 * Reinstall the stub probe-fire function.
939 */
940 g_pfnSupdrvProbeFireKernel = supdrvTracerProbeFireStub;
941
942 /*
943 * Disassociate the tracer implementation from all providers.
944 * We will have to wait on busy providers.
945 */
946 for (i = 0; ; i++)
947 {
948 uint32_t cZombies = 0;
949
950 /* Live providers. */
951 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
952 {
953 int rc;
954 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Attemting to unregister '%s' / %p...\n",
955 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
956
957 if (!pProv->fRegistered)
958 continue;
959 if (!pProv->fZombie)
960 {
961 rc = pDevExt->pTracerOps->pfnProviderDeregister(pDevExt->pTracerOps, &pProv->Core);
962 if (RT_FAILURE(rc))
963 pProv->fZombie = true;
964 }
965 else
966 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
967 if (RT_SUCCESS(rc))
968 pProv->fZombie = pProv->fRegistered = false;
969 else
970 {
971 cZombies++;
972 if (!(i & 0xf))
973 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on busy provider '%s' / %p (rc=%d)\n",
974 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
975 else
976 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Failed to unregister provider '%s' / %p - rc=%d\n",
977 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
978 }
979 }
980
981 /* Zombies providers. */
982 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
983 {
984 int rc;
985 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Attemting to unregister '%s' / %p (zombie)...\n",
986 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
987
988 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
989 if (RT_SUCCESS(rc))
990 {
991 RTListNodeRemove(&pProv->ListEntry);
992 supdrvTracerFreeProvider(pProv);
993 }
994 else
995 {
996 cZombies++;
997 if (!(i & 0xf))
998 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on busy provider '%s' / %p (rc=%d)\n",
999 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
1000 else
1001 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Failed to unregister provider '%s' / %p - rc=%d\n",
1002 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
1003 }
1004 }
1005
1006 /* Tracer opens. */
1007 if (pDevExt->cTracerOpens)
1008 {
1009 cZombies++;
1010 if (!(i & 0xf))
1011 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on %u opens\n", pDevExt->cTracerOpens);
1012 else
1013 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Waiting on %u opens\n", pDevExt->cTracerOpens));
1014 }
1015
1016 /* Done? */
1017 if (cZombies == 0)
1018 break;
1019
1020 /* Delay...*/
1021 RTSemFastMutexRelease(pDevExt->mtxTracer);
1022 RTThreadSleep(1000);
1023 RTSemFastMutexRequest(pDevExt->mtxTracer);
1024 }
1025
1026 /*
1027 * Deregister the tracer implementation.
1028 */
1029 pDevExt->pTracerImage = NULL;
1030 pDevExt->pTracerSession = NULL;
1031 pDevExt->pTracerOps = NULL;
1032 pDevExt->fTracerUnloading = false;
1033
1034 RTSemFastMutexRelease(pDevExt->mtxTracer);
1035}
1036
1037
1038/**
1039 * Deregister a tracer implementation.
1040 *
1041 * This should be called from the ModuleTerm code or from a ring-0 session.
1042 *
1043 * @returns VBox status code.
1044 * @param hMod The module handle.
1045 * @param pSession Ring-0 session handle.
1046 */
1047SUPR0DECL(int) SUPR0TracerDeregisterImpl(void *hMod, PSUPDRVSESSION pSession)
1048{
1049 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
1050 PSUPDRVDEVEXT pDevExt;
1051 int rc;
1052
1053 /*
1054 * Validate input and context.
1055 */
1056 if (pImage)
1057 {
1058 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
1059 AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
1060 pDevExt = pImage->pDevExt;
1061 }
1062 else
1063 {
1064 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1065 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
1066 pDevExt = pSession->pDevExt;
1067 }
1068 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
1069
1070 /*
1071 * Do the job.
1072 */
1073 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
1074 if (RT_SUCCESS(rc))
1075 {
1076 if ( pImage
1077 ? pDevExt->pTracerImage == pImage
1078 : pDevExt->pTracerSession == pSession)
1079 {
1080 LOG_TRACER(("SUPR0TracerDeregisterImpl: Unloading ...\n"));
1081 pDevExt->fTracerUnloading = true;
1082 RTSemFastMutexRelease(pDevExt->mtxTracer);
1083 supdrvTracerCommonDeregisterImpl(pDevExt);
1084 LOG_TRACER(("SUPR0TracerDeregisterImpl: ... done.\n"));
1085 }
1086 else
1087 {
1088 rc = VERR_SUPDRV_TRACER_NOT_REGISTERED;
1089 RTSemFastMutexRelease(pDevExt->mtxTracer);
1090 }
1091 }
1092
1093 return rc;
1094}
1095
1096
1097/*
1098 * The probe function is a bit more fun since we need tail jump optimizating.
1099 *
1100 * Since we cannot ship yasm sources for linux and freebsd, owing to the cursed
1101 * rebuilding of the kernel module from scratch at install time, we have to
1102 * deploy some ugly gcc inline assembly here.
1103 */
1104#if defined(__GNUC__) && (defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX))
1105__asm__("\
1106 .section .text \n\
1107 \n\
1108 .p2align 2,,3 \n\
1109 .global SUPR0TracerFireProbe \n\
1110SUPR0TracerFireProbe: \n\
1111");
1112# if defined(RT_ARCH_AMD64)
1113__asm__(" \
1114 movq g_pfnSupdrvProbeFireKernel(%rip), %rax \n\
1115 jmp *%rax \n\
1116");
1117# elif defined(RT_ARCH_X86)
1118__asm__("\
1119 movl g_pfnSupdrvProbeFireKernel, %eax \n\
1120 jmp *%eax \n\
1121");
1122# else
1123# error "Which arch is this?"
1124# endif
1125__asm__("\
1126 \n\
1127 .type supdrvTracerProbeFireStub,@function \n\
1128 .global supdrvTracerProbeFireStub \n\
1129supdrvTracerProbeFireStub: \n\
1130 ret \n\
1131 \n\
1132 .previous \n\
1133");
1134# if 0 /* Slickedit on windows highlighting fix */
1135 )
1136# endif
1137#endif
1138
1139
1140/**
1141 * Module unloading hook, called after execution in the module have ceased.
1142 *
1143 * @param pDevExt The device extension structure.
1144 * @param pImage The image being unloaded.
1145 */
1146void VBOXCALL supdrvTracerModuleUnloading(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1147{
1148 PSUPDRVTPPROVIDER pProv, pProvNext;
1149 AssertPtrReturnVoid(pImage); /* paranoia */
1150
1151 RTSemFastMutexRequest(pDevExt->mtxTracer);
1152
1153 /*
1154 * If it is the tracer image, we have to unload all the providers.
1155 */
1156 if (pDevExt->pTracerImage == pImage)
1157 {
1158 LOG_TRACER(("supdrvTracerModuleUnloading: Unloading tracer ...\n"));
1159 pDevExt->fTracerUnloading = true;
1160 RTSemFastMutexRelease(pDevExt->mtxTracer);
1161 supdrvTracerCommonDeregisterImpl(pDevExt);
1162 LOG_TRACER(("supdrvTracerModuleUnloading: ... done.\n"));
1163 }
1164 else
1165 {
1166 /*
1167 * Unregister all providers belonging to this image.
1168 */
1169 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
1170 {
1171 if (pProv->pImage == pImage)
1172 {
1173 RTListNodeRemove(&pProv->ListEntry);
1174 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
1175 }
1176 }
1177
1178 RTSemFastMutexRelease(pDevExt->mtxTracer);
1179
1180 /*
1181 * Try unregister zombies while we have a chance.
1182 */
1183 supdrvTracerProcessZombies(pDevExt);
1184 }
1185}
1186
1187
1188/**
1189 * Called when a session is being cleaned up.
1190 *
1191 * @param pDevExt The device extension structure.
1192 * @param pSession The session that is being torn down.
1193 */
1194void VBOXCALL supdrvTracerCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1195{
1196 /*
1197 * If ring-0 session, make sure it has deregistered VTG objects and the tracer.
1198 */
1199 if (pSession->R0Process == NIL_RTR0PROCESS)
1200 {
1201 SUPDRVTPPROVIDER *pProvNext;
1202 SUPDRVTPPROVIDER *pProv;
1203
1204 RTSemFastMutexRequest(pDevExt->mtxTracer);
1205 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
1206 {
1207 if (pProv->pSession == pSession)
1208 {
1209 RTListNodeRemove(&pProv->ListEntry);
1210 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
1211 }
1212 }
1213 RTSemFastMutexRelease(pDevExt->mtxTracer);
1214
1215 (void)SUPR0TracerDeregisterImpl(NULL, pSession);
1216 }
1217
1218 /*
1219 * Clean up instance data the trace may have associated with the session.
1220 */
1221 if (pSession->uTracerData)
1222 supdrvIOCtl_TracerClose(pDevExt, pSession);
1223}
1224
1225
1226/**
1227 * Open the tracer.
1228 *
1229 * @returns VBox status code
1230 * @param pDevExt The device extension structure.
1231 * @param pSession The current session.
1232 * @param uCookie The tracer cookie.
1233 * @param uArg The tracer open argument.
1234 */
1235int VBOXCALL supdrvIOCtl_TracerOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, uint32_t uCookie, uintptr_t uArg)
1236{
1237 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
1238 int rc;
1239
1240 RTSemFastMutexRequest(pDevExt->mtxTracer);
1241
1242 if (!pSession->uTracerData)
1243 {
1244 if (pDevExt->pTracerOps)
1245 {
1246 if (pDevExt->pTracerSession != pSession)
1247 {
1248 if (!pDevExt->fTracerUnloading)
1249 {
1250 if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
1251 {
1252 pDevExt->cTracerOpens++;
1253 pSession->uTracerData = ~(uintptr_t)0;
1254 pSession->hTracerCaller = hNativeSelf;
1255 RTSemFastMutexRelease(pDevExt->mtxTracer);
1256
1257 rc = pDevExt->pTracerOps->pfnTracerOpen(pDevExt->pTracerOps, pSession, uCookie, uArg, &pSession->uTracerData);
1258
1259 RTSemFastMutexRequest(pDevExt->mtxTracer);
1260 if (RT_FAILURE(rc))
1261 {
1262 pDevExt->cTracerOpens--;
1263 pSession->uTracerData = 0;
1264 }
1265 pSession->hTracerCaller = NIL_RTNATIVETHREAD;
1266 }
1267 else
1268 rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
1269 }
1270 else
1271 rc = VERR_SUPDRV_TRACER_UNLOADING;
1272 }
1273 else
1274 rc = VERR_SUPDRV_TRACER_CANNOT_OPEN_SELF;
1275 }
1276 else
1277 rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
1278 }
1279 else
1280 rc = VERR_SUPDRV_TRACER_ALREADY_OPENED;
1281
1282 RTSemFastMutexRelease(pDevExt->mtxTracer);
1283 return rc;
1284}
1285
1286
1287/**
1288 * Closes the tracer.
1289 *
1290 * @returns VBox status code.
1291 * @param pDevExt The device extension structure.
1292 * @param pSession The current session.
1293 */
1294int VBOXCALL supdrvIOCtl_TracerClose(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1295{
1296 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
1297 int rc;
1298
1299 RTSemFastMutexRequest(pDevExt->mtxTracer);
1300
1301 if (pSession->uTracerData)
1302 {
1303 Assert(pDevExt->cTracerOpens > 0);
1304
1305 if (pDevExt->pTracerOps)
1306 {
1307 if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
1308 {
1309 uintptr_t uTracerData = pSession->uTracerData;
1310 pSession->uTracerData = 0;
1311 pSession->hTracerCaller = hNativeSelf;
1312 RTSemFastMutexRelease(pDevExt->mtxTracer);
1313
1314 pDevExt->pTracerOps->pfnTracerClose(pDevExt->pTracerOps, pSession, uTracerData);
1315 rc = VINF_SUCCESS;
1316
1317 RTSemFastMutexRequest(pDevExt->mtxTracer);
1318 pSession->hTracerCaller = NIL_RTNATIVETHREAD;
1319 Assert(pDevExt->cTracerOpens > 0);
1320 pDevExt->cTracerOpens--;
1321 }
1322 else
1323 rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
1324 }
1325 else
1326 {
1327 rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
1328 pSession->uTracerData = 0;
1329 Assert(pDevExt->cTracerOpens > 0);
1330 pDevExt->cTracerOpens--;
1331 }
1332 }
1333 else
1334 rc = VERR_SUPDRV_TRACER_NOT_OPENED;
1335
1336 RTSemFastMutexRelease(pDevExt->mtxTracer);
1337 return rc;
1338}
1339
1340
1341/**
1342 * Performs a tracer I/O control request.
1343 *
1344 * @returns VBox status code.
1345 * @param pDevExt The device extension structure.
1346 * @param pSession The current session.
1347 * @param uCmd The tracer command.
1348 * @param uArg The tracer argument.
1349 * @param piRetVal Where to store the tracer specific return value.
1350 */
1351int VBOXCALL supdrvIOCtl_TracerIOCtl(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
1352{
1353 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
1354 int rc;
1355
1356 *piRetVal = 0;
1357 RTSemFastMutexRequest(pDevExt->mtxTracer);
1358
1359 if (pSession->uTracerData)
1360 {
1361 Assert(pDevExt->cTracerOpens > 0);
1362 if (pDevExt->pTracerOps)
1363 {
1364 if (!pDevExt->fTracerUnloading)
1365 {
1366 if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
1367 {
1368 uintptr_t uTracerData = pSession->uTracerData;
1369 pDevExt->cTracerOpens++;
1370 pSession->hTracerCaller = hNativeSelf;
1371 RTSemFastMutexRelease(pDevExt->mtxTracer);
1372
1373 rc = pDevExt->pTracerOps->pfnTracerIoCtl(pDevExt->pTracerOps, pSession, uTracerData, uCmd, uArg, piRetVal);
1374
1375 RTSemFastMutexRequest(pDevExt->mtxTracer);
1376 pSession->hTracerCaller = NIL_RTNATIVETHREAD;
1377 Assert(pDevExt->cTracerOpens > 0);
1378 pDevExt->cTracerOpens--;
1379 }
1380 else
1381 rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
1382 }
1383 else
1384 rc = VERR_SUPDRV_TRACER_UNLOADING;
1385 }
1386 else
1387 rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
1388 }
1389 else
1390 rc = VERR_SUPDRV_TRACER_NOT_OPENED;
1391
1392 RTSemFastMutexRelease(pDevExt->mtxTracer);
1393 return rc;
1394}
1395
1396
1397/**
1398 * Early module initialization hook.
1399 *
1400 * @returns VBox status code.
1401 * @param pDevExt The device extension structure.
1402 */
1403int VBOXCALL supdrvTracerInit(PSUPDRVDEVEXT pDevExt)
1404{
1405 /*
1406 * Initialize the tracer.
1407 */
1408 int rc = RTSemFastMutexCreate(&pDevExt->mtxTracer);
1409 if (RT_SUCCESS(rc))
1410 {
1411 pDevExt->TracerHlp.uVersion = SUPDRVTRACERHLP_VERSION;
1412 /** @todo */
1413 pDevExt->TracerHlp.uEndVersion = SUPDRVTRACERHLP_VERSION;
1414 RTListInit(&pDevExt->TracerProviderList);
1415 RTListInit(&pDevExt->TracerProviderZombieList);
1416
1417#ifdef VBOX_WITH_NATIVE_DTRACE_R0DRV
1418 pDevExt->pTracerOps = supdrvDTraceInit();
1419 if (pDevExt->pTracerOps)
1420 g_pfnSupdrvProbeFireKernel = (PFNRT)pDevExt->pTracerOps->pfnProbeFireKernel;
1421#endif
1422
1423 /*
1424 * Register the provider for this module, if compiled in.
1425 */
1426#ifdef VBOX_WITH_DTRACE_R0DRV
1427 rc = supdrvTracerRegisterVtgObj(pDevExt, &g_VTGObjHeader, _1M, NULL /*pImage*/, NULL /*pSession*/, "vboxdrv");
1428 if (RT_SUCCESS(rc))
1429 return rc;
1430 SUPR0Printf("supdrvTracerInit: supdrvTracerRegisterVtgObj failed with rc=%d\n", rc);
1431 RTSemFastMutexDestroy(pDevExt->mtxTracer);
1432#else
1433
1434 return VINF_SUCCESS;
1435#endif
1436 }
1437 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
1438 return rc;
1439}
1440
1441
1442/**
1443 * Late module termination hook.
1444 *
1445 * @returns VBox status code.
1446 * @param pDevExt The device extension structure.
1447 */
1448void VBOXCALL supdrvTracerTerm(PSUPDRVDEVEXT pDevExt)
1449{
1450 LOG_TRACER(("supdrvTracerTerm\n"));
1451
1452 supdrvTracerRemoveAllProviders(pDevExt);
1453
1454 RTSemFastMutexDestroy(pDevExt->mtxTracer);
1455 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
1456 LOG_TRACER(("supdrvTracerTerm: Done\n"));
1457}
1458
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