VirtualBox

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

Last change on this file since 58920 was 58920, checked in by vboxsync, 9 years ago

VBoxTpG,SupDrv: Added a per provider enabled probe counter: VTGDESCPROVIDER::cProbesEnabled, <PROVIDER>_ANY_PROBES_ENABLED()

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