VirtualBox

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

Last change on this file since 93256 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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