VirtualBox

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

Last change on this file since 109047 was 109047, checked in by vboxsync, 3 weeks ago

SUPDrv: Make it build on linux.arm64. jiraref:VBP-1598

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