VirtualBox

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

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

warning

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