VirtualBox

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

Last change on this file since 44180 was 42011, checked in by vboxsync, 13 years ago

SUPDrvTracer: c90 warning.

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