VirtualBox

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

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

SUPDrv,VMM: Tracepoints in raw-mode.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 86.9 KB
Line 
1/* $Id: SUPDrvTracer.cpp 41147 2012-05-03 20:15:27Z 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#include <iprt/param.h>
46#include <iprt/uuid.h>
47
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/** Pointer to a user tracer module registration record. */
53typedef struct SUPDRVTRACERUMOD *PSUPDRVTRACERUMOD;
54
55/**
56 * Data for a tracepoint provider.
57 */
58typedef struct SUPDRVTPPROVIDER
59{
60 /** The entry in the provider list for this image. */
61 RTLISTNODE ListEntry;
62 /** The entry in the per session provider list for this image. */
63 RTLISTNODE SessionListEntry;
64
65 /** The core structure. */
66 SUPDRVVDTPROVIDERCORE Core;
67
68 /** Pointer to the image this provider resides in. NULL if it's a
69 * driver. */
70 PSUPDRVLDRIMAGE pImage;
71 /** The session this provider is associated with if registered via
72 * SUPR0VtgRegisterDrv. NULL if pImage is set. */
73 PSUPDRVSESSION pSession;
74 /** The user tracepoint module associated with this provider. NULL if
75 * pImage is set. */
76 PSUPDRVTRACERUMOD pUmod;
77
78 /** Used to indicate that we've called pfnProviderDeregistered already and it
79 * failed because the provider was busy. Next time we must try
80 * pfnProviderDeregisterZombie.
81 *
82 * @remarks This does not necessiarly mean the provider is in the zombie
83 * list. See supdrvTracerCommonDeregisterImpl. */
84 bool fZombie;
85 /** Set if the provider has been successfully registered with the
86 * tracer. */
87 bool fRegistered;
88 /** The provider name (for logging purposes). */
89 char szName[1];
90} SUPDRVTPPROVIDER;
91/** Pointer to the data for a tracepoint provider. */
92typedef SUPDRVTPPROVIDER *PSUPDRVTPPROVIDER;
93
94
95/**
96 * User tracer module VTG data copy.
97 */
98typedef struct SUPDRVVTGCOPY
99{
100 /** Magic (SUDPRVVTGCOPY_MAGIC). */
101 uint32_t u32Magic;
102 /** Refernece counter (we expect to share a lot of these). */
103 uint32_t cRefs;
104 /** The size of the */
105 uint32_t cbStrTab;
106 /** Image type flags. */
107 uint32_t fFlags;
108 /** Hash list entry (SUPDRVDEVEXT::aTrackerUmodHash). */
109 RTLISTNODE ListEntry;
110 /** The VTG object header.
111 * The rest of the data follows immediately afterwards. First the object,
112 * then the probe locations and finally the probe location string table. All
113 * pointers are fixed up to point within this data. */
114 VTGOBJHDR Hdr;
115} SUPDRVVTGCOPY;
116/** Pointer to a VTG object copy. */
117typedef SUPDRVVTGCOPY *PSUPDRVVTGCOPY;
118/** Magic value for SUPDRVVTGCOPY. */
119#define SUDPRVVTGCOPY_MAGIC UINT32_C(0x00080386)
120
121
122/**
123 * User tracer module registration record.
124 */
125typedef struct SUPDRVTRACERUMOD
126{
127 /** Magic (SUPDRVTRACERUMOD_MAGIC). */
128 uint32_t u32Magic;
129 /** List entry. This is anchored in SUPDRVSESSION::UmodList. */
130 RTLISTNODE ListEntry;
131 /** The address of the ring-3 VTG header. */
132 RTR3PTR R3PtrVtgHdr;
133 /** Pointer to the ring-0 copy of the VTG data. */
134 PSUPDRVVTGCOPY pVtgCopy;
135 /** The memory object that locks down the user memory. */
136 RTR0MEMOBJ hMemObjLock;
137 /** The memory object that maps the locked memory into kernel space. */
138 RTR0MEMOBJ hMemObjMap;
139 /** Pointer to the probe enabled-count array within the mapping. */
140 uint32_t *pacProbeEnabled;
141 /** Pointer to the probe location array within the mapping. */
142 void *pvProbeLocs;
143 /** The address of the ring-3 probe locations. */
144 RTR3PTR R3PtrProbeLocs;
145 /** The lookup table index. */
146 uint8_t iLookupTable;
147 /** The module bit count. */
148 uint8_t cBits;
149 /** The size of a probe location record. */
150 uint8_t cbProbeLoc;
151 /** The number of probe locations. */
152 uint32_t cProbeLocs;
153 /** Ring-0 probe location info. */
154 SUPDRVPROBELOC aProbeLocs[1];
155} SUPDRVTRACERUMOD;
156/** Magic value for SUPDRVVTGCOPY. */
157#define SUPDRVTRACERUMOD_MAGIC UINT32_C(0x00080486)
158
159
160/*******************************************************************************
161* Defined Constants And Macros *
162*******************************************************************************/
163/** Simple SUPR0Printf-style logging. */
164#ifdef DEBUG_bird
165# define LOG_TRACER(a_Args) SUPR0Printf a_Args
166#else
167# define LOG_TRACER(a_Args) do { } while (0)
168#endif
169
170
171/*******************************************************************************
172* Global Variables *
173*******************************************************************************/
174/** The address of the current probe fire routine for kernel mode. */
175PFNRT g_pfnSupdrvProbeFireKernel = supdrvTracerProbeFireStub;
176
177
178/*******************************************************************************
179* Internal Functions *
180*******************************************************************************/
181static void supdrvVtgReleaseObjectCopy(PSUPDRVDEVEXT pDevExt, PSUPDRVVTGCOPY pThis);
182
183
184
185/**
186 * Validates a VTG string against length and characterset limitations.
187 *
188 * @returns VINF_SUCCESS, VERR_SUPDRV_VTG_BAD_STRING or
189 * VERR_SUPDRV_VTG_STRING_TOO_LONG.
190 * @param psz The string.
191 */
192static int supdrvVtgValidateString(const char *psz)
193{
194 size_t off = 0;
195 while (off < _4K)
196 {
197 char const ch = psz[off++];
198 if (!ch)
199 return VINF_SUCCESS;
200 if ( !RTLocCIsAlNum(ch)
201 && ch != ' '
202 && ch != '_'
203 && ch != '-'
204 && ch != '('
205 && ch != ')'
206 && ch != ','
207 && ch != '*'
208 && ch != '&'
209 )
210 {
211 /*RTAssertMsg2("off=%u '%s'\n", off, psz);*/
212 return VERR_SUPDRV_VTG_BAD_STRING;
213 }
214 }
215 return VERR_SUPDRV_VTG_STRING_TOO_LONG;
216}
217
218
219/** Used by the validation code below. */
220#define MY_CHECK_RET(a_Expr, a_rc) \
221 MY_CHECK_MSG_RET(a_Expr, ("%s: Validation failed on line " RT_XSTR(__LINE__) ": " #a_Expr "\n", __FUNCTION__), a_rc)
222
223/** Used by the validation code below. */
224#define MY_CHECK_MSG_RET(a_Expr, a_PrintfArgs, a_rc) \
225 do { if (RT_UNLIKELY(!(a_Expr))) { SUPR0Printf a_PrintfArgs; return (a_rc); } } while (0)
226
227/** Used by the validation code below. */
228#define MY_WITHIN_IMAGE(p, rc) \
229 do { \
230 if (pbImage) \
231 { \
232 if ((uintptr_t)(p) - (uintptr_t)pbImage > cbImage) \
233 { \
234 SUPR0Printf("supdrvVtgValidate: " #rc " - p=%p pbImage=%p cbImage=%#zxline=%u %s\n", \
235 p, pbImage, cbImage, #p); \
236 return (rc); \
237 } \
238 } \
239 else if (!RT_VALID_PTR(p)) \
240 return (rc); \
241 } while (0)
242
243
244/**
245 * Validates the VTG object header.
246 *
247 * @returns VBox status code.
248 * @param pVtgHdr The header.
249 * @param uVtgHdrAddr The address where the header is actually
250 * loaded.
251 * @param cbVtgObj The alleged size of the header.
252 * @param pbImage The image base, if available.
253 * @param cbImage The image size, if available.
254 * @param fUmod Whether this is a user module.
255 */
256static int supdrvVtgValidateHdr(PVTGOBJHDR pVtgHdr, RTUINTPTR uVtgHdrAddr, const uint8_t *pbImage, size_t cbImage, bool fUmod)
257{
258 struct VTGAREAS
259 {
260 uint32_t off;
261 uint32_t cb;
262 } const *paAreas;
263 unsigned cAreas;
264 unsigned i;
265 uint32_t cbVtgObj;
266 uint32_t off;
267
268#define MY_VALIDATE_SIZE(cb, cMin, cMax, cbUnit, rcBase) \
269 do { \
270 if ((cb) < (cMin) * (cbUnit)) \
271 { \
272 SUPR0Printf("supdrvVtgValidateHdr: " #rcBase "_TOO_FEW - cb=%#zx cMin=%#zx cbUnit=%#zx line=%u %s\n", \
273 (size_t)(cb), (size_t)(cMin), (size_t)cbUnit, __LINE__, #cb); \
274 return rcBase ## _TOO_FEW; \
275 } \
276 if ((cb) >= (cMax) * (cbUnit)) \
277 { \
278 SUPR0Printf("supdrvVtgValidateHdr: " #rcBase "_TOO_MUCH - cb=%#zx cMax=%#zx cbUnit=%#zx line=%u %s\n", \
279 (size_t)(cb), (size_t)(cMax), (size_t)cbUnit, __LINE__, #cb); \
280 return rcBase ## _TOO_MUCH; \
281 } \
282 if ((cb) / (cbUnit) * (cbUnit) != (cb)) \
283 { \
284 SUPR0Printf("supdrvVtgValidateHdr: " #rcBase "_NOT_MULTIPLE - cb=%#zx cbUnit=%#zx line=%u %s\n", \
285 (size_t)(cb), (size_t)cbUnit, __LINE__, #cb); \
286 return rcBase ## _NOT_MULTIPLE; \
287 } \
288 } while (0)
289
290#define MY_VALIDATE_OFF(off, cb, cMin, cMax, cbUnit, cbAlign, rcBase) \
291 do { \
292 if ( (cb) >= cbVtgObj \
293 || off > cbVtgObj - (cb) ) \
294 { \
295 SUPR0Printf("supdrvVtgValidateHdr: " #rcBase "_OFF - off=%#x cb=%#x pVtgHdr=%p cbVtgHdr=%#zx line=%u %s\n", \
296 (off), (cb), pVtgHdr, cbVtgObj, __LINE__, #off); \
297 return rcBase ## _OFF; \
298 } \
299 if (RT_ALIGN(off, cbAlign) != (off)) \
300 { \
301 SUPR0Printf("supdrvVtgValidateHdr: " #rcBase "_OFF - off=%#x align=%#zx line=%u %s\n", \
302 (off), (size_t)(cbAlign), __LINE__, #off); \
303 return rcBase ## _OFF; \
304 } \
305 MY_VALIDATE_SIZE(cb, cMin, cMax, cbUnit, rcBase); \
306 } while (0)
307
308 /*
309 * Make sure both pbImage and cbImage are NULL/0 if one if of them is.
310 */
311 if (!pbImage || !cbImage)
312 {
313 pbImage = NULL;
314 cbImage = 0;
315 cbVtgObj = pVtgHdr->cbObj;
316 }
317 else
318 {
319 MY_WITHIN_IMAGE(pVtgHdr, VERR_SUPDRV_VTG_BAD_HDR_PTR);
320 cbVtgObj = pVtgHdr->cbObj;
321 MY_WITHIN_IMAGE((uint8_t *)pVtgHdr + cbVtgObj - 1, VERR_SUPDRV_VTG_BAD_HDR_PTR);
322 }
323
324 if (cbVtgObj > _1M)
325 {
326 SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_TRACER_TOO_LARGE - cbVtgObj=%#x\n", cbVtgObj);
327 return VERR_SUPDRV_TRACER_TOO_LARGE;
328 }
329
330 /*
331 * Set the probe location array offset and size members.
332 */
333 if (!pVtgHdr->offProbeLocs)
334 {
335 uint64_t u64Tmp = pVtgHdr->uProbeLocsEnd.u64 - pVtgHdr->uProbeLocs.u64;
336 if (u64Tmp >= UINT32_MAX)
337 {
338 SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH - u64Tmp=%#llx ProbeLocs=%#llx ProbeLocsEnd=%#llx\n",
339 u64Tmp, pVtgHdr->uProbeLocs.u64, pVtgHdr->uProbeLocsEnd.u64);
340 return VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH;
341 }
342 pVtgHdr->cbProbeLocs = (uint32_t)u64Tmp;
343
344 u64Tmp = pVtgHdr->uProbeLocs.u64 - uVtgHdrAddr;
345 if ((int64_t)u64Tmp != (int32_t)u64Tmp)
346 {
347 SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_PTR - u64Tmp=%#llx uProbeLocs=%#llx uVtgHdrAddr=%RTptr\n",
348 u64Tmp, pVtgHdr->uProbeLocs.u64, uVtgHdrAddr);
349 return VERR_SUPDRV_VTG_BAD_HDR_PTR;
350 }
351 pVtgHdr->offProbeLocs = (int32_t)u64Tmp;
352 }
353
354 /*
355 * The non-area description fields.
356 */
357 if (memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)))
358 return VERR_SUPDRV_VTG_MAGIC;
359 if ( pVtgHdr->cBits != ARCH_BITS
360 && ( !fUmod
361 || ( pVtgHdr->cBits != 32
362 && pVtgHdr->cBits != 64)) )
363 return VERR_SUPDRV_VTG_BITS;
364 if ( pVtgHdr->au32Reserved1[0]
365 || pVtgHdr->au32Reserved1[1]
366 || pVtgHdr->au32Reserved1[2]
367 || pVtgHdr->au32Reserved1[3])
368 return VERR_SUPDRV_VTG_BAD_HDR_MISC;
369 if (RTUuidIsNull(&pVtgHdr->Uuid))
370 return VERR_SUPDRV_VTG_BAD_HDR_MISC;
371
372 /*
373 * Check the individual area descriptors.
374 */
375 MY_VALIDATE_OFF(pVtgHdr->offStrTab, pVtgHdr->cbStrTab, 4, _1M, sizeof(char), sizeof(uint8_t), VERR_SUPDRV_VTG_BAD_HDR);
376 MY_VALIDATE_OFF(pVtgHdr->offArgLists, pVtgHdr->cbArgLists, 1, _32K, sizeof(uint32_t), sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
377 MY_VALIDATE_OFF(pVtgHdr->offProbes, pVtgHdr->cbProbes, 1, _32K, sizeof(VTGDESCPROBE), sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
378 MY_VALIDATE_OFF(pVtgHdr->offProviders, pVtgHdr->cbProviders, 1, 16, sizeof(VTGDESCPROVIDER), sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
379 MY_VALIDATE_OFF(pVtgHdr->offProbeEnabled, pVtgHdr->cbProbeEnabled, 1, _32K, sizeof(uint32_t), sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
380 if (!fUmod)
381 {
382 MY_WITHIN_IMAGE(pVtgHdr->uProbeLocs.p, VERR_SUPDRV_VTG_BAD_HDR_PTR);
383 MY_WITHIN_IMAGE(pVtgHdr->uProbeLocsEnd.p, VERR_SUPDRV_VTG_BAD_HDR_PTR);
384 MY_VALIDATE_SIZE( pVtgHdr->cbProbeLocs, 1, _128K, sizeof(VTGPROBELOC), VERR_SUPDRV_VTG_BAD_HDR);
385 }
386 else
387 {
388 if (pVtgHdr->cBits == 32)
389 MY_VALIDATE_SIZE( pVtgHdr->cbProbeLocs, 1, _8K, sizeof(VTGPROBELOC32), VERR_SUPDRV_VTG_BAD_HDR);
390 else
391 MY_VALIDATE_SIZE( pVtgHdr->cbProbeLocs, 1, _8K, sizeof(VTGPROBELOC64), VERR_SUPDRV_VTG_BAD_HDR);
392 /* Will check later that offProbeLocs are following closely on the
393 enable count array, so no need to validate the offset here. */
394 }
395
396 /*
397 * Some additional consistency checks.
398 */
399 if ( pVtgHdr->uProbeLocsEnd.u64 - pVtgHdr->uProbeLocs.u64 != pVtgHdr->cbProbeLocs
400 || (int64_t)(pVtgHdr->uProbeLocs.u64 - uVtgHdrAddr) != pVtgHdr->offProbeLocs)
401 {
402 SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - uProbeLocs=%#llx uProbeLocsEnd=%#llx offProbeLocs=%#llx cbProbeLocs=%#x uVtgHdrAddr=%RTptr\n",
403 pVtgHdr->uProbeLocs.u64, pVtgHdr->uProbeLocsEnd.u64, pVtgHdr->offProbeLocs, pVtgHdr->cbProbeLocs, uVtgHdrAddr);
404 return VERR_SUPDRV_VTG_BAD_HDR_MISC;
405 }
406
407 if (pVtgHdr->cbProbes / sizeof(VTGDESCPROBE) != pVtgHdr->cbProbeEnabled / sizeof(uint32_t))
408 {
409 SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - cbProbeEnabled=%#zx cbProbes=%#zx\n",
410 pVtgHdr->cbProbeEnabled, pVtgHdr->cbProbes);
411 return VERR_SUPDRV_VTG_BAD_HDR_MISC;
412 }
413
414 /*
415 * Check that there are no overlapping areas. This is a little bit ugly...
416 */
417 paAreas = (struct VTGAREAS const *)&pVtgHdr->offStrTab;
418 cAreas = pVtgHdr->offProbeLocs >= 0 ? 6 : 5;
419 off = sizeof(VTGOBJHDR);
420 for (i = 0; i < cAreas; i++)
421 {
422 if (paAreas[i].off < off)
423 {
424 SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - overlapping areas %d and %d\n", i, i-1);
425 return VERR_SUPDRV_VTG_BAD_HDR_MISC;
426 }
427 off = paAreas[i].off + paAreas[i].cb;
428 }
429 if ( pVtgHdr->offProbeLocs > 0
430 && (uint32_t)-pVtgHdr->offProbeLocs < pVtgHdr->cbProbeLocs)
431 {
432 SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - probe locations overlaps the header\n");
433 return VERR_SUPDRV_VTG_BAD_HDR_MISC;
434 }
435
436 /*
437 * Check that the object size is correct.
438 */
439 if (pVtgHdr->cbObj != pVtgHdr->offProbeEnabled + pVtgHdr->cbProbeEnabled)
440 {
441 SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - bad header size %#x, expected %#x\n",
442 pVtgHdr->cbObj, pVtgHdr->offProbeEnabled + pVtgHdr->cbProbeEnabled);
443 return VERR_SUPDRV_VTG_BAD_HDR_MISC;
444 }
445
446
447 return VINF_SUCCESS;
448#undef MY_VALIDATE_OFF
449#undef MY_VALIDATE_SIZE
450}
451
452
453/**
454 * Validates the VTG data.
455 *
456 * @returns VBox status code.
457 * @param pVtgHdr The VTG object header of the data to validate.
458 * @param uVtgHdrAddr The address where the header is actually
459 * loaded.
460 * @param pbImage The image base. For validating the probe
461 * locations.
462 * @param cbImage The image size to go with @a pbImage.
463 * @param fUmod Whether this is a user module.
464 */
465static int supdrvVtgValidate(PVTGOBJHDR pVtgHdr, RTUINTPTR uVtgHdrAddr, const uint8_t *pbImage, size_t cbImage, bool fUmod)
466{
467 uintptr_t offTmp;
468 uintptr_t i;
469 uintptr_t cProviders;
470 int rc;
471
472 if (!pbImage || !cbImage)
473 {
474 pbImage = NULL;
475 cbImage = 0;
476 }
477
478#define MY_VALIDATE_STR(a_offStrTab) \
479 do { \
480 if ((a_offStrTab) >= pVtgHdr->cbStrTab) \
481 return VERR_SUPDRV_VTG_STRTAB_OFF; \
482 rc = supdrvVtgValidateString((char *)pVtgHdr + pVtgHdr->offStrTab + (a_offStrTab)); \
483 if (rc != VINF_SUCCESS) \
484 return rc; \
485 } while (0)
486#define MY_VALIDATE_ATTR(Attr) \
487 do { \
488 if ((Attr).u8Code <= (uint8_t)kVTGStability_Invalid || (Attr).u8Code >= (uint8_t)kVTGStability_End) \
489 return VERR_SUPDRV_VTG_BAD_ATTR; \
490 if ((Attr).u8Data <= (uint8_t)kVTGStability_Invalid || (Attr).u8Data >= (uint8_t)kVTGStability_End) \
491 return VERR_SUPDRV_VTG_BAD_ATTR; \
492 if ((Attr).u8DataDep <= (uint8_t)kVTGClass_Invalid || (Attr).u8DataDep >= (uint8_t)kVTGClass_End) \
493 return VERR_SUPDRV_VTG_BAD_ATTR; \
494 } while (0)
495
496 /*
497 * The header.
498 */
499 rc = supdrvVtgValidateHdr(pVtgHdr, uVtgHdrAddr, pbImage, cbImage, fUmod);
500 if (RT_FAILURE(rc))
501 return rc;
502
503 /*
504 * Validate the providers.
505 */
506 cProviders = i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
507 while (i-- > 0)
508 {
509 PCVTGDESCPROVIDER pProvider = (PCVTGDESCPROVIDER)((uintptr_t)pVtgHdr + pVtgHdr->offProviders) + i;
510
511 MY_VALIDATE_STR(pProvider->offName);
512 MY_CHECK_RET(pProvider->iFirstProbe < pVtgHdr->cbProbeEnabled / sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_PROVIDER);
513 MY_CHECK_RET((uint32_t)pProvider->iFirstProbe + pProvider->cProbes <= pVtgHdr->cbProbeEnabled / sizeof(uint32_t),
514 VERR_SUPDRV_VTG_BAD_PROVIDER);
515 MY_VALIDATE_ATTR(pProvider->AttrSelf);
516 MY_VALIDATE_ATTR(pProvider->AttrModules);
517 MY_VALIDATE_ATTR(pProvider->AttrFunctions);
518 MY_VALIDATE_ATTR(pProvider->AttrNames);
519 MY_VALIDATE_ATTR(pProvider->AttrArguments);
520 MY_CHECK_RET(pProvider->bReserved == 0, VERR_SUPDRV_VTG_BAD_PROVIDER);
521 }
522
523 /*
524 * Validate probes.
525 */
526 i = pVtgHdr->cbProbes / sizeof(VTGDESCPROBE);
527 while (i-- > 0)
528 {
529 PCVTGDESCPROBE pProbe = (PCVTGDESCPROBE)( (uintptr_t)pVtgHdr + pVtgHdr->offProbes) + i;
530 PCVTGDESCPROVIDER pProvider = (PCVTGDESCPROVIDER)((uintptr_t)pVtgHdr + pVtgHdr->offProviders) + pProbe->idxProvider;
531 PCVTGDESCARGLIST pArgList = (PCVTGDESCARGLIST)( (uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbe->offArgList );
532 unsigned iArg;
533 bool fHaveLargeArgs;
534
535
536 MY_VALIDATE_STR(pProbe->offName);
537 MY_CHECK_RET(pProbe->offArgList < pVtgHdr->cbArgLists, VERR_SUPDRV_VTG_BAD_PROBE);
538 MY_CHECK_RET((pProbe->offArgList & 3) == 0, VERR_SUPDRV_VTG_BAD_PROBE);
539 MY_CHECK_RET(pProbe->idxEnabled == i, VERR_SUPDRV_VTG_BAD_PROBE); /* The lists are parallel. */
540 MY_CHECK_RET(pProbe->idxProvider < cProviders, VERR_SUPDRV_VTG_BAD_PROBE);
541 MY_CHECK_RET(i - pProvider->iFirstProbe < pProvider->cProbes, VERR_SUPDRV_VTG_BAD_PROBE);
542 if (pProbe->offObjHdr != (intptr_t)pVtgHdr - (intptr_t)pProbe)
543 {
544 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - iProbe=%u offObjHdr=%d expected %zd\n",
545 i, pProbe->offObjHdr, (intptr_t)pVtgHdr - (intptr_t)pProbe);
546 return VERR_SUPDRV_VTG_BAD_PROBE;
547 }
548
549 /* The referenced argument list. */
550 if (pArgList->cArgs > 16)
551 {
552 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - iProbe=%u cArgs=%u\n", i, pArgList->cArgs);
553 return VERR_SUPDRV_VTG_BAD_ARGLIST;
554 }
555 if (pArgList->fHaveLargeArgs >= 2)
556 {
557 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - iProbe=%u fHaveLargeArgs=%d\n", i, pArgList->fHaveLargeArgs);
558 return VERR_SUPDRV_VTG_BAD_ARGLIST;
559 }
560 if ( pArgList->abReserved[0]
561 || pArgList->abReserved[1])
562 {
563 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - reserved MBZ iProbe=%u\n", i);
564 return VERR_SUPDRV_VTG_BAD_ARGLIST;
565 }
566 fHaveLargeArgs = false;
567 iArg = pArgList->cArgs;
568 while (iArg-- > 0)
569 {
570 uint32_t const fType = pArgList->aArgs[iArg].fType;
571 if (fType & ~VTG_TYPE_VALID_MASK)
572 {
573 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - fType=%#x iArg=%u iProbe=%u (#0)\n", fType, iArg, i);
574 return VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
575 }
576
577 switch (pArgList->aArgs[iArg].fType & VTG_TYPE_SIZE_MASK)
578 {
579 case 0:
580 if (pArgList->aArgs[iArg].fType & VTG_TYPE_FIXED_SIZED)
581 {
582 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - fType=%#x iArg=%u iProbe=%u (#1)\n", fType, iArg, i);
583 return VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
584 }
585 break;
586 case 1: case 2: case 4: case 8:
587 break;
588 default:
589 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - fType=%#x iArg=%u iProbe=%u (#2)\n", fType, iArg, i);
590 return VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
591 }
592 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
593 fHaveLargeArgs = true;
594
595 MY_VALIDATE_STR(pArgList->aArgs[iArg].offType);
596 }
597 if ((uint8_t)fHaveLargeArgs != pArgList->fHaveLargeArgs)
598 {
599 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - iProbe=%u fHaveLargeArgs=%d expected %d\n",
600 i, pArgList->fHaveLargeArgs, fHaveLargeArgs);
601 return VERR_SUPDRV_VTG_BAD_PROBE;
602 }
603 }
604
605 /*
606 * Check that pacProbeEnabled is all zeros.
607 */
608 {
609 uint32_t const *pcProbeEnabled = (uint32_t const *)((uintptr_t)pVtgHdr + pVtgHdr->offProbeEnabled);
610 i = pVtgHdr->cbProbeEnabled / sizeof(uint32_t);
611 while (i-- > 0)
612 MY_CHECK_RET(pcProbeEnabled[0] == 0, VERR_SUPDRV_VTG_BAD_PROBE_ENABLED);
613 }
614
615 /*
616 * Probe locations.
617 */
618 {
619 PCVTGPROBELOC paProbeLocs = (PCVTGPROBELOC)((intptr_t)pVtgHdr + pVtgHdr->offProbeLocs);
620 i = pVtgHdr->cbProbeLocs / sizeof(VTGPROBELOC);
621 while (i-- > 0)
622 {
623 MY_CHECK_RET(paProbeLocs[i].uLine < _1G, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
624 MY_CHECK_RET(paProbeLocs[i].fEnabled == false, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
625 MY_CHECK_RET(paProbeLocs[i].idProbe == 0, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
626 MY_WITHIN_IMAGE(paProbeLocs[i].pszFunction, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
627 offTmp = (uintptr_t)paProbeLocs[i].pProbe - (uintptr_t)pVtgHdr->offProbes - (uintptr_t)pVtgHdr;
628 MY_CHECK_RET(offTmp < pVtgHdr->cbProbes, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
629 MY_CHECK_RET(offTmp / sizeof(VTGDESCPROBE) * sizeof(VTGDESCPROBE) == offTmp, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
630 }
631 }
632
633 return VINF_SUCCESS;
634}
635
636#undef MY_VALIDATE_STR
637#undef MY_VALIDATE_ATTR
638#undef MY_WITHIN_IMAGE
639
640
641/**
642 * Gets a string from the string table.
643 *
644 * @returns Pointer to the string.
645 * @param pVtgHdr The VTG object header.
646 * @param offStrTab The string table offset.
647 */
648static const char *supdrvVtgGetString(PVTGOBJHDR pVtgHdr, uint32_t offStrTab)
649{
650 Assert(offStrTab < pVtgHdr->cbStrTab);
651 return (char *)pVtgHdr + pVtgHdr->offStrTab + offStrTab;
652}
653
654
655/**
656 * Frees the provider structure and associated resources.
657 *
658 * @param pProv The provider to free.
659 */
660static void supdrvTracerFreeProvider(PSUPDRVTPPROVIDER pProv)
661{
662 LOG_TRACER(("Freeing tracepoint provider '%s' / %p\n", pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
663 pProv->fRegistered = false;
664 pProv->fZombie = true;
665 pProv->Core.pDesc = NULL;
666 pProv->Core.pHdr = NULL;
667 pProv->Core.paProbeLocsRO = NULL;
668 pProv->Core.pvProbeLocsEn = NULL;
669 pProv->Core.pacProbeEnabled = NULL;
670 pProv->Core.paR0ProbeLocs = NULL;
671 pProv->Core.paR0Probes = NULL;
672 RT_ZERO(pProv->Core.TracerData);
673 RTMemFree(pProv);
674}
675
676
677/**
678 * Unlinks and deregisters a provider.
679 *
680 * If the provider is still busy, it will be put in the zombie list.
681 *
682 * @param pDevExt The device extension.
683 * @param pProv The provider.
684 *
685 * @remarks The caller owns mtxTracer.
686 */
687static void supdrvTracerDeregisterVtgObj(PSUPDRVDEVEXT pDevExt, PSUPDRVTPPROVIDER pProv)
688{
689 int rc;
690
691 RTListNodeRemove(&pProv->ListEntry);
692 if (pProv->pSession)
693 {
694 RTListNodeRemove(&pProv->SessionListEntry);
695 RTListInit(&pProv->SessionListEntry);
696 pProv->pSession->cTpProviders--;
697 }
698
699 if (!pProv->fRegistered || !pDevExt->pTracerOps)
700 rc = VINF_SUCCESS;
701 else
702 rc = pDevExt->pTracerOps->pfnProviderDeregister(pDevExt->pTracerOps, &pProv->Core);
703 if (RT_SUCCESS(rc))
704 {
705 supdrvTracerFreeProvider(pProv);
706 return;
707 }
708
709 pProv->fZombie = true;
710 pProv->pImage = NULL;
711 pProv->pSession = NULL;
712 pProv->pUmod = NULL;
713 pProv->Core.pDesc = NULL;
714 pProv->Core.pHdr = NULL;
715 pProv->Core.paProbeLocsRO = NULL;
716 pProv->Core.pvProbeLocsEn = NULL;
717 pProv->Core.pacProbeEnabled = NULL;
718 pProv->Core.paR0ProbeLocs = NULL;
719
720 RTListAppend(&pDevExt->TracerProviderZombieList, &pProv->ListEntry);
721 LOG_TRACER(("Invalidated provider '%s' / %p and put it on the zombie list (rc=%Rrc)\n",
722 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
723}
724
725
726/**
727 * Processes the zombie list.
728 *
729 * @param pDevExt The device extension.
730 */
731static void supdrvTracerProcessZombies(PSUPDRVDEVEXT pDevExt)
732{
733 PSUPDRVTPPROVIDER pProv, pProvNext;
734
735 RTSemFastMutexRequest(pDevExt->mtxTracer);
736 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
737 {
738 int rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
739 if (RT_SUCCESS(rc))
740 {
741 RTListNodeRemove(&pProv->ListEntry);
742 supdrvTracerFreeProvider(pProv);
743 }
744 }
745 RTSemFastMutexRelease(pDevExt->mtxTracer);
746}
747
748
749/**
750 * Unregisters all providers, including zombies, waiting for busy providers to
751 * go idle and unregister smoothly.
752 *
753 * This may block.
754 *
755 * @param pDevExt The device extension.
756 */
757static void supdrvTracerRemoveAllProviders(PSUPDRVDEVEXT pDevExt)
758{
759 uint32_t i;
760 PSUPDRVTPPROVIDER pProv;
761 PSUPDRVTPPROVIDER pProvNext;
762
763 /*
764 * Unregister all probes (there should only be one).
765 */
766 RTSemFastMutexRequest(pDevExt->mtxTracer);
767 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
768 {
769 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
770 }
771 RTSemFastMutexRelease(pDevExt->mtxTracer);
772
773 /*
774 * Try unregister zombies now, sleep on busy ones and tracer opens.
775 */
776 for (i = 0; ; i++)
777 {
778 bool fEmpty;
779
780 RTSemFastMutexRequest(pDevExt->mtxTracer);
781
782 /* Zombies */
783 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
784 {
785 int rc;
786 LOG_TRACER(("supdrvTracerRemoveAllProviders: Attemting to unregister '%s' / %p...\n",
787 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
788
789 if (pDevExt->pTracerOps)
790 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
791 else
792 rc = VINF_SUCCESS;
793 if (!rc)
794 {
795 RTListNodeRemove(&pProv->ListEntry);
796 supdrvTracerFreeProvider(pProv);
797 }
798 else if (!(i & 0xf))
799 SUPR0Printf("supdrvTracerRemoveAllProviders: Waiting on busy provider '%s' / %p (rc=%d)\n",
800 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
801 else
802 LOG_TRACER(("supdrvTracerRemoveAllProviders: Failed to unregister provider '%s' / %p - rc=%d\n",
803 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
804 }
805
806 fEmpty = RTListIsEmpty(&pDevExt->TracerProviderZombieList);
807
808 /* Tracer opens. */
809 if ( pDevExt->cTracerOpens
810 && pDevExt->pTracerOps)
811 {
812 fEmpty = false;
813 if (!(i & 0xf))
814 SUPR0Printf("supdrvTracerRemoveAllProviders: Waiting on %u opens\n", pDevExt->cTracerOpens);
815 else
816 LOG_TRACER(("supdrvTracerRemoveAllProviders: Waiting on %u opens\n", pDevExt->cTracerOpens));
817 }
818
819 RTSemFastMutexRelease(pDevExt->mtxTracer);
820
821 if (fEmpty)
822 break;
823
824 /* Delay...*/
825 RTThreadSleep(1000);
826 }
827}
828
829
830/**
831 * Registers the VTG tracepoint providers of a driver.
832 *
833 * @returns VBox status code.
834 * @param pszName The driver name.
835 * @param pVtgHdr The VTG object header.
836 * @param pImage The image if applicable.
837 * @param pSession The session if applicable.
838 * @param pUmod The associated user tracepoint module if
839 * applicable.
840 * @param pszModName The module name.
841 */
842static int supdrvTracerRegisterVtgObj(PSUPDRVDEVEXT pDevExt, PVTGOBJHDR pVtgHdr, PSUPDRVLDRIMAGE pImage,
843 PSUPDRVSESSION pSession, PSUPDRVTRACERUMOD pUmod, const char *pszModName)
844{
845 int rc;
846 uintptr_t i;
847 PSUPDRVTPPROVIDER pProv;
848 size_t cchModName;
849
850 /*
851 * Validate input.
852 */
853 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
854 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
855 AssertPtrNullReturn(pImage, VERR_INVALID_POINTER);
856 AssertPtrNullReturn(pSession, VERR_INVALID_POINTER);
857 AssertPtrReturn(pszModName, VERR_INVALID_POINTER);
858 cchModName = strlen(pszModName);
859
860 if (pImage)
861 rc = supdrvVtgValidate(pVtgHdr, (uintptr_t)pVtgHdr,
862 (const uint8_t *)pImage->pvImage, pImage->cbImageBits,
863 false /*fUmod*/);
864 else
865 rc = supdrvVtgValidate(pVtgHdr, (uintptr_t)pVtgHdr, NULL, 0, pUmod != NULL);
866 if (RT_FAILURE(rc))
867 return rc;
868
869 /*
870 * Check that there aren't any obvious duplicates.
871 * (Yes, this isn't race free, but it's good enough for now.)
872 */
873 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
874 if (RT_FAILURE(rc))
875 return rc;
876 if (pImage || !pSession || pSession->R0Process == NIL_RTPROCESS)
877 {
878 RTListForEach(&pDevExt->TracerProviderList, pProv, SUPDRVTPPROVIDER, ListEntry)
879 {
880 if (pProv->Core.pHdr == pVtgHdr)
881 {
882 rc = VERR_SUPDRV_VTG_ALREADY_REGISTERED;
883 break;
884 }
885
886 if ( pProv->pSession == pSession
887 && pProv->pImage == pImage)
888 {
889 rc = VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION;
890 break;
891 }
892 }
893 }
894 else
895 {
896 RTListForEach(&pSession->TpProviders, pProv, SUPDRVTPPROVIDER, SessionListEntry)
897 {
898 if (pProv->Core.pHdr == pVtgHdr)
899 {
900 rc = VERR_SUPDRV_VTG_ALREADY_REGISTERED;
901 break;
902 }
903 }
904 }
905 RTSemFastMutexRelease(pDevExt->mtxTracer);
906 if (RT_FAILURE(rc))
907 return rc;
908
909 /*
910 * Register the providers.
911 */
912 i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
913 while (i-- > 0)
914 {
915 PVTGDESCPROVIDER pDesc = (PVTGDESCPROVIDER)((uintptr_t)pVtgHdr + pVtgHdr->offProviders) + i;
916 const char *pszName = supdrvVtgGetString(pVtgHdr, pDesc->offName);
917 size_t const cchName = strlen(pszName) + (pUmod ? 16 : 0);
918
919 pProv = (PSUPDRVTPPROVIDER)RTMemAllocZ(RT_OFFSETOF(SUPDRVTPPROVIDER, szName[cchName + 1 + cchModName + 1]));
920 if (pProv)
921 {
922 pProv->Core.pszName = &pProv->szName[0];
923 pProv->Core.pszModName = &pProv->szName[cchName + 1];
924 pProv->Core.pDesc = pDesc;
925 pProv->Core.pHdr = pVtgHdr;
926 pProv->Core.paProbeLocsRO = (PCVTGPROBELOC )((uintptr_t)pVtgHdr + pVtgHdr->offProbeLocs);
927 if (!pUmod)
928 {
929 pProv->Core.pvProbeLocsEn = (void *)((uintptr_t)pVtgHdr + pVtgHdr->offProbeLocs);
930 pProv->Core.pacProbeEnabled = (uint32_t *)((uintptr_t)pVtgHdr + pVtgHdr->offProbeEnabled);
931 pProv->Core.paR0ProbeLocs = NULL;
932 pProv->Core.paR0Probes = NULL;
933 pProv->Core.cbProbeLocsEn = sizeof(VTGPROBELOC);
934 pProv->Core.cBits = ARCH_BITS;
935 pProv->Core.fUmod = false;
936 }
937 else
938 {
939 pProv->Core.pvProbeLocsEn = pUmod->pvProbeLocs;
940 pProv->Core.pacProbeEnabled = pUmod->pacProbeEnabled;
941 pProv->Core.paR0ProbeLocs = &pUmod->aProbeLocs[0];
942 pProv->Core.paR0Probes = (PSUPDRVPROBEINFO)&pUmod->aProbeLocs[pUmod->cProbeLocs];
943 pProv->Core.cbProbeLocsEn = pUmod->cbProbeLoc;
944 pProv->Core.cBits = pUmod->cBits;
945 pProv->Core.fUmod = true;
946 }
947 pProv->pImage = pImage;
948 pProv->pSession = pSession;
949 pProv->pUmod = pUmod;
950 pProv->fZombie = false;
951 pProv->fRegistered = true;
952
953 if (!pUmod)
954 memcpy(pProv->szName, pszName, cchName + 1);
955 else
956 RTStrPrintf(pProv->szName, cchName + 1, "%s%u", pszName, (uint32_t)pSession->Process);
957 memcpy((void *)pProv->Core.pszModName, pszModName, cchModName + 1);
958
959 /*
960 * Do the actual registration and list manipulations while holding
961 * down the lock.
962 */
963 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
964 if (RT_SUCCESS(rc))
965 {
966 if ( pDevExt->pTracerOps
967 && !pDevExt->fTracerUnloading)
968 rc = pDevExt->pTracerOps->pfnProviderRegister(pDevExt->pTracerOps, &pProv->Core);
969 else
970 {
971 pProv->fRegistered = false;
972 rc = VINF_SUCCESS;
973 }
974 if (RT_SUCCESS(rc))
975 {
976 RTListAppend(&pDevExt->TracerProviderList, &pProv->ListEntry);
977 if (pSession)
978 {
979 RTListAppend(&pSession->TpProviders, &pProv->SessionListEntry);
980 pSession->cTpProviders++;
981 }
982 else
983 RTListInit(&pProv->SessionListEntry);
984 RTSemFastMutexRelease(pDevExt->mtxTracer);
985 LOG_TRACER(("Registered tracepoint provider '%s' in '%s' -> %p\n",
986 pProv->szName, pszModName, pProv->Core.TracerData.DTrace.idProvider));
987 }
988 else
989 {
990 RTSemFastMutexRelease(pDevExt->mtxTracer);
991 LOG_TRACER(("Failed to register tracepoint provider '%s' in '%s' -> %Rrc\n",
992 pProv->szName, pszModName, rc));
993 }
994 }
995 }
996 else
997 rc = VERR_NO_MEMORY;
998
999 /*
1000 * In case of failure, we have to undo any providers we already
1001 * managed to register.
1002 */
1003 if (RT_FAILURE(rc))
1004 {
1005 PSUPDRVTPPROVIDER pProvNext;
1006
1007 if (pProv)
1008 supdrvTracerFreeProvider(pProv);
1009
1010 RTSemFastMutexRequest(pDevExt->mtxTracer);
1011 if (pImage)
1012 {
1013 RTListForEachReverseSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
1014 {
1015 if (pProv->Core.pHdr == pVtgHdr)
1016 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
1017 }
1018 }
1019 else
1020 {
1021 RTListForEachSafe(&pSession->TpProviders, pProv, pProvNext, SUPDRVTPPROVIDER, SessionListEntry)
1022 {
1023 if (pProv->Core.pHdr == pVtgHdr)
1024 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
1025 }
1026 }
1027 RTSemFastMutexRelease(pDevExt->mtxTracer);
1028 return rc;
1029 }
1030 }
1031
1032 return VINF_SUCCESS;
1033}
1034
1035
1036/**
1037 * Registers the VTG tracepoint providers of a driver.
1038 *
1039 * @returns VBox status code.
1040 * @param pSession The support driver session handle.
1041 * @param pVtgHdr The VTG header.
1042 * @param pszName The driver name.
1043 */
1044SUPR0DECL(int) SUPR0TracerRegisterDrv(PSUPDRVSESSION pSession, PVTGOBJHDR pVtgHdr, const char *pszName)
1045{
1046 int rc;
1047
1048 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1049 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
1050 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
1051 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
1052 LOG_TRACER(("SUPR0TracerRegisterDrv: pSession=%p pVtgHdr=%p pszName=%s\n", pSession, pVtgHdr, pszName));
1053
1054 rc = supdrvTracerRegisterVtgObj(pSession->pDevExt, pVtgHdr, NULL /*pImage*/, pSession, NULL /*pUmod*/, pszName);
1055
1056 /*
1057 * Try unregister zombies while we have a chance.
1058 */
1059 supdrvTracerProcessZombies(pSession->pDevExt);
1060
1061 return rc;
1062}
1063
1064
1065/**
1066 * Deregister the VTG tracepoint providers of a driver.
1067 *
1068 * @param pSession The support driver session handle.
1069 * @param pVtgHdr The VTG header.
1070 */
1071SUPR0DECL(void) SUPR0TracerDeregisterDrv(PSUPDRVSESSION pSession)
1072{
1073 PSUPDRVTPPROVIDER pProv, pProvNext;
1074 PSUPDRVDEVEXT pDevExt;
1075 AssertReturnVoid(SUP_IS_SESSION_VALID(pSession));
1076 AssertReturnVoid(pSession->R0Process == NIL_RTR0PROCESS);
1077 LOG_TRACER(("SUPR0TracerDeregisterDrv: pSession=%p\n", pSession));
1078
1079 pDevExt = pSession->pDevExt;
1080
1081 /*
1082 * Search for providers belonging to this driver session.
1083 */
1084 RTSemFastMutexRequest(pDevExt->mtxTracer);
1085 RTListForEachSafe(&pSession->TpProviders, pProv, pProvNext, SUPDRVTPPROVIDER, SessionListEntry)
1086 {
1087 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
1088 }
1089 RTSemFastMutexRelease(pDevExt->mtxTracer);
1090
1091 /*
1092 * Try unregister zombies while we have a chance.
1093 */
1094 supdrvTracerProcessZombies(pDevExt);
1095}
1096
1097
1098/**
1099 * Registers the VTG tracepoint providers of a module loaded by
1100 * the support driver.
1101 *
1102 * This should be called from the ModuleInit code.
1103 *
1104 * @returns VBox status code.
1105 * @param hMod The module handle.
1106 * @param pVtgHdr The VTG header.
1107 */
1108SUPR0DECL(int) SUPR0TracerRegisterModule(void *hMod, PVTGOBJHDR pVtgHdr)
1109{
1110 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
1111 PSUPDRVDEVEXT pDevExt;
1112 int rc;
1113
1114 LOG_TRACER(("SUPR0TracerRegisterModule: %p\n", pVtgHdr));
1115
1116 /*
1117 * Validate input and context.
1118 */
1119 AssertPtrReturn(pImage, VERR_INVALID_HANDLE);
1120 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
1121
1122 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
1123 pDevExt = pImage->pDevExt;
1124 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
1125 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
1126 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
1127 AssertReturn((uintptr_t)pVtgHdr - (uintptr_t)pImage->pvImage < pImage->cbImageBits, VERR_INVALID_PARAMETER);
1128
1129 /*
1130 * Do the job.
1131 */
1132 rc = supdrvTracerRegisterVtgObj(pDevExt, pVtgHdr, pImage, NULL /*pSession*/, NULL /*pUmod*/, pImage->szName);
1133 LOG_TRACER(("SUPR0TracerRegisterModule: rc=%d\n", rc));
1134
1135 /*
1136 * Try unregister zombies while we have a chance.
1137 */
1138 supdrvTracerProcessZombies(pDevExt);
1139
1140 return rc;
1141}
1142
1143
1144/**
1145 * Registers the tracer implementation.
1146 *
1147 * This should be called from the ModuleInit code or from a ring-0 session.
1148 *
1149 * @returns VBox status code.
1150 * @param hMod The module handle.
1151 * @param pSession Ring-0 session handle.
1152 * @param pReg Pointer to the tracer registration structure.
1153 * @param ppHlp Where to return the tracer helper method table.
1154 */
1155SUPR0DECL(int) SUPR0TracerRegisterImpl(void *hMod, PSUPDRVSESSION pSession, PCSUPDRVTRACERREG pReg, PCSUPDRVTRACERHLP *ppHlp)
1156{
1157 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
1158 PSUPDRVDEVEXT pDevExt;
1159 PSUPDRVTPPROVIDER pProv;
1160 int rc;
1161
1162 /*
1163 * Validate input and context.
1164 */
1165 AssertPtrReturn(ppHlp, VERR_INVALID_POINTER);
1166 *ppHlp = NULL;
1167 AssertPtrReturn(pReg, VERR_INVALID_HANDLE);
1168
1169 if (pImage)
1170 {
1171 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
1172 AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
1173 pDevExt = pImage->pDevExt;
1174 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
1175 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
1176 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
1177 }
1178 else
1179 {
1180 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1181 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
1182 pDevExt = pSession->pDevExt;
1183 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
1184 }
1185
1186 AssertReturn(pReg->u32Magic == SUPDRVTRACERREG_MAGIC, VERR_INVALID_MAGIC);
1187 AssertReturn(pReg->u32Version == SUPDRVTRACERREG_VERSION, VERR_VERSION_MISMATCH);
1188 AssertReturn(pReg->uEndMagic == SUPDRVTRACERREG_MAGIC, VERR_VERSION_MISMATCH);
1189 AssertPtrReturn(pReg->pfnProbeFireKernel, VERR_INVALID_POINTER);
1190 AssertPtrReturn(pReg->pfnProbeFireUser, VERR_INVALID_POINTER);
1191 AssertPtrReturn(pReg->pfnTracerOpen, VERR_INVALID_POINTER);
1192 AssertPtrReturn(pReg->pfnTracerIoCtl, VERR_INVALID_POINTER);
1193 AssertPtrReturn(pReg->pfnTracerClose, VERR_INVALID_POINTER);
1194 AssertPtrReturn(pReg->pfnProviderRegister, VERR_INVALID_POINTER);
1195 AssertPtrReturn(pReg->pfnProviderDeregister, VERR_INVALID_POINTER);
1196 AssertPtrReturn(pReg->pfnProviderDeregisterZombie, VERR_INVALID_POINTER);
1197
1198 /*
1199 * Do the job.
1200 */
1201 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
1202 if (RT_SUCCESS(rc))
1203 {
1204 if (!pDevExt->pTracerOps)
1205 {
1206 LOG_TRACER(("SUPR0TracerRegisterImpl: pReg=%p\n", pReg));
1207 pDevExt->pTracerOps = pReg;
1208 pDevExt->pTracerSession = pSession;
1209 pDevExt->pTracerImage = pImage;
1210
1211 g_pfnSupdrvProbeFireKernel = (PFNRT)pDevExt->pTracerOps->pfnProbeFireKernel;
1212
1213 *ppHlp = &pDevExt->TracerHlp;
1214 rc = VINF_SUCCESS;
1215
1216 /*
1217 * Iterate the already loaded modules and register their providers.
1218 */
1219 RTListForEach(&pDevExt->TracerProviderList, pProv, SUPDRVTPPROVIDER, ListEntry)
1220 {
1221 Assert(!pProv->fRegistered);
1222 pProv->fRegistered = true;
1223 int rc2 = pDevExt->pTracerOps->pfnProviderRegister(pDevExt->pTracerOps, &pProv->Core);
1224 if (RT_FAILURE(rc2))
1225 {
1226 pProv->fRegistered = false;
1227 SUPR0Printf("SUPR0TracerRegisterImpl: Failed to register provider %s::%s - rc=%d\n",
1228 pProv->Core.pszModName, pProv->szName, rc2);
1229 }
1230 }
1231 }
1232 else
1233 rc = VERR_SUPDRV_TRACER_ALREADY_REGISTERED;
1234 RTSemFastMutexRelease(pDevExt->mtxTracer);
1235 }
1236
1237 return rc;
1238
1239}
1240
1241
1242/**
1243 * Common tracer implementation deregistration code.
1244 *
1245 * The caller sets fTracerUnloading prior to calling this function.
1246 *
1247 * @param pDevExt The device extension structure.
1248 */
1249static void supdrvTracerCommonDeregisterImpl(PSUPDRVDEVEXT pDevExt)
1250{
1251 uint32_t i;
1252 PSUPDRVTPPROVIDER pProv;
1253 PSUPDRVTPPROVIDER pProvNext;
1254
1255 RTSemFastMutexRequest(pDevExt->mtxTracer);
1256
1257 /*
1258 * Reinstall the stub probe-fire function.
1259 */
1260 g_pfnSupdrvProbeFireKernel = supdrvTracerProbeFireStub;
1261
1262 /*
1263 * Disassociate the tracer implementation from all providers.
1264 * We will have to wait on busy providers.
1265 */
1266 for (i = 0; ; i++)
1267 {
1268 uint32_t cZombies = 0;
1269
1270 /* Live providers. */
1271 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
1272 {
1273 int rc;
1274 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Attemting to unregister '%s' / %p...\n",
1275 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
1276
1277 if (!pProv->fRegistered)
1278 continue;
1279 if (!pProv->fZombie)
1280 {
1281 rc = pDevExt->pTracerOps->pfnProviderDeregister(pDevExt->pTracerOps, &pProv->Core);
1282 if (RT_FAILURE(rc))
1283 pProv->fZombie = true;
1284 }
1285 else
1286 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
1287 if (RT_SUCCESS(rc))
1288 pProv->fZombie = pProv->fRegistered = false;
1289 else
1290 {
1291 cZombies++;
1292 if (!(i & 0xf))
1293 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on busy provider '%s' / %p (rc=%d)\n",
1294 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
1295 else
1296 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Failed to unregister provider '%s' / %p - rc=%d\n",
1297 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
1298 }
1299 }
1300
1301 /* Zombies providers. */
1302 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
1303 {
1304 int rc;
1305 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Attemting to unregister '%s' / %p (zombie)...\n",
1306 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
1307
1308 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
1309 if (RT_SUCCESS(rc))
1310 {
1311 RTListNodeRemove(&pProv->ListEntry);
1312 supdrvTracerFreeProvider(pProv);
1313 }
1314 else
1315 {
1316 cZombies++;
1317 if (!(i & 0xf))
1318 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on busy provider '%s' / %p (rc=%d)\n",
1319 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
1320 else
1321 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Failed to unregister provider '%s' / %p - rc=%d\n",
1322 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
1323 }
1324 }
1325
1326 /* Tracer opens. */
1327 if (pDevExt->cTracerOpens)
1328 {
1329 cZombies++;
1330 if (!(i & 0xf))
1331 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on %u opens\n", pDevExt->cTracerOpens);
1332 else
1333 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Waiting on %u opens\n", pDevExt->cTracerOpens));
1334 }
1335
1336 /* Tracer calls. */
1337 if (pDevExt->cTracerCallers)
1338 {
1339 cZombies++;
1340 if (!(i & 0xf))
1341 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on %u callers\n", pDevExt->cTracerCallers);
1342 else
1343 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Waiting on %u callers\n", pDevExt->cTracerCallers));
1344 }
1345
1346 /* Done? */
1347 if (cZombies == 0)
1348 break;
1349
1350 /* Delay...*/
1351 RTSemFastMutexRelease(pDevExt->mtxTracer);
1352 RTThreadSleep(1000);
1353 RTSemFastMutexRequest(pDevExt->mtxTracer);
1354 }
1355
1356 /*
1357 * Deregister the tracer implementation.
1358 */
1359 pDevExt->pTracerImage = NULL;
1360 pDevExt->pTracerSession = NULL;
1361 pDevExt->pTracerOps = NULL;
1362 pDevExt->fTracerUnloading = false;
1363
1364 RTSemFastMutexRelease(pDevExt->mtxTracer);
1365}
1366
1367
1368/**
1369 * Deregister a tracer implementation.
1370 *
1371 * This should be called from the ModuleTerm code or from a ring-0 session.
1372 *
1373 * @returns VBox status code.
1374 * @param hMod The module handle.
1375 * @param pSession Ring-0 session handle.
1376 */
1377SUPR0DECL(int) SUPR0TracerDeregisterImpl(void *hMod, PSUPDRVSESSION pSession)
1378{
1379 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
1380 PSUPDRVDEVEXT pDevExt;
1381 int rc;
1382
1383 /*
1384 * Validate input and context.
1385 */
1386 if (pImage)
1387 {
1388 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
1389 AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
1390 pDevExt = pImage->pDevExt;
1391 }
1392 else
1393 {
1394 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1395 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
1396 pDevExt = pSession->pDevExt;
1397 }
1398 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
1399
1400 /*
1401 * Do the job.
1402 */
1403 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
1404 if (RT_SUCCESS(rc))
1405 {
1406 if ( pImage
1407 ? pDevExt->pTracerImage == pImage
1408 : pDevExt->pTracerSession == pSession)
1409 {
1410 LOG_TRACER(("SUPR0TracerDeregisterImpl: Unloading ...\n"));
1411 pDevExt->fTracerUnloading = true;
1412 RTSemFastMutexRelease(pDevExt->mtxTracer);
1413 supdrvTracerCommonDeregisterImpl(pDevExt);
1414 LOG_TRACER(("SUPR0TracerDeregisterImpl: ... done.\n"));
1415 }
1416 else
1417 {
1418 rc = VERR_SUPDRV_TRACER_NOT_REGISTERED;
1419 RTSemFastMutexRelease(pDevExt->mtxTracer);
1420 }
1421 }
1422
1423 return rc;
1424}
1425
1426
1427/*
1428 * The probe function is a bit more fun since we need tail jump optimizating.
1429 *
1430 * Since we cannot ship yasm sources for linux and freebsd, owing to the cursed
1431 * rebuilding of the kernel module from scratch at install time, we have to
1432 * deploy some ugly gcc inline assembly here.
1433 */
1434#if defined(__GNUC__) && (defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX))
1435__asm__("\
1436 .section .text \n\
1437 \n\
1438 .p2align 2,,3 \n\
1439 .global SUPR0TracerFireProbe \n\
1440SUPR0TracerFireProbe: \n\
1441");
1442# if defined(RT_ARCH_AMD64)
1443__asm__(" \
1444 movq g_pfnSupdrvProbeFireKernel(%rip), %rax \n\
1445 jmp *%rax \n\
1446");
1447# elif defined(RT_ARCH_X86)
1448__asm__("\
1449 movl g_pfnSupdrvProbeFireKernel, %eax \n\
1450 jmp *%eax \n\
1451");
1452# else
1453# error "Which arch is this?"
1454# endif
1455__asm__("\
1456 \n\
1457 .type supdrvTracerProbeFireStub,@function \n\
1458 .global supdrvTracerProbeFireStub \n\
1459supdrvTracerProbeFireStub: \n\
1460 ret \n\
1461 \n\
1462 .previous \n\
1463");
1464# if 0 /* Slickedit on windows highlighting fix */
1465 )
1466# endif
1467#endif
1468
1469
1470/**
1471 * Module unloading hook, called after execution in the module have ceased.
1472 *
1473 * @param pDevExt The device extension structure.
1474 * @param pImage The image being unloaded.
1475 */
1476void VBOXCALL supdrvTracerModuleUnloading(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1477{
1478 PSUPDRVTPPROVIDER pProv, pProvNext;
1479 AssertPtrReturnVoid(pImage); /* paranoia */
1480
1481 RTSemFastMutexRequest(pDevExt->mtxTracer);
1482
1483 /*
1484 * If it is the tracer image, we have to unload all the providers.
1485 */
1486 if (pDevExt->pTracerImage == pImage)
1487 {
1488 LOG_TRACER(("supdrvTracerModuleUnloading: Unloading tracer ...\n"));
1489 pDevExt->fTracerUnloading = true;
1490 RTSemFastMutexRelease(pDevExt->mtxTracer);
1491 supdrvTracerCommonDeregisterImpl(pDevExt);
1492 LOG_TRACER(("supdrvTracerModuleUnloading: ... done.\n"));
1493 }
1494 else
1495 {
1496 /*
1497 * Unregister all providers belonging to this image.
1498 */
1499 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
1500 {
1501 if (pProv->pImage == pImage)
1502 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
1503 }
1504
1505 RTSemFastMutexRelease(pDevExt->mtxTracer);
1506
1507 /*
1508 * Try unregister zombies while we have a chance.
1509 */
1510 supdrvTracerProcessZombies(pDevExt);
1511 }
1512}
1513
1514
1515/**
1516 * Called when a session is being cleaned up.
1517 *
1518 * @param pDevExt The device extension structure.
1519 * @param pSession The session that is being torn down.
1520 */
1521void VBOXCALL supdrvTracerCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1522{
1523 /*
1524 * Deregister all providers.
1525 */
1526 SUPDRVTPPROVIDER *pProvNext;
1527 SUPDRVTPPROVIDER *pProv;
1528 RTSemFastMutexRequest(pDevExt->mtxTracer);
1529 RTListForEachSafe(&pSession->TpProviders, pProv, pProvNext, SUPDRVTPPROVIDER, SessionListEntry)
1530 {
1531 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
1532 }
1533 RTSemFastMutexRelease(pDevExt->mtxTracer);
1534
1535 /*
1536 * Clean up instance data the trace may have associated with the session.
1537 */
1538 if (pSession->uTracerData)
1539 supdrvIOCtl_TracerClose(pDevExt, pSession);
1540
1541 /*
1542 * Deregister any tracer implementation.
1543 */
1544 if (pSession->R0Process == NIL_RTR0PROCESS)
1545 (void)SUPR0TracerDeregisterImpl(NULL, pSession);
1546
1547 if (pSession->R0Process != NIL_RTR0PROCESS)
1548 {
1549 /*
1550 * Free any lingering user modules. We don't bother holding the lock
1551 * here as there shouldn't be anyone messing with the session at this
1552 * point.
1553 */
1554 PSUPDRVTRACERUMOD pUmodNext;
1555 PSUPDRVTRACERUMOD pUmod;
1556 RTListForEachSafe(&pSession->TpUmods, pUmod, pUmodNext, SUPDRVTRACERUMOD, ListEntry)
1557 {
1558 RTR0MemObjFree(pUmod->hMemObjMap, false /*fFreeMappings*/);
1559 RTR0MemObjFree(pUmod->hMemObjLock, false /*fFreeMappings*/);
1560 supdrvVtgReleaseObjectCopy(pDevExt, pUmod->pVtgCopy);
1561 RTMemFree(pUmod);
1562 }
1563 }
1564}
1565
1566
1567static void supdrvVtgReleaseObjectCopy(PSUPDRVDEVEXT pDevExt, PSUPDRVVTGCOPY pThis)
1568{
1569 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1570 if (!cRefs)
1571 {
1572 RTSemFastMutexRequest(pDevExt->mtxTracer);
1573 pThis->u32Magic = ~SUDPRVVTGCOPY_MAGIC;
1574 RTListNodeRemove(&pThis->ListEntry);
1575 RTSemFastMutexRelease(pDevExt->mtxTracer);
1576
1577 RTMemFree(pThis);
1578 }
1579}
1580
1581
1582/**
1583 * Finds a matching VTG object copy, caller owns the lock already.
1584 *
1585 * @returns Copy with reference. NULL if not found.
1586 * @param pHashList The hash list to search.
1587 * @param pHdr The VTG header (valid).
1588 * @param cbStrTab The string table size.
1589 * @param fFlags The user module flags.
1590 */
1591static PSUPDRVVTGCOPY supdrvVtgFindObjectCopyLocked(PRTLISTANCHOR pHashList, PCVTGOBJHDR pHdr, uint32_t cbStrTab, uint32_t fFlags)
1592{
1593 PSUPDRVVTGCOPY pCur;
1594
1595 fFlags &= SUP_TRACER_UMOD_FLAGS_TYPE_MASK;
1596 RTListForEach(pHashList, pCur, SUPDRVVTGCOPY, ListEntry)
1597 {
1598#define HDR_EQUALS(member) pCur->Hdr.member == pHdr->member
1599 if ( HDR_EQUALS(Uuid.au32[0])
1600 && HDR_EQUALS(Uuid.au32[1])
1601 && HDR_EQUALS(Uuid.au32[2])
1602 && HDR_EQUALS(Uuid.au32[3])
1603 && HDR_EQUALS(cbObj)
1604 && HDR_EQUALS(cBits)
1605 && pCur->cbStrTab == cbStrTab
1606 && pCur->fFlags == fFlags
1607 )
1608 {
1609 if (RT_LIKELY( HDR_EQUALS(offStrTab)
1610 && HDR_EQUALS(cbStrTab)
1611 && HDR_EQUALS(offArgLists)
1612 && HDR_EQUALS(cbArgLists)
1613 && HDR_EQUALS(offProbes)
1614 && HDR_EQUALS(cbProbes)
1615 && HDR_EQUALS(offProviders)
1616 && HDR_EQUALS(cbProviders)
1617 && HDR_EQUALS(offProbeEnabled)
1618 && HDR_EQUALS(cbProbeEnabled)
1619 && HDR_EQUALS(offProbeLocs)
1620 && HDR_EQUALS(cbProbeLocs)
1621 )
1622 )
1623 {
1624 Assert(pCur->cRefs > 0);
1625 Assert(pCur->cRefs < _1M);
1626 pCur->cRefs++;
1627 return pCur;
1628 }
1629 }
1630#undef HDR_EQUALS
1631 }
1632
1633 return NULL;
1634}
1635
1636
1637/**
1638 * Finds a matching VTG object copy.
1639 *
1640 * @returns Copy with reference. NULL if not found.
1641 * @param pDevExt The device extension.
1642 * @param pHdr The VTG header (valid).
1643 * @param cbStrTab The string table size.
1644 * @param fFlags The user module flags.
1645 */
1646static PSUPDRVVTGCOPY supdrvVtgFindObjectCopy(PSUPDRVDEVEXT pDevExt, PCVTGOBJHDR pHdr, uint32_t cbStrTab, uint32_t fFlags)
1647{
1648 PRTLISTANCHOR pHashList = &pDevExt->aTrackerUmodHash[pHdr->Uuid.au8[3] % RT_ELEMENTS(pDevExt->aTrackerUmodHash)];
1649 PSUPDRVVTGCOPY pRet;
1650
1651 int rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
1652 AssertRCReturn(rc, NULL);
1653
1654 pRet = supdrvVtgFindObjectCopyLocked(pHashList, pHdr, cbStrTab, fFlags);
1655
1656 RTSemFastMutexRelease(pDevExt->mtxTracer);
1657 return pRet;
1658}
1659
1660
1661/**
1662 * Makes a shared copy of the VTG object.
1663 *
1664 * @returns VBox status code.
1665 * @param pDevExt The device extension.
1666 * @param pVtgHdr The VTG header (valid).
1667 * @param R3PtrVtgHdr The ring-3 VTG header address.
1668 * @param uVtgHdrAddr The address of the VTG header in the context
1669 * where it is actually used.
1670 * @param R3PtrStrTab The ring-3 address of the probe location string
1671 * table. The probe location array have offsets
1672 * into this instead of funciton name pointers.
1673 * @param cbStrTab The size of the probe location string table.
1674 * @param fFlags The user module flags.
1675 * @param pUmod The structure we've allocated to track the
1676 * module. This have a valid kernel mapping of the
1677 * probe location array. Upon successful return,
1678 * the pVtgCopy member will hold the address of our
1679 * copy (with a referenced of course).
1680 */
1681static int supdrvVtgCreateObjectCopy(PSUPDRVDEVEXT pDevExt, PCVTGOBJHDR pVtgHdr, RTR3PTR R3PtrVtgHdr, RTUINTPTR uVtgHdrAddr,
1682 RTR3PTR R3PtrStrTab, uint32_t cbStrTab, uint32_t fFlags, PSUPDRVTRACERUMOD pUmod)
1683{
1684 /*
1685 * Calculate the space required, allocate and copy in the data.
1686 */
1687 int rc;
1688 size_t const cProbeLocs = pVtgHdr->cbProbeLocs / (pVtgHdr->cBits == 32 ? sizeof(VTGPROBELOC32) : sizeof(VTGPROBELOC64));
1689 size_t const cbProbeLocs = cProbeLocs * sizeof(VTGPROBELOC);
1690 size_t const offProbeLocs = RT_ALIGN(pVtgHdr->cbObj, 8);
1691 size_t const cb = offProbeLocs + cbProbeLocs + cbStrTab + 1;
1692 PSUPDRVVTGCOPY pThis = (PSUPDRVVTGCOPY)RTMemAlloc(RT_OFFSETOF(SUPDRVVTGCOPY, Hdr) + cb);
1693 if (!pThis)
1694 return VERR_NO_MEMORY;
1695
1696 pThis->u32Magic = SUDPRVVTGCOPY_MAGIC;
1697 pThis->cRefs = 1;
1698 pThis->cbStrTab = cbStrTab;
1699 pThis->fFlags = fFlags & SUP_TRACER_UMOD_FLAGS_TYPE_MASK;
1700 RTListInit(&pThis->ListEntry);
1701
1702 rc = RTR0MemUserCopyFrom(&pThis->Hdr, R3PtrVtgHdr, pVtgHdr->cbObj);
1703 if (RT_SUCCESS(rc))
1704 {
1705 char *pchStrTab = (char *)&pThis->Hdr + offProbeLocs + cbProbeLocs;
1706 rc = RTR0MemUserCopyFrom(pchStrTab, R3PtrStrTab, cbStrTab);
1707 if (RT_SUCCESS(rc))
1708 {
1709 PVTGPROBELOC paDst = (PVTGPROBELOC)((char *)&pThis->Hdr + offProbeLocs);
1710 uint32_t i;
1711
1712 /*
1713 * Some paranoia: Overwrite the header with the copy we've already
1714 * validated and zero terminate the string table.
1715 */
1716 pThis->Hdr = *pVtgHdr;
1717 pchStrTab[cbStrTab] = '\0';
1718
1719 /*
1720 * Set the probe location array related header members since we're
1721 * making our own copy in a different location.
1722 */
1723 pThis->Hdr.uProbeLocs.u64 = (uintptr_t)paDst;
1724 pThis->Hdr.uProbeLocsEnd.u64 = (uintptr_t)paDst + cbProbeLocs;
1725 pThis->Hdr.offProbeLocs = offProbeLocs;
1726 pThis->Hdr.cbProbeLocs = cbProbeLocs;
1727 pThis->Hdr.cBits = ARCH_BITS;
1728
1729 /*
1730 * Copy, convert and fix up the the probe location table.
1731 */
1732 if (pVtgHdr->cBits == 32)
1733 {
1734 uintptr_t const offDelta = (uintptr_t)&pThis->Hdr - uVtgHdrAddr;
1735 PCVTGPROBELOC32 paSrc = (PCVTGPROBELOC32)pUmod->pvProbeLocs;
1736
1737 for (i = 0; i < cProbeLocs; i++)
1738 {
1739 paDst[i].uLine = paSrc[i].uLine;
1740 paDst[i].fEnabled = paSrc[i].fEnabled;
1741 paDst[i].idProbe = paSrc[i].idProbe;
1742 if (paSrc[i].pszFunction > cbStrTab)
1743 {
1744 rc = VERR_SUPDRV_TRACER_UMOD_STRTAB_OFF_BAD;
1745 break;
1746 }
1747 paDst[i].pszFunction = pchStrTab + paSrc[i].pszFunction;
1748 paDst[i].pProbe = (PVTGDESCPROBE)(uintptr_t)(paSrc[i].pProbe + offDelta);
1749 }
1750 }
1751 else
1752 {
1753 uint64_t const offDelta = (uintptr_t)&pThis->Hdr - uVtgHdrAddr;
1754 PCVTGPROBELOC64 paSrc = (PCVTGPROBELOC64)pUmod->pvProbeLocs;
1755
1756 for (i = 0; i < cProbeLocs; i++)
1757 {
1758 paDst[i].uLine = paSrc[i].uLine;
1759 paDst[i].fEnabled = paSrc[i].fEnabled;
1760 paDst[i].idProbe = paSrc[i].idProbe;
1761 if (paSrc[i].pszFunction > cbStrTab)
1762 {
1763 rc = VERR_SUPDRV_TRACER_UMOD_STRTAB_OFF_BAD;
1764 break;
1765 }
1766 paDst[i].pszFunction = pchStrTab + (uintptr_t)paSrc[i].pszFunction;
1767 paDst[i].pProbe = (PVTGDESCPROBE)(uintptr_t)(paSrc[i].pProbe + offDelta);
1768 }
1769 }
1770
1771 /*
1772 * Validate it
1773 *
1774 * Note! fUmod is false as this is a kernel copy with all native
1775 * structures.
1776 */
1777 if (RT_SUCCESS(rc))
1778 rc = supdrvVtgValidate(&pThis->Hdr, (uintptr_t)&pThis->Hdr, (uint8_t *)&pThis->Hdr, cb, false /*fUmod*/);
1779 if (RT_SUCCESS(rc))
1780 {
1781 /*
1782 * Add it to the hash list, making sure nobody raced us.
1783 */
1784 PRTLISTANCHOR pHashList = &pDevExt->aTrackerUmodHash[ pVtgHdr->Uuid.au8[3]
1785 % RT_ELEMENTS(pDevExt->aTrackerUmodHash)];
1786
1787 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
1788 if (RT_SUCCESS(rc))
1789 {
1790 pUmod->pVtgCopy = supdrvVtgFindObjectCopyLocked(pHashList, pVtgHdr, cbStrTab, fFlags);
1791 if (!pUmod->pVtgCopy)
1792 {
1793 pUmod->pVtgCopy = pThis;
1794 RTListAppend(pHashList, &pThis->ListEntry);
1795 RTSemFastMutexRelease(pDevExt->mtxTracer);
1796 return rc;
1797 }
1798
1799 /*
1800 * Someone raced us, free our copy and return the existing
1801 * one instead.
1802 */
1803 RTSemFastMutexRelease(pDevExt->mtxTracer);
1804 }
1805 }
1806 }
1807 }
1808 RTMemFree(pThis);
1809 return rc;
1810}
1811
1812
1813/**
1814 * Undoes what supdrvTracerUmodSetProbeIds did.
1815 *
1816 * @param pDevExt The device extension.
1817 * @param pSession The current session.
1818 * @param pUmod The user tracepoint module.
1819 */
1820static void supdrvTracerUmodClearProbeIds(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVTRACERUMOD pUmod)
1821{
1822 uint32_t i;
1823
1824 AssertReturnVoid(pUmod->iLookupTable < RT_ELEMENTS(pSession->apTpLookupTable));
1825 AssertReturnVoid(pSession->apTpLookupTable[pUmod->iLookupTable] == pUmod);
1826
1827 /*
1828 * Clear the probe IDs and disable the probes.
1829 */
1830 i = pUmod->cProbeLocs;
1831 if (pUmod->cBits == 32)
1832 {
1833 PVTGPROBELOC32 paProbeLocs = (PVTGPROBELOC32)pUmod->pvProbeLocs;
1834 while (i-- > 0)
1835 paProbeLocs[i].idProbe = 0;
1836 }
1837 else
1838 {
1839 PVTGPROBELOC64 paProbeLocs = (PVTGPROBELOC64)pUmod->pvProbeLocs;
1840 while (i-- > 0)
1841 paProbeLocs[i].idProbe = 0;
1842 }
1843
1844 /*
1845 * Free the lookup table entry. We'll have to wait for the table to go
1846 * idle to make sure there are no current users of pUmod.
1847 */
1848 RTSemFastMutexRequest(pDevExt->mtxTracer);
1849 if (pSession->apTpLookupTable[pUmod->iLookupTable] == pUmod)
1850 {
1851 if (pSession->cTpProbesFiring > 0)
1852 {
1853 i = 0;
1854 while (pSession->cTpProbesFiring > 0)
1855 {
1856 RTSemFastMutexRelease(pDevExt->mtxTracer);
1857 i++;
1858 if (!(i & 0xff))
1859 SUPR0Printf("supdrvTracerUmodClearProbeIds: waiting for lookup table to go idle (i=%u)\n", i);
1860 RTThreadSleep(10);
1861 RTSemFastMutexRequest(pDevExt->mtxTracer);
1862 }
1863 }
1864 ASMAtomicWriteNullPtr(&pSession->apTpLookupTable[pUmod->iLookupTable]);
1865 }
1866 RTSemFastMutexRelease(pDevExt->mtxTracer);
1867}
1868
1869
1870/**
1871 * Allocates a lookup table entry for the Umod and sets the
1872 * VTGPROBELOC::idProbe fields in user mode.
1873 *
1874 * @returns VINF_SUCCESS or VERR_SUPDRV_TRACER_TOO_MANY_PROVIDERS.
1875 * @param pDevExt The device extension.
1876 * @param pSession The current session.
1877 * @param pUmod The user tracepoint module.
1878 */
1879static int supdrvTracerUmodSetProbeIds(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVTRACERUMOD pUmod)
1880{
1881 uint32_t iBase;
1882 uint32_t i;
1883
1884 /*
1885 * Allocate a lookup table entry.
1886 */
1887 RTSemFastMutexRequest(pDevExt->mtxTracer);
1888 for (i = 0; i < RT_ELEMENTS(pSession->apTpLookupTable); i++)
1889 {
1890 if (!pSession->apTpLookupTable[i])
1891 {
1892 pSession->apTpLookupTable[i] = pUmod;
1893 pUmod->iLookupTable = i;
1894 break;
1895 }
1896 }
1897 RTSemFastMutexRelease(pDevExt->mtxTracer);
1898 if (i >= RT_ELEMENTS(pSession->apTpLookupTable))
1899 return VERR_SUPDRV_TRACER_TOO_MANY_PROVIDERS;
1900
1901 /*
1902 * Set probe IDs of the usermode probe location to indicate our lookup
1903 * table entry as well as the probe location array entry.
1904 */
1905 iBase = (uint32_t)pUmod->iLookupTable << 24;
1906 i = pUmod->cProbeLocs;
1907 if (pUmod->cBits == 32)
1908 {
1909 PVTGPROBELOC32 paProbeLocs = (PVTGPROBELOC32)pUmod->pvProbeLocs;
1910 while (i-- > 0)
1911 paProbeLocs[i].idProbe = iBase | i;
1912 }
1913 else
1914 {
1915 PVTGPROBELOC64 paProbeLocs = (PVTGPROBELOC64)pUmod->pvProbeLocs;
1916 while (i-- > 0)
1917 paProbeLocs[i].idProbe = iBase | i;
1918 }
1919
1920 return VINF_SUCCESS;
1921}
1922
1923
1924int VBOXCALL supdrvIOCtl_TracerUmodRegister(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession,
1925 RTR3PTR R3PtrVtgHdr, RTUINTPTR uVtgHdrAddr,
1926 RTR3PTR R3PtrStrTab, uint32_t cbStrTab,
1927 const char *pszModName, uint32_t fFlags)
1928{
1929 VTGOBJHDR Hdr;
1930 PSUPDRVTRACERUMOD pUmod;
1931 RTR3PTR R3PtrLock;
1932 size_t cbLock;
1933 uint32_t cProbeLocs;
1934 int rc;
1935
1936 /*
1937 * Validate input.
1938 */
1939 if (pSession->R0Process == NIL_RTR0PROCESS)
1940 return VERR_INVALID_CONTEXT;
1941 if ( fFlags != SUP_TRACER_UMOD_FLAGS_EXE
1942 && fFlags != SUP_TRACER_UMOD_FLAGS_SHARED)
1943 return VERR_INVALID_PARAMETER;
1944
1945 if (pSession->cTpProviders >= RT_ELEMENTS(pSession->apTpLookupTable))
1946 return VERR_SUPDRV_TRACER_TOO_MANY_PROVIDERS;
1947
1948 if ( cbStrTab < 2
1949 || cbStrTab > _1M)
1950 return VERR_SUPDRV_TRACER_UMOD_STRTAB_TOO_BIG;
1951
1952 /*
1953 * Read the VTG header into a temporary buffer and perform some simple
1954 * validations to make sure we aren't wasting our time here.
1955 */
1956 rc = RTR0MemUserCopyFrom(&Hdr, R3PtrVtgHdr, sizeof(Hdr));
1957 if (RT_FAILURE(rc))
1958 return rc;
1959 rc = supdrvVtgValidateHdr(&Hdr, uVtgHdrAddr, NULL, 0, true /*fUmod*/);
1960 if (RT_FAILURE(rc))
1961 return rc;
1962 if (Hdr.cbProviders / sizeof(VTGDESCPROVIDER) > 2)
1963 return VERR_SUPDRV_TRACER_TOO_MANY_PROVIDERS;
1964
1965 /*
1966 * Check how much needs to be locked down and how many probe locations
1967 * there are.
1968 */
1969 if ( Hdr.offProbeLocs <= 0
1970 || Hdr.offProbeEnabled > (uint32_t)Hdr.offProbeLocs
1971 || (uint32_t)Hdr.offProbeLocs - Hdr.offProbeEnabled - Hdr.cbProbeEnabled > 128)
1972 return VERR_SUPDRV_TRACER_UMOD_NOT_ADJACENT;
1973 R3PtrLock = R3PtrVtgHdr + Hdr.offProbeEnabled;
1974 cbLock = Hdr.offProbeLocs + Hdr.cbProbeLocs - Hdr.offProbeEnabled + (R3PtrLock & PAGE_OFFSET_MASK);
1975 R3PtrLock &= ~(RTR3PTR)PAGE_OFFSET_MASK;
1976 if (cbLock > _64K)
1977 return VERR_SUPDRV_TRACER_UMOD_TOO_MANY_PROBES;
1978
1979 cProbeLocs = Hdr.cbProbeLocs / (Hdr.cBits == 32 ? sizeof(VTGPROBELOC32) : sizeof(VTGPROBELOC64));
1980
1981 /*
1982 * Allocate the tracker data we keep in the session.
1983 */
1984 pUmod = (PSUPDRVTRACERUMOD)RTMemAllocZ( RT_OFFSETOF(SUPDRVTRACERUMOD, aProbeLocs[cProbeLocs])
1985 + (Hdr.cbProbeEnabled / sizeof(uint32_t) * sizeof(SUPDRVPROBEINFO)) );
1986 if (!pUmod)
1987 return VERR_NO_MEMORY;
1988 pUmod->u32Magic = SUPDRVTRACERUMOD_MAGIC;
1989 RTListInit(&pUmod->ListEntry);
1990 pUmod->R3PtrVtgHdr = R3PtrVtgHdr;
1991 pUmod->pVtgCopy = NULL;
1992 pUmod->hMemObjLock = NIL_RTR0MEMOBJ;
1993 pUmod->hMemObjMap = NIL_RTR0MEMOBJ;
1994 pUmod->R3PtrProbeLocs = (RTR3INTPTR)R3PtrVtgHdr + Hdr.offProbeLocs;
1995 pUmod->iLookupTable = UINT8_MAX;
1996 pUmod->cBits = Hdr.cBits;
1997 pUmod->cbProbeLoc = Hdr.cBits == 32 ? sizeof(VTGPROBELOC32) : sizeof(VTGPROBELOC64);
1998 pUmod->cProbeLocs = cProbeLocs;
1999
2000 /*
2001 * Lock down and map the user-mode structures.
2002 */
2003 rc = RTR0MemObjLockUser(&pUmod->hMemObjLock, R3PtrLock, cbLock, RTMEM_PROT_READ | RTMEM_PROT_WRITE, NIL_RTR0PROCESS);
2004 if (RT_SUCCESS(rc))
2005 {
2006 rc = RTR0MemObjMapKernel(&pUmod->hMemObjMap, pUmod->hMemObjLock, (void *)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
2007 if (RT_SUCCESS(rc))
2008 {
2009 pUmod->pacProbeEnabled = (uint32_t *)( (uintptr_t)RTR0MemObjAddress(pUmod->hMemObjMap)
2010 + ((uintptr_t)(R3PtrVtgHdr + Hdr.offProbeEnabled) & PAGE_OFFSET_MASK));
2011 pUmod->pvProbeLocs = (uint8_t *)pUmod->pacProbeEnabled + Hdr.offProbeLocs - Hdr.offProbeEnabled;
2012
2013 /*
2014 * Does some other process use the same module already? If so,
2015 * share the VTG data with it. Otherwise, make a ring-0 copy it.
2016 */
2017 pUmod->pVtgCopy = supdrvVtgFindObjectCopy(pDevExt, &Hdr, cbStrTab, fFlags);
2018 if (!pUmod->pVtgCopy)
2019 rc = supdrvVtgCreateObjectCopy(pDevExt, &Hdr, R3PtrVtgHdr, uVtgHdrAddr, R3PtrStrTab, cbStrTab, fFlags, pUmod);
2020 if (RT_SUCCESS(rc))
2021 {
2022 AssertPtr(pUmod->pVtgCopy);
2023
2024 /*
2025 * Grabe a place in apTpLookupTable and set the probe IDs
2026 * accordingly.
2027 */
2028 rc = supdrvTracerUmodSetProbeIds(pDevExt, pSession, pUmod);
2029 if (RT_SUCCESS(rc))
2030 {
2031 /*
2032 * Register the providers.
2033 */
2034 rc = supdrvTracerRegisterVtgObj(pDevExt, &pUmod->pVtgCopy->Hdr,
2035 NULL /*pImage*/, pSession, pUmod, pszModName);
2036 if (RT_SUCCESS(rc))
2037 {
2038 RTSemFastMutexRequest(pDevExt->mtxTracer);
2039 RTListAppend(&pSession->TpUmods, &pUmod->ListEntry);
2040 RTSemFastMutexRelease(pDevExt->mtxTracer);
2041
2042 return VINF_SUCCESS;
2043 }
2044
2045 /* bail out. */
2046 supdrvTracerUmodClearProbeIds(pDevExt, pSession, pUmod);
2047 }
2048 supdrvVtgReleaseObjectCopy(pDevExt, pUmod->pVtgCopy);
2049 }
2050 RTR0MemObjFree(pUmod->hMemObjMap, false /*fFreeMappings*/);
2051 }
2052 RTR0MemObjFree(pUmod->hMemObjLock, false /*fFreeMappings*/);
2053 }
2054 pUmod->u32Magic = ~SUPDRVTRACERUMOD_MAGIC;
2055 RTMemFree(pUmod);
2056 return rc;
2057}
2058
2059
2060int VBOXCALL supdrvIOCtl_TracerUmodDeregister(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, RTR3PTR R3PtrVtgHdr)
2061{
2062 PSUPDRVTRACERUMOD pUmod = NULL;
2063 uint32_t i;
2064 int rc;
2065
2066 /*
2067 * Validate the request.
2068 */
2069 RTSemFastMutexRequest(pDevExt->mtxTracer);
2070 for (i = 0; i < RT_ELEMENTS(pSession->apTpLookupTable); i++)
2071 {
2072 pUmod = pSession->apTpLookupTable[i];
2073 if ( pUmod
2074 && pUmod->u32Magic == SUPDRVTRACERUMOD_MAGIC
2075 && pUmod->R3PtrVtgHdr == R3PtrVtgHdr)
2076 break;
2077 }
2078 RTSemFastMutexRelease(pDevExt->mtxTracer);
2079 if (pUmod)
2080 {
2081 SUPDRVTPPROVIDER *pProvNext;
2082 SUPDRVTPPROVIDER *pProv;
2083
2084 /*
2085 * Remove ourselves from the lookup table and clean up the ring-3 bits
2086 * we've dirtied. We do this first to make sure no probes are firing
2087 * when we're destroying the providers in the next step.
2088 */
2089 supdrvTracerUmodClearProbeIds(pDevExt, pSession, pUmod);
2090
2091 /*
2092 * Deregister providers related to the VTG object.
2093 */
2094 RTSemFastMutexRequest(pDevExt->mtxTracer);
2095 RTListForEachSafe(&pSession->TpProviders, pProv, pProvNext, SUPDRVTPPROVIDER, SessionListEntry)
2096 {
2097 if (pProv->pUmod == pUmod)
2098 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
2099 }
2100 RTSemFastMutexRelease(pDevExt->mtxTracer);
2101
2102 /*
2103 * Destroy the Umod object.
2104 */
2105 pUmod->u32Magic = ~SUPDRVTRACERUMOD_MAGIC;
2106 supdrvVtgReleaseObjectCopy(pDevExt, pUmod->pVtgCopy);
2107 RTR0MemObjFree(pUmod->hMemObjMap, false /*fFreeMappings*/);
2108 RTR0MemObjFree(pUmod->hMemObjLock, false /*fFreeMappings*/);
2109 RTMemFree(pUmod);
2110 }
2111 else
2112 rc = VERR_NOT_FOUND;
2113 return rc;
2114}
2115
2116
2117/**
2118 * Implementation of supdrvIOCtl_TracerUmodProbeFire and
2119 * SUPR0TracerUmodProbeFire.
2120 *
2121 * @param pDevExt The device extension.
2122 * @param pSession The calling session.
2123 * @param pCtx The context record.
2124 */
2125static void supdrvTracerUmodProbeFire(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVTRACERUSRCTX pCtx)
2126{
2127 /*
2128 * We cannot trust user mode to hand us the right bits nor not calling us
2129 * when disabled. So, we have to check for our selves.
2130 */
2131 PSUPDRVTRACERUMOD pUmod;
2132 uint32_t const iLookupTable = pCtx->idProbe >> 24;
2133 uint32_t const iProbeLoc = pCtx->idProbe & UINT32_C(0x00ffffff);
2134
2135 if (RT_UNLIKELY( !pDevExt->pTracerOps
2136 || pDevExt->fTracerUnloading))
2137 return;
2138 if (RT_UNLIKELY(iLookupTable >= RT_ELEMENTS(pSession->apTpLookupTable)))
2139 return;
2140 if (RT_UNLIKELY( pCtx->cBits != 32
2141 && pCtx->cBits != 64))
2142 return;
2143
2144 ASMAtomicIncU32(&pSession->cTpProviders);
2145
2146 pUmod = pSession->apTpLookupTable[iLookupTable];
2147 if (RT_LIKELY(pUmod))
2148 {
2149 if (RT_LIKELY( pUmod->u32Magic == SUPDRVTRACERUMOD_MAGIC
2150 && iProbeLoc < pUmod->cProbeLocs
2151 && pCtx->cBits == pUmod->cBits))
2152 {
2153 RTR3PTR R3PtrProbeLoc = pUmod->R3PtrProbeLocs + iProbeLoc * pUmod->cbProbeLoc;
2154 if (RT_LIKELY( (pCtx->cBits == 32 ? (RTR3PTR)pCtx->u.X86.uVtgProbeLoc : pCtx->u.Amd64.uVtgProbeLoc)
2155 == R3PtrProbeLoc))
2156 {
2157 if (RT_LIKELY(pUmod->aProbeLocs[iProbeLoc].fEnabled))
2158 {
2159 PSUPDRVVTGCOPY pVtgCopy;
2160 ASMAtomicIncU32(&pDevExt->cTracerCallers);
2161 pVtgCopy = pUmod->pVtgCopy;
2162 if (RT_LIKELY( pDevExt->pTracerOps
2163 && !pDevExt->fTracerUnloading
2164 && pVtgCopy))
2165 {
2166 PCVTGPROBELOC pProbeLocRO;
2167 pProbeLocRO = (PCVTGPROBELOC)((uintptr_t)&pVtgCopy->Hdr + pVtgCopy->Hdr.offProbeLocs) + iProbeLoc;
2168
2169 pCtx->idProbe = pUmod->aProbeLocs[iProbeLoc].idProbe;
2170 pDevExt->pTracerOps->pfnProbeFireUser(pDevExt->pTracerOps, pSession, pCtx, &pVtgCopy->Hdr, pProbeLocRO);
2171 }
2172 ASMAtomicDecU32(&pDevExt->cTracerCallers);
2173 }
2174 }
2175 }
2176 }
2177
2178 ASMAtomicDecU32(&pSession->cTpProviders);
2179}
2180
2181
2182SUPR0DECL(void) SUPR0TracerUmodProbeFire(PSUPDRVSESSION pSession, PSUPDRVTRACERUSRCTX pCtx)
2183{
2184 AssertReturnVoid(SUP_IS_SESSION_VALID(pSession));
2185 AssertPtrReturnVoid(pCtx);
2186
2187 supdrvTracerUmodProbeFire(pSession->pDevExt, pSession, pCtx);
2188}
2189
2190
2191void VBOXCALL supdrvIOCtl_TracerUmodProbeFire(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVTRACERUSRCTX pCtx)
2192{
2193 supdrvTracerUmodProbeFire(pDevExt, pSession, pCtx);
2194}
2195
2196
2197/**
2198 * Open the tracer.
2199 *
2200 * @returns VBox status code
2201 * @param pDevExt The device extension structure.
2202 * @param pSession The current session.
2203 * @param uCookie The tracer cookie.
2204 * @param uArg The tracer open argument.
2205 */
2206int VBOXCALL supdrvIOCtl_TracerOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, uint32_t uCookie, uintptr_t uArg)
2207{
2208 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
2209 int rc;
2210
2211 RTSemFastMutexRequest(pDevExt->mtxTracer);
2212
2213 if (!pSession->uTracerData)
2214 {
2215 if (pDevExt->pTracerOps)
2216 {
2217 if (pDevExt->pTracerSession != pSession)
2218 {
2219 if (!pDevExt->fTracerUnloading)
2220 {
2221 if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
2222 {
2223 pDevExt->cTracerOpens++;
2224 pSession->uTracerData = ~(uintptr_t)0;
2225 pSession->hTracerCaller = hNativeSelf;
2226 RTSemFastMutexRelease(pDevExt->mtxTracer);
2227
2228 rc = pDevExt->pTracerOps->pfnTracerOpen(pDevExt->pTracerOps, pSession, uCookie, uArg, &pSession->uTracerData);
2229
2230 RTSemFastMutexRequest(pDevExt->mtxTracer);
2231 if (RT_FAILURE(rc))
2232 {
2233 pDevExt->cTracerOpens--;
2234 pSession->uTracerData = 0;
2235 }
2236 pSession->hTracerCaller = NIL_RTNATIVETHREAD;
2237 }
2238 else
2239 rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
2240 }
2241 else
2242 rc = VERR_SUPDRV_TRACER_UNLOADING;
2243 }
2244 else
2245 rc = VERR_SUPDRV_TRACER_CANNOT_OPEN_SELF;
2246 }
2247 else
2248 rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
2249 }
2250 else
2251 rc = VERR_SUPDRV_TRACER_ALREADY_OPENED;
2252
2253 RTSemFastMutexRelease(pDevExt->mtxTracer);
2254 return rc;
2255}
2256
2257
2258/**
2259 * Closes the tracer.
2260 *
2261 * @returns VBox status code.
2262 * @param pDevExt The device extension structure.
2263 * @param pSession The current session.
2264 */
2265int VBOXCALL supdrvIOCtl_TracerClose(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
2266{
2267 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
2268 int rc;
2269
2270 RTSemFastMutexRequest(pDevExt->mtxTracer);
2271
2272 if (pSession->uTracerData)
2273 {
2274 Assert(pDevExt->cTracerOpens > 0);
2275
2276 if (pDevExt->pTracerOps)
2277 {
2278 if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
2279 {
2280 uintptr_t uTracerData = pSession->uTracerData;
2281 pSession->uTracerData = 0;
2282 pSession->hTracerCaller = hNativeSelf;
2283 RTSemFastMutexRelease(pDevExt->mtxTracer);
2284
2285 pDevExt->pTracerOps->pfnTracerClose(pDevExt->pTracerOps, pSession, uTracerData);
2286 rc = VINF_SUCCESS;
2287
2288 RTSemFastMutexRequest(pDevExt->mtxTracer);
2289 pSession->hTracerCaller = NIL_RTNATIVETHREAD;
2290 Assert(pDevExt->cTracerOpens > 0);
2291 pDevExt->cTracerOpens--;
2292 }
2293 else
2294 rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
2295 }
2296 else
2297 {
2298 rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
2299 pSession->uTracerData = 0;
2300 Assert(pDevExt->cTracerOpens > 0);
2301 pDevExt->cTracerOpens--;
2302 }
2303 }
2304 else
2305 rc = VERR_SUPDRV_TRACER_NOT_OPENED;
2306
2307 RTSemFastMutexRelease(pDevExt->mtxTracer);
2308 return rc;
2309}
2310
2311
2312/**
2313 * Performs a tracer I/O control request.
2314 *
2315 * @returns VBox status code.
2316 * @param pDevExt The device extension structure.
2317 * @param pSession The current session.
2318 * @param uCmd The tracer command.
2319 * @param uArg The tracer argument.
2320 * @param piRetVal Where to store the tracer specific return value.
2321 */
2322int VBOXCALL supdrvIOCtl_TracerIOCtl(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
2323{
2324 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
2325 int rc;
2326
2327 *piRetVal = 0;
2328 RTSemFastMutexRequest(pDevExt->mtxTracer);
2329
2330 if (pSession->uTracerData)
2331 {
2332 Assert(pDevExt->cTracerOpens > 0);
2333 if (pDevExt->pTracerOps)
2334 {
2335 if (!pDevExt->fTracerUnloading)
2336 {
2337 if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
2338 {
2339 uintptr_t uTracerData = pSession->uTracerData;
2340 pDevExt->cTracerOpens++;
2341 pSession->hTracerCaller = hNativeSelf;
2342 RTSemFastMutexRelease(pDevExt->mtxTracer);
2343
2344 rc = pDevExt->pTracerOps->pfnTracerIoCtl(pDevExt->pTracerOps, pSession, uTracerData, uCmd, uArg, piRetVal);
2345
2346 RTSemFastMutexRequest(pDevExt->mtxTracer);
2347 pSession->hTracerCaller = NIL_RTNATIVETHREAD;
2348 Assert(pDevExt->cTracerOpens > 0);
2349 pDevExt->cTracerOpens--;
2350 }
2351 else
2352 rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
2353 }
2354 else
2355 rc = VERR_SUPDRV_TRACER_UNLOADING;
2356 }
2357 else
2358 rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
2359 }
2360 else
2361 rc = VERR_SUPDRV_TRACER_NOT_OPENED;
2362
2363 RTSemFastMutexRelease(pDevExt->mtxTracer);
2364 return rc;
2365}
2366
2367
2368/**
2369 * Early module initialization hook.
2370 *
2371 * @returns VBox status code.
2372 * @param pDevExt The device extension structure.
2373 */
2374int VBOXCALL supdrvTracerInit(PSUPDRVDEVEXT pDevExt)
2375{
2376 /*
2377 * Initialize the tracer.
2378 */
2379 int rc = RTSemFastMutexCreate(&pDevExt->mtxTracer);
2380 if (RT_SUCCESS(rc))
2381 {
2382 uint32_t i;
2383
2384 pDevExt->TracerHlp.uVersion = SUPDRVTRACERHLP_VERSION;
2385 /** @todo */
2386 pDevExt->TracerHlp.uEndVersion = SUPDRVTRACERHLP_VERSION;
2387 RTListInit(&pDevExt->TracerProviderList);
2388 RTListInit(&pDevExt->TracerProviderZombieList);
2389 for (i = 0; i < RT_ELEMENTS(pDevExt->aTrackerUmodHash); i++)
2390 RTListInit(&pDevExt->aTrackerUmodHash[i]);
2391
2392#ifdef VBOX_WITH_NATIVE_DTRACE
2393 pDevExt->pTracerOps = supdrvDTraceInit();
2394 if (pDevExt->pTracerOps)
2395 g_pfnSupdrvProbeFireKernel = (PFNRT)pDevExt->pTracerOps->pfnProbeFireKernel;
2396#endif
2397
2398 /*
2399 * Register the provider for this module, if compiled in.
2400 */
2401#ifdef VBOX_WITH_DTRACE_R0DRV
2402 rc = supdrvTracerRegisterVtgObj(pDevExt, &g_VTGObjHeader, NULL /*pImage*/, NULL /*pSession*/, NULL /*pUmod*/, "vboxdrv");
2403 if (RT_SUCCESS(rc))
2404 return rc;
2405 SUPR0Printf("supdrvTracerInit: supdrvTracerRegisterVtgObj failed with rc=%d\n", rc);
2406 RTSemFastMutexDestroy(pDevExt->mtxTracer);
2407#else
2408
2409 return VINF_SUCCESS;
2410#endif
2411 }
2412 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
2413 return rc;
2414}
2415
2416
2417/**
2418 * Late module termination hook.
2419 *
2420 * @returns VBox status code.
2421 * @param pDevExt The device extension structure.
2422 */
2423void VBOXCALL supdrvTracerTerm(PSUPDRVDEVEXT pDevExt)
2424{
2425 LOG_TRACER(("supdrvTracerTerm\n"));
2426
2427 supdrvTracerRemoveAllProviders(pDevExt);
2428
2429 RTSemFastMutexDestroy(pDevExt->mtxTracer);
2430 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
2431 LOG_TRACER(("supdrvTracerTerm: Done\n"));
2432}
2433
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