VirtualBox

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

Last change on this file since 103306 was 101358, checked in by vboxsync, 8 months ago

Linux: vboxdrv: Replace SUPDRV_UNFORTIFIED_MEMCPY with RT_BCOPY_UNFORTIFIED, bugref:10209.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use