VirtualBox

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

Last change on this file since 103684 was 103684, checked in by vboxsync, 14 months ago

Linux kernel modules: Fix UBSAN warnings by switching to flexible arrays where possible, bugref:10585.

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