VirtualBox

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

Last change on this file since 46861 was 44529, checked in by vboxsync, 12 years ago

header (C) fixes

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette