VirtualBox

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

Last change on this file since 57358 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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