VirtualBox

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

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

VBoxTpG,SUPDrv,VBoxVMM: Working on static user land probes for the non-native platforms.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette