VirtualBox

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

Last change on this file since 48070 was 47518, checked in by vboxsync, 11 years ago

Found more details, extended the hack a little to be on the safe side (hopefully).

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