VirtualBox

source: vbox/trunk/src/VBox/ExtPacks/VBoxDTrace/VBoxDTraceR0/VBoxDTraceR0.cpp@ 53707

Last change on this file since 53707 was 53707, checked in by vboxsync, 10 years ago

VBoxDTrace: fixes (r84)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 55.5 KB
Line 
1/* $Id: VBoxDTraceR0.cpp 53707 2015-01-02 12:44:22Z vboxsync $ */
2/** @file
3 * VBoxDTraceR0.
4 */
5
6/*
7 * Copyright (c) 2012 bird
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <VBox/sup.h>
36#include <VBox/log.h>
37
38#include <iprt/asm-amd64-x86.h>
39#include <iprt/assert.h>
40#include <iprt/ctype.h>
41#include <iprt/err.h>
42#include <iprt/mem.h>
43#include <iprt/mp.h>
44#include <iprt/process.h>
45#include <iprt/semaphore.h>
46#include <iprt/spinlock.h>
47#include <iprt/string.h>
48#include <iprt/thread.h>
49#include <iprt/time.h>
50
51#include <sys/dtrace_impl.h>
52
53#include <VBox/VBoxTpG.h>
54
55
56/*******************************************************************************
57* Defined Constants And Macros *
58*******************************************************************************/
59//#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
60//# define HAVE_RTMEMALLOCEX_FEATURES
61//#endif
62
63
64/*******************************************************************************
65* Structures and Typedefs *
66*******************************************************************************/
67
68/** Caller indicator. */
69typedef enum VBOXDTCALLER
70{
71 kVBoxDtCaller_Invalid = 0,
72 kVBoxDtCaller_Generic,
73 kVBoxDtCaller_ProbeFireUser,
74 kVBoxDtCaller_ProbeFireKernel
75} VBOXDTCALLER;
76
77/**
78 * Stack data used for thread structure and such.
79 *
80 * This is planted in every external entry point and used to emulate solaris
81 * curthread, CRED, curproc and similar. It is also used to get at the
82 * uncached probe arguments.
83 */
84typedef struct VBoxDtStackData
85{
86 /** Eyecatcher no. 1 (VBDT_STACK_DATA_MAGIC2). */
87 uint32_t u32Magic1;
88 /** Eyecatcher no. 2 (VBDT_STACK_DATA_MAGIC2). */
89 uint32_t u32Magic2;
90 /** The format of the caller specific data. */
91 VBOXDTCALLER enmCaller;
92 /** Caller specific data. */
93 union
94 {
95 /** kVBoxDtCaller_ProbeFireKernel. */
96 struct
97 {
98 /** The caller. */
99 uintptr_t uCaller;
100 /** Pointer to the stack arguments of a probe function call. */
101 uintptr_t *pauStackArgs;
102 } ProbeFireKernel;
103 /** kVBoxDtCaller_ProbeFireUser. */
104 struct
105 {
106 /** The user context. */
107 PCSUPDRVTRACERUSRCTX pCtx;
108 } ProbeFireUser;
109 } u;
110 /** Credentials allocated by VBoxDtGetCurrentCreds. */
111 struct VBoxDtCred *pCred;
112 /** Thread structure currently being held by this thread. */
113 struct VBoxDtThread *pThread;
114 /** Pointer to this structure.
115 * This is the final bit of integrity checking. */
116 struct VBoxDtStackData *pSelf;
117} VBDTSTACKDATA;
118/** Pointer to the on-stack thread specific data. */
119typedef VBDTSTACKDATA *PVBDTSTACKDATA;
120
121/** The first magic value. */
122#define VBDT_STACK_DATA_MAGIC1 RT_MAKE_U32_FROM_U8('V', 'B', 'o', 'x')
123/** The second magic value. */
124#define VBDT_STACK_DATA_MAGIC2 RT_MAKE_U32_FROM_U8('D', 'T', 'r', 'c')
125
126/** The alignment of the stack data.
127 * The data doesn't require more than sizeof(uintptr_t) alignment, but the
128 * greater alignment the quicker lookup. */
129#define VBDT_STACK_DATA_ALIGN 32
130
131/** Plants the stack data. */
132#define VBDT_SETUP_STACK_DATA(a_enmCaller) \
133 uint8_t abBlob[sizeof(VBDTSTACKDATA) + VBDT_STACK_DATA_ALIGN - 1]; \
134 PVBDTSTACKDATA pStackData = (PVBDTSTACKDATA)( (uintptr_t)&abBlob[VBDT_STACK_DATA_ALIGN - 1] \
135 & ~(uintptr_t)(VBDT_STACK_DATA_ALIGN - 1)); \
136 pStackData->u32Magic1 = VBDT_STACK_DATA_MAGIC1; \
137 pStackData->u32Magic2 = VBDT_STACK_DATA_MAGIC2; \
138 pStackData->enmCaller = a_enmCaller; \
139 pStackData->pCred = NULL; \
140 pStackData->pThread = NULL; \
141 pStackData->pSelf = pStackData
142
143/** Passifies the stack data and frees up resource held within it. */
144#define VBDT_CLEAR_STACK_DATA() \
145 do \
146 { \
147 pStackData->u32Magic1 = 0; \
148 pStackData->u32Magic2 = 0; \
149 pStackData->pSelf = NULL; \
150 if (pStackData->pCred) \
151 crfree(pStackData->pCred); \
152 if (pStackData->pThread) \
153 VBoxDtReleaseThread(pStackData->pThread); \
154 } while (0)
155
156
157/*******************************************************************************
158* Global Variables *
159*******************************************************************************/
160/** Per CPU information */
161cpucore_t g_aVBoxDtCpuCores[RTCPUSET_MAX_CPUS];
162/** Dummy mutex. */
163struct VBoxDtMutex g_DummyMtx;
164/** Pointer to the tracer helpers provided by VBoxDrv. */
165static PCSUPDRVTRACERHLP g_pVBoxDTraceHlp;
166
167dtrace_cacheid_t dtrace_predcache_id = DTRACE_CACHEIDNONE + 1;
168
169#if 0
170void (*dtrace_cpu_init)(processorid_t);
171void (*dtrace_modload)(struct modctl *);
172void (*dtrace_modunload)(struct modctl *);
173void (*dtrace_helpers_cleanup)(void);
174void (*dtrace_helpers_fork)(proc_t *, proc_t *);
175void (*dtrace_cpustart_init)(void);
176void (*dtrace_cpustart_fini)(void);
177void (*dtrace_cpc_fire)(uint64_t);
178void (*dtrace_debugger_init)(void);
179void (*dtrace_debugger_fini)(void);
180#endif
181
182
183/**
184 * Gets the stack data.
185 *
186 * @returns Pointer to the stack data. Never NULL.
187 */
188static PVBDTSTACKDATA vboxDtGetStackData(void)
189{
190 int volatile iDummy = 1; /* use this to get the stack address. */
191 PVBDTSTACKDATA pData = (PVBDTSTACKDATA)( ((uintptr_t)&iDummy + VBDT_STACK_DATA_ALIGN - 1)
192 & ~(uintptr_t)(VBDT_STACK_DATA_ALIGN - 1));
193 for (;;)
194 {
195 if ( pData->u32Magic1 == VBDT_STACK_DATA_MAGIC1
196 && pData->u32Magic2 == VBDT_STACK_DATA_MAGIC2
197 && pData->pSelf == pData)
198 return pData;
199 pData = (PVBDTSTACKDATA)((uintptr_t)pData + VBDT_STACK_DATA_ALIGN);
200 }
201}
202
203
204void dtrace_toxic_ranges(void (*pfnAddOne)(uintptr_t uBase, uintptr_t cbRange))
205{
206 /** @todo ? */
207}
208
209
210
211/**
212 * Dummy callback used by dtrace_sync.
213 */
214static DECLCALLBACK(void) vboxDtSyncCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
215{
216 NOREF(idCpu); NOREF(pvUser1); NOREF(pvUser2);
217}
218
219
220/**
221 * Synchronzie across all CPUs (expensive).
222 */
223void dtrace_sync(void)
224{
225 int rc = RTMpOnAll(vboxDtSyncCallback, NULL, NULL);
226 AssertRC(rc);
227}
228
229
230/**
231 * Fetch a 8-bit "word" from userland.
232 *
233 * @return The byte value.
234 * @param pvUserAddr The userland address.
235 */
236uint8_t dtrace_fuword8( void *pvUserAddr)
237{
238 uint8_t u8;
239 int rc = RTR0MemUserCopyFrom(&u8, (uintptr_t)pvUserAddr, sizeof(u8));
240 if (RT_FAILURE(rc))
241 {
242 RTCPUID iCpu = VBDT_GET_CPUID();
243 cpu_core[iCpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
244 cpu_core[iCpu].cpuc_dtrace_illval = (uintptr_t)pvUserAddr;
245 u8 = 0;
246 }
247 return u8;
248}
249
250
251/**
252 * Fetch a 16-bit word from userland.
253 *
254 * @return The word value.
255 * @param pvUserAddr The userland address.
256 */
257uint16_t dtrace_fuword16(void *pvUserAddr)
258{
259 uint16_t u16;
260 int rc = RTR0MemUserCopyFrom(&u16, (uintptr_t)pvUserAddr, sizeof(u16));
261 if (RT_FAILURE(rc))
262 {
263 RTCPUID iCpu = VBDT_GET_CPUID();
264 cpu_core[iCpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
265 cpu_core[iCpu].cpuc_dtrace_illval = (uintptr_t)pvUserAddr;
266 u16 = 0;
267 }
268 return u16;
269}
270
271
272/**
273 * Fetch a 32-bit word from userland.
274 *
275 * @return The dword value.
276 * @param pvUserAddr The userland address.
277 */
278uint32_t dtrace_fuword32(void *pvUserAddr)
279{
280 uint32_t u32;
281 int rc = RTR0MemUserCopyFrom(&u32, (uintptr_t)pvUserAddr, sizeof(u32));
282 if (RT_FAILURE(rc))
283 {
284 RTCPUID iCpu = VBDT_GET_CPUID();
285 cpu_core[iCpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
286 cpu_core[iCpu].cpuc_dtrace_illval = (uintptr_t)pvUserAddr;
287 u32 = 0;
288 }
289 return u32;
290}
291
292
293/**
294 * Fetch a 64-bit word from userland.
295 *
296 * @return The qword value.
297 * @param pvUserAddr The userland address.
298 */
299uint64_t dtrace_fuword64(void *pvUserAddr)
300{
301 uint64_t u64;
302 int rc = RTR0MemUserCopyFrom(&u64, (uintptr_t)pvUserAddr, sizeof(u64));
303 if (RT_FAILURE(rc))
304 {
305 RTCPUID iCpu = VBDT_GET_CPUID();
306 cpu_core[iCpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
307 cpu_core[iCpu].cpuc_dtrace_illval = (uintptr_t)pvUserAddr;
308 u64 = 0;
309 }
310 return u64;
311}
312
313
314/** copyin implementation */
315int VBoxDtCopyIn(void const *pvUser, void *pvDst, size_t cb)
316{
317 int rc = RTR0MemUserCopyFrom(pvDst, (uintptr_t)pvUser, cb);
318 return RT_SUCCESS(rc) ? 0 : -1;
319}
320
321
322/** copyout implementation */
323int VBoxDtCopyOut(void const *pvSrc, void *pvUser, size_t cb)
324{
325 int rc = RTR0MemUserCopyTo((uintptr_t)pvUser, pvSrc, cb);
326 return RT_SUCCESS(rc) ? 0 : -1;
327}
328
329
330/**
331 * Copy data from userland into the kernel.
332 *
333 * @param uUserAddr The userland address.
334 * @param uKrnlAddr The kernel buffer address.
335 * @param cb The number of bytes to copy.
336 * @param pfFlags Pointer to the relevant cpuc_dtrace_flags.
337 */
338void dtrace_copyin( uintptr_t uUserAddr, uintptr_t uKrnlAddr, size_t cb, volatile uint16_t *pfFlags)
339{
340 int rc = RTR0MemUserCopyFrom((void *)uKrnlAddr, uUserAddr, cb);
341 if (RT_FAILURE(rc))
342 {
343 *pfFlags |= CPU_DTRACE_BADADDR;
344 cpu_core[VBDT_GET_CPUID()].cpuc_dtrace_illval = uUserAddr;
345 }
346}
347
348
349/**
350 * Copy data from the kernel into userlad.
351 *
352 * @param uKrnlAddr The kernel buffer address.
353 * @param uUserAddr The userland address.
354 * @param cb The number of bytes to copy.
355 * @param pfFlags Pointer to the relevant cpuc_dtrace_flags.
356 */
357void dtrace_copyout( uintptr_t uKrnlAddr, uintptr_t uUserAddr, size_t cb, volatile uint16_t *pfFlags)
358{
359 int rc = RTR0MemUserCopyTo(uUserAddr, (void const *)uKrnlAddr, cb);
360 if (RT_FAILURE(rc))
361 {
362 *pfFlags |= CPU_DTRACE_BADADDR;
363 cpu_core[VBDT_GET_CPUID()].cpuc_dtrace_illval = uUserAddr;
364 }
365}
366
367
368/**
369 * Copy a string from userland into the kernel.
370 *
371 * @param uUserAddr The userland address.
372 * @param uKrnlAddr The kernel buffer address.
373 * @param cbMax The maximum number of bytes to copy. May stop
374 * earlier if zero byte is encountered.
375 * @param pfFlags Pointer to the relevant cpuc_dtrace_flags.
376 */
377void dtrace_copyinstr( uintptr_t uUserAddr, uintptr_t uKrnlAddr, size_t cbMax, volatile uint16_t *pfFlags)
378{
379 if (!cbMax)
380 return;
381
382 char *pszDst = (char *)uKrnlAddr;
383 int rc = RTR0MemUserCopyFrom(pszDst, uUserAddr, cbMax);
384 if (RT_FAILURE(rc))
385 {
386 /* Byte by byte - lazy bird! */
387 size_t off = 0;
388 while (off < cbMax)
389 {
390 rc = RTR0MemUserCopyFrom(&pszDst[off], uUserAddr + off, 1);
391 if (RT_FAILURE(rc))
392 {
393 *pfFlags |= CPU_DTRACE_BADADDR;
394 cpu_core[VBDT_GET_CPUID()].cpuc_dtrace_illval = uUserAddr;
395 pszDst[off] = '\0';
396 return;
397 }
398 if (!pszDst[off])
399 return;
400 off++;
401 }
402 }
403
404 pszDst[cbMax - 1] = '\0';
405}
406
407
408/**
409 * Copy a string from the kernel and into user land.
410 *
411 * @param uKrnlAddr The kernel string address.
412 * @param uUserAddr The userland address.
413 * @param cbMax The maximum number of bytes to copy. Will stop
414 * earlier if zero byte is encountered.
415 * @param pfFlags Pointer to the relevant cpuc_dtrace_flags.
416 */
417void dtrace_copyoutstr(uintptr_t uKrnlAddr, uintptr_t uUserAddr, size_t cbMax, volatile uint16_t *pfFlags)
418{
419 const char *pszSrc = (const char *)uKrnlAddr;
420 size_t cbActual = RTStrNLen(pszSrc, cbMax);
421 cbActual += cbActual < cbMax;
422 dtrace_copyout(uKrnlAddr,uUserAddr, cbActual, pfFlags);
423}
424
425
426/**
427 * Get the caller @a cCallFrames call frames up the stack.
428 *
429 * @returns The caller's return address or ~(uintptr_t)0.
430 * @param cCallFrames The number of frames.
431 */
432uintptr_t dtrace_caller(int cCallFrames)
433{
434 PVBDTSTACKDATA pData = vboxDtGetStackData();
435 if (pData->enmCaller == kVBoxDtCaller_ProbeFireKernel)
436 return pData->u.ProbeFireKernel.uCaller;
437 return ~(uintptr_t)0;
438}
439
440
441/**
442 * Get argument number @a iArg @a cCallFrames call frames up the stack.
443 *
444 * @returns The caller's return address or ~(uintptr_t)0.
445 * @param iArg The argument to get.
446 * @param cCallFrames The number of frames.
447 */
448uint64_t dtrace_getarg(int iArg, int cCallFrames)
449{
450 PVBDTSTACKDATA pData = vboxDtGetStackData();
451 AssertReturn(iArg >= 5, UINT64_MAX);
452
453 if (pData->enmCaller == kVBoxDtCaller_ProbeFireKernel)
454 return pData->u.ProbeFireKernel.pauStackArgs[iArg - 5];
455 return UINT64_MAX;
456}
457
458
459/**
460 * Produce a traceback of the kernel stack.
461 *
462 * @param paPcStack Where to return the program counters.
463 * @param cMaxFrames The maximum number of PCs to return.
464 * @param cSkipFrames The number of artificial callstack frames to
465 * skip at the top.
466 * @param pIntr Not sure what this is...
467 */
468void dtrace_getpcstack(pc_t *paPcStack, int cMaxFrames, int cSkipFrames, uint32_t *pIntr)
469{
470 int iFrame = 0;
471 while (iFrame < cMaxFrames)
472 {
473 paPcStack[iFrame] = NULL;
474 iFrame++;
475 }
476}
477
478
479/**
480 * Get the number of call frames on the stack.
481 *
482 * @returns The stack depth.
483 * @param cSkipFrames The number of artificial callstack frames to
484 * skip at the top.
485 */
486int dtrace_getstackdepth(int cSkipFrames)
487{
488 return 1;
489}
490
491
492/**
493 * Produce a traceback of the userland stack.
494 *
495 * @param paPcStack Where to return the program counters.
496 * @param paFpStack Where to return the frame pointers.
497 * @param cMaxFrames The maximum number of frames to return.
498 */
499void dtrace_getufpstack(uint64_t *paPcStack, uint64_t *paFpStack, int cMaxFrames)
500{
501 int iFrame = 0;
502 while (iFrame < cMaxFrames)
503 {
504 paPcStack[iFrame] = 0;
505 paFpStack[iFrame] = 0;
506 iFrame++;
507 }
508}
509
510
511/**
512 * Produce a traceback of the userland stack.
513 *
514 * @param paPcStack Where to return the program counters.
515 * @param cMaxFrames The maximum number of frames to return.
516 */
517void dtrace_getupcstack(uint64_t *paPcStack, int cMaxFrames)
518{
519 int iFrame = 0;
520 while (iFrame < cMaxFrames)
521 {
522 paPcStack[iFrame] = 0;
523 iFrame++;
524 }
525}
526
527
528/**
529 * Computes the depth of the userland stack.
530 */
531int dtrace_getustackdepth(void)
532{
533 return 0;
534}
535
536
537/**
538 * Get the current IPL/IRQL.
539 *
540 * @returns Current level.
541 */
542int dtrace_getipl(void)
543{
544#ifdef RT_ARCH_AMD64
545 /* CR8 is normally the same as IRQL / IPL on AMD64. */
546 return ASMGetCR8();
547#else
548 /* Just fake it on x86. */
549 return !ASMIntAreEnabled();
550#endif
551}
552
553
554/**
555 * Get current monotonic timestamp.
556 *
557 * @returns Timestamp, nano seconds.
558 */
559hrtime_t dtrace_gethrtime(void)
560{
561 return RTTimeNanoTS();
562}
563
564
565/**
566 * Get current walltime.
567 *
568 * @returns Timestamp, nano seconds.
569 */
570hrtime_t dtrace_gethrestime(void)
571{
572 /** @todo try get better resolution here somehow ... */
573 RTTIMESPEC Now;
574 return RTTimeSpecGetNano(RTTimeNow(&Now));
575}
576
577
578/**
579 * DTrace panic routine.
580 *
581 * @param pszFormat Panic message.
582 * @param va Arguments to the panic message.
583 */
584void dtrace_vpanic(const char *pszFormat, va_list va)
585{
586 RTAssertMsg1(NULL, __LINE__, __FILE__, __FUNCTION__);
587 RTAssertMsg2WeakV(pszFormat, va);
588 RTR0AssertPanicSystem();
589 for (;;)
590 {
591 ASMBreakpoint();
592 volatile char *pchCrash = (volatile char *)~(uintptr_t)0;
593 *pchCrash = '\0';
594 }
595}
596
597
598/**
599 * DTrace panic routine.
600 *
601 * @param pszFormat Panic message.
602 * @param ... Arguments to the panic message.
603 */
604void VBoxDtPanic(const char *pszFormat, ...)
605{
606 va_list va;
607 va_start(va, pszFormat);
608 dtrace_vpanic(pszFormat, va);
609 va_end(va);
610}
611
612
613/**
614 * DTrace kernel message routine.
615 *
616 * @param pszFormat Kernel message.
617 * @param ... Arguments to the panic message.
618 */
619void VBoxDtCmnErr(int iLevel, const char *pszFormat, ...)
620{
621 va_list va;
622 va_start(va, pszFormat);
623 SUPR0Printf("%N", pszFormat, va);
624 va_end(va);
625}
626
627
628/** uprintf implementation */
629void VBoxDtUPrintf(const char *pszFormat, ...)
630{
631 va_list va;
632 va_start(va, pszFormat);
633 VBoxDtUPrintfV(pszFormat, va);
634 va_end(va);
635}
636
637
638/** vuprintf implementation */
639void VBoxDtUPrintfV(const char *pszFormat, va_list va)
640{
641 SUPR0Printf("%N", pszFormat, va);
642}
643
644
645/* CRED implementation. */
646cred_t *VBoxDtGetCurrentCreds(void)
647{
648 PVBDTSTACKDATA pData = vboxDtGetStackData();
649 if (!pData->pCred)
650 {
651 struct VBoxDtCred *pCred;
652#ifdef HAVE_RTMEMALLOCEX_FEATURES
653 int rc = RTMemAllocEx(sizeof(*pCred), 0, RTMEMALLOCEX_FLAGS_ANY_CTX, (void **)&pCred);
654#else
655 int rc = RTMemAllocEx(sizeof(*pCred), 0, 0, (void **)&pCred);
656#endif
657 AssertFatalRC(rc);
658 pCred->cr_refs = 1;
659 /** @todo get the right creds on unix systems. */
660 pCred->cr_uid = 0;
661 pCred->cr_ruid = 0;
662 pCred->cr_suid = 0;
663 pCred->cr_gid = 0;
664 pCred->cr_rgid = 0;
665 pCred->cr_sgid = 0;
666 pCred->cr_zone = 0;
667 pData->pCred = pCred;
668 }
669
670 return pData->pCred;
671}
672
673
674/* crhold implementation */
675void VBoxDtCredHold(struct VBoxDtCred *pCred)
676{
677 int32_t cRefs = ASMAtomicIncS32(&pCred->cr_refs);
678 Assert(cRefs > 1);
679}
680
681
682/* crfree implementation */
683void VBoxDtCredFree(struct VBoxDtCred *pCred)
684{
685 int32_t cRefs = ASMAtomicDecS32(&pCred->cr_refs);
686 Assert(cRefs >= 0);
687 if (!cRefs)
688 RTMemFreeEx(pCred, sizeof(*pCred));
689}
690
691/** Spinlock protecting the thread structures. */
692static RTSPINLOCK g_hThreadSpinlock = NIL_RTSPINLOCK;
693/** List of threads by usage age. */
694static RTLISTANCHOR g_ThreadAgeList;
695/** Hash table for looking up thread structures. */
696static struct VBoxDtThread *g_apThreadsHash[16384];
697/** Fake kthread_t structures.
698 * The size of this array is making horrible ASSUMPTIONS about the number of
699 * thread in the system that will be subjected to DTracing. */
700static struct VBoxDtThread g_aThreads[8192];
701
702
703static int vboxDtInitThreadDb(void)
704{
705 int rc = RTSpinlockCreate(&g_hThreadSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxDtThreadDb");
706 if (RT_FAILURE(rc))
707 return rc;
708
709 RTListInit(&g_ThreadAgeList);
710 for (uint32_t i = 0; i < RT_ELEMENTS(g_aThreads); i++)
711 {
712 g_aThreads[i].hNative = NIL_RTNATIVETHREAD;
713 g_aThreads[i].uPid = NIL_RTPROCESS;
714 RTListPrepend(&g_ThreadAgeList, &g_aThreads[i].AgeEntry);
715 }
716
717 return VINF_SUCCESS;
718}
719
720
721static void vboxDtTermThreadDb(void)
722{
723 RTSpinlockDestroy(g_hThreadSpinlock);
724 g_hThreadSpinlock = NIL_RTSPINLOCK;
725 RTListInit(&g_ThreadAgeList);
726}
727
728
729/* curthread implementation, providing a fake kthread_t. */
730struct VBoxDtThread *VBoxDtGetCurrentThread(void)
731{
732 /*
733 * Once we've retrieved a thread, we hold on to it until the thread exits
734 * the VBoxDTrace module.
735 */
736 PVBDTSTACKDATA pData = vboxDtGetStackData();
737 if (pData->pThread)
738 {
739 AssertPtr(pData->pThread);
740 Assert(pData->pThread->hNative == RTThreadNativeSelf());
741 Assert(pData->pThread->uPid == RTProcSelf());
742 Assert(RTListIsEmpty(&pData->pThread->AgeEntry));
743 return pData->pThread;
744 }
745
746 /*
747 * Lookup the thread in the hash table.
748 */
749 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
750 RTPROCESS uPid = RTProcSelf();
751 uintptr_t iHash = (hNativeSelf * 2654435761) % RT_ELEMENTS(g_apThreadsHash);
752
753 RTSpinlockAcquire(g_hThreadSpinlock);
754
755 struct VBoxDtThread *pThread = g_apThreadsHash[iHash];
756 while (pThread)
757 {
758 if (pThread->hNative == hNativeSelf)
759 {
760 if (pThread->uPid != uPid)
761 {
762 /* Re-initialize the reused thread. */
763 pThread->uPid = uPid;
764 pThread->t_dtrace_vtime = 0;
765 pThread->t_dtrace_start = 0;
766 pThread->t_dtrace_stop = 0;
767 pThread->t_dtrace_scrpc = 0;
768 pThread->t_dtrace_astpc = 0;
769 pThread->t_predcache = 0;
770 }
771
772 /* Hold the thread in the on-stack data, making sure it does not
773 get reused till the thread leaves VBoxDTrace. */
774 RTListNodeRemove(&pThread->AgeEntry);
775 pData->pThread = pThread;
776
777 RTSpinlockReleaseNoInts(g_hThreadSpinlock);
778 return pThread;
779 }
780
781 pThread = pThread->pNext;
782 }
783
784 /*
785 * Unknown thread. Allocate a new entry, recycling unused or old ones.
786 */
787 pThread = RTListGetLast(&g_ThreadAgeList, struct VBoxDtThread, AgeEntry);
788 AssertFatal(pThread);
789 RTListNodeRemove(&pThread->AgeEntry);
790 if (pThread->hNative != NIL_RTNATIVETHREAD)
791 {
792 uintptr_t iHash2 = (pThread->hNative * 2654435761) % RT_ELEMENTS(g_apThreadsHash);
793 if (g_apThreadsHash[iHash2] == pThread)
794 g_apThreadsHash[iHash2] = pThread->pNext;
795 else
796 {
797 for (struct VBoxDtThread *pPrev = g_apThreadsHash[iHash2]; ; pPrev = pPrev->pNext)
798 {
799 AssertPtr(pPrev);
800 if (pPrev->pNext == pThread)
801 {
802 pPrev->pNext = pThread->pNext;
803 break;
804 }
805 }
806 }
807 }
808
809 /*
810 * Initialize the data.
811 */
812 pThread->t_dtrace_vtime = 0;
813 pThread->t_dtrace_start = 0;
814 pThread->t_dtrace_stop = 0;
815 pThread->t_dtrace_scrpc = 0;
816 pThread->t_dtrace_astpc = 0;
817 pThread->t_predcache = 0;
818 pThread->hNative = hNativeSelf;
819 pThread->uPid = uPid;
820
821 /*
822 * Add it to the hash as well as the on-stack data.
823 */
824 pThread->pNext = g_apThreadsHash[iHash];
825 g_apThreadsHash[iHash] = pThread->pNext;
826
827 pData->pThread = pThread;
828
829 RTSpinlockReleaseNoInts(g_hThreadSpinlock);
830 return pThread;
831}
832
833
834/**
835 * Called by the stack data destructor.
836 *
837 * @param pThread The thread to release.
838 *
839 */
840static void VBoxDtReleaseThread(struct VBoxDtThread *pThread)
841{
842 RTSpinlockAcquire(g_hThreadSpinlock);
843
844 RTListAppend(&g_ThreadAgeList, &pThread->AgeEntry);
845
846 RTSpinlockReleaseNoInts(g_hThreadSpinlock);
847}
848
849
850
851
852/*
853 *
854 * Virtual Memory / Resource Allocator.
855 * Virtual Memory / Resource Allocator.
856 * Virtual Memory / Resource Allocator.
857 *
858 */
859
860
861/** The number of bits per chunk.
862 * @remarks The 32 bytes are for heap headers and such like. */
863#define VBOXDTVMEMCHUNK_BITS ( ((_64K - 32 - sizeof(uint32_t) * 2) / sizeof(uint32_t)) * 32)
864
865/**
866 * Resource allocator chunk.
867 */
868typedef struct VBoxDtVMemChunk
869{
870 /** The ordinal (unbased) of the first item. */
871 uint32_t iFirst;
872 /** The current number of free items in this chunk. */
873 uint32_t cCurFree;
874 /** The allocation bitmap. */
875 uint32_t bm[VBOXDTVMEMCHUNK_BITS / 32];
876} VBOXDTVMEMCHUNK;
877/** Pointer to a resource allocator chunk. */
878typedef VBOXDTVMEMCHUNK *PVBOXDTVMEMCHUNK;
879
880
881
882/**
883 * Resource allocator instance.
884 */
885typedef struct VBoxDtVMem
886{
887 /** Spinlock protecting the data. */
888 RTSPINLOCK hSpinlock;
889 /** Magic value. */
890 uint32_t u32Magic;
891 /** The current number of free items in the chunks. */
892 uint32_t cCurFree;
893 /** The current number of chunks that we have allocated. */
894 uint32_t cCurChunks;
895 /** The configured resource base. */
896 uint32_t uBase;
897 /** The configured max number of items. */
898 uint32_t cMaxItems;
899 /** The size of the apChunks array. */
900 uint32_t cMaxChunks;
901 /** Array of chunk pointers.
902 * (The size is determined at creation.) */
903 PVBOXDTVMEMCHUNK apChunks[1];
904} VBOXDTVMEM;
905/** Pointer to a resource allocator instance. */
906typedef VBOXDTVMEM *PVBOXDTVMEM;
907
908/** Magic value for the VBOXDTVMEM structure. */
909#define VBOXDTVMEM_MAGIC RT_MAKE_U32_FROM_U8('V', 'M', 'e', 'm')
910
911
912/* vmem_create implementation */
913struct VBoxDtVMem *VBoxDtVMemCreate(const char *pszName, void *pvBase, size_t cb, size_t cbUnit,
914 PFNRT pfnAlloc, PFNRT pfnFree, struct VBoxDtVMem *pSrc,
915 size_t cbQCacheMax, uint32_t fFlags)
916{
917 /*
918 * Assert preconditions of this implementation.
919 */
920 AssertMsgReturn((uintptr_t)pvBase <= UINT32_MAX, ("%p\n", pvBase), NULL);
921 AssertMsgReturn(cb <= UINT32_MAX, ("%zu\n", cb), NULL);
922 AssertMsgReturn((uintptr_t)pvBase + cb - 1 <= UINT32_MAX, ("%p %zu\n", pvBase, cb), NULL);
923 AssertMsgReturn(cbUnit == 1, ("%zu\n", cbUnit), NULL);
924 AssertReturn(!pfnAlloc, NULL);
925 AssertReturn(!pfnFree, NULL);
926 AssertReturn(!pSrc, NULL);
927 AssertReturn(!cbQCacheMax, NULL);
928 AssertReturn(fFlags & VM_SLEEP, NULL);
929 AssertReturn(fFlags & VMC_IDENTIFIER, NULL);
930
931 /*
932 * Allocate the instance.
933 */
934 uint32_t cChunks = (uint32_t)cb / VBOXDTVMEMCHUNK_BITS;
935 if (cb % VBOXDTVMEMCHUNK_BITS)
936 cChunks++;
937 PVBOXDTVMEM pThis = (PVBOXDTVMEM)RTMemAllocZ(RT_OFFSETOF(VBOXDTVMEM, apChunks[cChunks]));
938 if (!pThis)
939 return NULL;
940 int rc = RTSpinlockCreate(&pThis->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxDtVMem");
941 if (RT_FAILURE(rc))
942 {
943 RTMemFree(pThis);
944 return NULL;
945 }
946 pThis->u32Magic = VBOXDTVMEM_MAGIC;
947 pThis->cCurFree = 0;
948 pThis->cCurChunks = 0;
949 pThis->uBase = (uint32_t)(uintptr_t)pvBase;
950 pThis->cMaxItems = (uint32_t)cb;
951 pThis->cMaxChunks = cChunks;
952
953 return pThis;
954}
955
956
957/* vmem_destroy implementation */
958void VBoxDtVMemDestroy(struct VBoxDtVMem *pThis)
959{
960 if (!pThis)
961 return;
962 AssertPtrReturnVoid(pThis);
963 AssertReturnVoid(pThis->u32Magic == VBOXDTVMEM_MAGIC);
964
965 /*
966 * Invalidate the instance.
967 */
968 RTSpinlockAcquire(pThis->hSpinlock); /* paranoia */
969 pThis->u32Magic = 0;
970 RTSpinlockRelease(pThis->hSpinlock);
971 RTSpinlockDestroy(pThis->hSpinlock);
972
973 /*
974 * Free the chunks, then the instance.
975 */
976 uint32_t iChunk = pThis->cCurChunks;
977 while (iChunk-- > 0)
978 {
979 RTMemFree(pThis->apChunks[iChunk]);
980 pThis->apChunks[iChunk] = NULL;
981 }
982 RTMemFree(pThis);
983}
984
985
986/* vmem_alloc implementation */
987void *VBoxDtVMemAlloc(struct VBoxDtVMem *pThis, size_t cbMem, uint32_t fFlags)
988{
989 /*
990 * Validate input.
991 */
992 AssertReturn(fFlags & VM_BESTFIT, NULL);
993 AssertReturn(fFlags & VM_SLEEP, NULL);
994 AssertReturn(cbMem == 1, NULL);
995 AssertPtrReturn(pThis, NULL);
996 AssertReturn(pThis->u32Magic == VBOXDTVMEM_MAGIC, NULL);
997
998 /*
999 * Allocation loop.
1000 */
1001 RTSpinlockAcquire(pThis->hSpinlock);
1002 for (;;)
1003 {
1004 PVBOXDTVMEMCHUNK pChunk;
1005 uint32_t const cChunks = pThis->cCurChunks;
1006
1007 if (RT_LIKELY(pThis->cCurFree > 0))
1008 {
1009 for (uint32_t iChunk = 0; iChunk < cChunks; iChunk++)
1010 {
1011 pChunk = pThis->apChunks[iChunk];
1012 if (pChunk->cCurFree > 0)
1013 {
1014 int iBit = ASMBitFirstClear(pChunk->bm, VBOXDTVMEMCHUNK_BITS);
1015 AssertMsgReturnStmt(iBit >= 0 && (unsigned)iBit < VBOXDTVMEMCHUNK_BITS, ("%d\n", iBit),
1016 RTSpinlockRelease(pThis->hSpinlock),
1017 NULL);
1018
1019 ASMBitSet(pChunk->bm, iBit);
1020 pChunk->cCurFree--;
1021 pThis->cCurFree--;
1022
1023 uint32_t iRet = (uint32_t)iBit + pChunk->iFirst + pThis->uBase;
1024 RTSpinlockReleaseNoInts(pThis->hSpinlock);
1025 return (void *)(uintptr_t)iRet;
1026 }
1027 }
1028 AssertFailedBreak();
1029 }
1030
1031 /* Out of resources? */
1032 if (cChunks >= pThis->cMaxChunks)
1033 break;
1034
1035 /*
1036 * Allocate another chunk.
1037 */
1038 uint32_t const iFirstBit = cChunks > 0 ? pThis->apChunks[cChunks - 1]->iFirst + VBOXDTVMEMCHUNK_BITS : 0;
1039 uint32_t const cFreeBits = cChunks + 1 == pThis->cMaxChunks
1040 ? pThis->cMaxItems - (iFirstBit - pThis->uBase)
1041 : VBOXDTVMEMCHUNK_BITS;
1042 Assert(cFreeBits <= VBOXDTVMEMCHUNK_BITS);
1043
1044 RTSpinlockRelease(pThis->hSpinlock);
1045
1046 pChunk = (PVBOXDTVMEMCHUNK)RTMemAllocZ(sizeof(*pChunk));
1047 if (!pChunk)
1048 return NULL;
1049
1050 pChunk->iFirst = iFirstBit;
1051 pChunk->cCurFree = cFreeBits;
1052 if (cFreeBits != VBOXDTVMEMCHUNK_BITS)
1053 {
1054 /* lazy bird. */
1055 uint32_t iBit = cFreeBits;
1056 while (iBit < VBOXDTVMEMCHUNK_BITS)
1057 {
1058 ASMBitSet(pChunk->bm, iBit);
1059 iBit++;
1060 }
1061 }
1062
1063 RTSpinlockAcquire(pThis->hSpinlock);
1064
1065 /*
1066 * Insert the new chunk. If someone raced us here, we'll drop it to
1067 * avoid wasting resources.
1068 */
1069 if (pThis->cCurChunks == cChunks)
1070 {
1071 pThis->apChunks[cChunks] = pChunk;
1072 pThis->cCurFree += pChunk->cCurFree;
1073 pThis->cCurChunks += 1;
1074 }
1075 else
1076 {
1077 RTSpinlockRelease(pThis->hSpinlock);
1078 RTMemFree(pChunk);
1079 RTSpinlockAcquire(pThis->hSpinlock);
1080 }
1081 }
1082 RTSpinlockReleaseNoInts(pThis->hSpinlock);
1083
1084 return NULL;
1085}
1086
1087/* vmem_free implementation */
1088void VBoxDtVMemFree(struct VBoxDtVMem *pThis, void *pvMem, size_t cbMem)
1089{
1090 /*
1091 * Validate input.
1092 */
1093 AssertReturnVoid(cbMem == 1);
1094 AssertPtrReturnVoid(pThis);
1095 AssertReturnVoid(pThis->u32Magic == VBOXDTVMEM_MAGIC);
1096
1097 AssertReturnVoid((uintptr_t)pvMem < UINT32_MAX);
1098 uint32_t uMem = (uint32_t)(uintptr_t)pvMem;
1099 AssertReturnVoid(uMem >= pThis->uBase);
1100 uMem -= pThis->uBase;
1101 AssertReturnVoid(uMem < pThis->cMaxItems);
1102
1103
1104 /*
1105 * Free it.
1106 */
1107 RTSpinlockAcquire(pThis->hSpinlock);
1108 uint32_t const iChunk = uMem / VBOXDTVMEMCHUNK_BITS;
1109 if (iChunk < pThis->cCurChunks)
1110 {
1111 PVBOXDTVMEMCHUNK pChunk = pThis->apChunks[iChunk];
1112 uint32_t iBit = uMem - pChunk->iFirst;
1113 AssertReturnVoidStmt(iBit < VBOXDTVMEMCHUNK_BITS, RTSpinlockRelease(pThis->hSpinlock));
1114 AssertReturnVoidStmt(ASMBitTestAndClear(pChunk->bm, iBit), RTSpinlockRelease(pThis->hSpinlock));
1115
1116 pChunk->cCurFree++;
1117 pThis->cCurFree++;
1118 }
1119
1120 RTSpinlockRelease(pThis->hSpinlock);
1121}
1122
1123
1124/*
1125 *
1126 * Memory Allocators.
1127 * Memory Allocators.
1128 * Memory Allocators.
1129 *
1130 */
1131
1132
1133/* kmem_alloc implementation */
1134void *VBoxDtKMemAlloc(size_t cbMem, uint32_t fFlags)
1135{
1136 void *pvMem;
1137#ifdef HAVE_RTMEMALLOCEX_FEATURES
1138 uint32_t fMemAllocFlags = fFlags & KM_NOSLEEP ? RTMEMALLOCEX_FLAGS_ANY_CTX : 0;
1139#else
1140 uint32_t fMemAllocFlags = 0;
1141#endif
1142 int rc = RTMemAllocEx(cbMem, 0, fMemAllocFlags, &pvMem);
1143 AssertRCReturn(rc, NULL);
1144 AssertPtr(pvMem);
1145 return pvMem;
1146}
1147
1148
1149/* kmem_zalloc implementation */
1150void *VBoxDtKMemAllocZ(size_t cbMem, uint32_t fFlags)
1151{
1152 void *pvMem;
1153#ifdef HAVE_RTMEMALLOCEX_FEATURES
1154 uint32_t fMemAllocFlags = (fFlags & KM_NOSLEEP ? RTMEMALLOCEX_FLAGS_ANY_CTX : 0) | RTMEMALLOCEX_FLAGS_ZEROED;
1155#else
1156 uint32_t fMemAllocFlags = RTMEMALLOCEX_FLAGS_ZEROED;
1157#endif
1158 int rc = RTMemAllocEx(cbMem, 0, fMemAllocFlags, &pvMem);
1159 AssertRCReturn(rc, NULL);
1160 AssertPtr(pvMem);
1161 return pvMem;
1162}
1163
1164
1165/* kmem_free implementation */
1166void VBoxDtKMemFree(void *pvMem, size_t cbMem)
1167{
1168 RTMemFreeEx(pvMem, cbMem);
1169}
1170
1171
1172/**
1173 * Memory cache mockup structure.
1174 * No slab allocator here!
1175 */
1176struct VBoxDtMemCache
1177{
1178 uint32_t u32Magic;
1179 size_t cbBuf;
1180 size_t cbAlign;
1181};
1182
1183
1184/* Limited kmem_cache_create implementation. */
1185struct VBoxDtMemCache *VBoxDtKMemCacheCreate(const char *pszName, size_t cbBuf, size_t cbAlign,
1186 PFNRT pfnCtor, PFNRT pfnDtor, PFNRT pfnReclaim,
1187 void *pvUser, void *pvVM, uint32_t fFlags)
1188{
1189 /*
1190 * Check the input.
1191 */
1192 AssertReturn(cbBuf > 0 && cbBuf < _1G, NULL);
1193 AssertReturn(RT_IS_POWER_OF_TWO(cbAlign), NULL);
1194 AssertReturn(!pfnCtor, NULL);
1195 AssertReturn(!pfnDtor, NULL);
1196 AssertReturn(!pfnReclaim, NULL);
1197 AssertReturn(!pvUser, NULL);
1198 AssertReturn(!pvVM, NULL);
1199 AssertReturn(!fFlags, NULL);
1200
1201 /*
1202 * Create a parameter container. Don't bother with anything fancy here yet,
1203 * just get something working.
1204 */
1205 struct VBoxDtMemCache *pThis = (struct VBoxDtMemCache *)RTMemAlloc(sizeof(*pThis));
1206 if (!pThis)
1207 return NULL;
1208
1209 pThis->cbAlign = cbAlign;
1210 pThis->cbBuf = cbBuf;
1211 return pThis;
1212}
1213
1214
1215/* Limited kmem_cache_destroy implementation. */
1216void VBoxDtKMemCacheDestroy(struct VBoxDtMemCache *pThis)
1217{
1218 RTMemFree(pThis);
1219}
1220
1221
1222/* kmem_cache_alloc implementation. */
1223void *VBoxDtKMemCacheAlloc(struct VBoxDtMemCache *pThis, uint32_t fFlags)
1224{
1225 void *pvMem;
1226#ifdef HAVE_RTMEMALLOCEX_FEATURES
1227 uint32_t fMemAllocFlags = (fFlags & KM_NOSLEEP ? RTMEMALLOCEX_FLAGS_ANY_CTX : 0) | RTMEMALLOCEX_FLAGS_ZEROED;
1228#else
1229 uint32_t fMemAllocFlags = RTMEMALLOCEX_FLAGS_ZEROED;
1230#endif
1231 int rc = RTMemAllocEx(pThis->cbBuf, /*pThis->cbAlign*/0, fMemAllocFlags, &pvMem);
1232 AssertRCReturn(rc, NULL);
1233 AssertPtr(pvMem);
1234 return pvMem;
1235}
1236
1237
1238/* kmem_cache_free implementation. */
1239void VBoxDtKMemCacheFree(struct VBoxDtMemCache *pThis, void *pvMem)
1240{
1241 RTMemFreeEx(pvMem, pThis->cbBuf);
1242}
1243
1244
1245/*
1246 *
1247 * Mutex Semaphore Wrappers.
1248 *
1249 */
1250
1251
1252/** Initializes a mutex. */
1253int VBoxDtMutexInit(struct VBoxDtMutex *pMtx)
1254{
1255 AssertReturn(pMtx != &g_DummyMtx, -1);
1256 AssertPtr(pMtx);
1257
1258 pMtx->hOwner = NIL_RTNATIVETHREAD;
1259 pMtx->hMtx = NIL_RTSEMMUTEX;
1260 int rc = RTSemMutexCreate(&pMtx->hMtx);
1261 if (RT_SUCCESS(rc))
1262 return 0;
1263 return -1;
1264}
1265
1266
1267/** Deletes a mutex. */
1268void VBoxDtMutexDelete(struct VBoxDtMutex *pMtx)
1269{
1270 AssertReturnVoid(pMtx != &g_DummyMtx);
1271 AssertPtr(pMtx);
1272 if (pMtx->hMtx == NIL_RTSEMMUTEX || pMtx->hMtx == NULL)
1273 return;
1274
1275 Assert(pMtx->hOwner == NIL_RTNATIVETHREAD);
1276 int rc = RTSemMutexDestroy(pMtx->hMtx); AssertRC(rc);
1277 pMtx->hMtx = NIL_RTSEMMUTEX;
1278}
1279
1280
1281/* mutex_enter implementation */
1282void VBoxDtMutexEnter(struct VBoxDtMutex *pMtx)
1283{
1284 AssertPtr(pMtx);
1285 if (pMtx == &g_DummyMtx)
1286 return;
1287
1288 RTNATIVETHREAD hSelf = RTThreadNativeSelf();
1289
1290 int rc = RTSemMutexRequest(pMtx->hMtx, RT_INDEFINITE_WAIT);
1291 AssertFatalRC(rc);
1292
1293 Assert(pMtx->hOwner == NIL_RTNATIVETHREAD);
1294 pMtx->hOwner = hSelf;
1295}
1296
1297
1298/* mutex_exit implementation */
1299void VBoxDtMutexExit(struct VBoxDtMutex *pMtx)
1300{
1301 AssertPtr(pMtx);
1302 if (pMtx == &g_DummyMtx)
1303 return;
1304
1305 Assert(pMtx->hOwner == RTThreadNativeSelf());
1306
1307 pMtx->hOwner = NIL_RTNATIVETHREAD;
1308 int rc = RTSemMutexRelease(pMtx->hMtx);
1309 AssertFatalRC(rc);
1310}
1311
1312
1313/* MUTEX_HELD implementation */
1314bool VBoxDtMutexIsOwner(struct VBoxDtMutex *pMtx)
1315{
1316 AssertPtrReturn(pMtx, false);
1317 if (pMtx == &g_DummyMtx)
1318 return true;
1319 return pMtx->hOwner == RTThreadNativeSelf();
1320}
1321
1322
1323
1324/*
1325 *
1326 * Helpers for handling VTG structures.
1327 * Helpers for handling VTG structures.
1328 * Helpers for handling VTG structures.
1329 *
1330 */
1331
1332
1333
1334/**
1335 * Converts an attribute from VTG description speak to DTrace.
1336 *
1337 * @param pDtAttr The DTrace attribute (dst).
1338 * @param pVtgAttr The VTG attribute descriptor (src).
1339 */
1340static void vboxDtVtgConvAttr(dtrace_attribute_t *pDtAttr, PCVTGDESCATTR pVtgAttr)
1341{
1342 pDtAttr->dtat_name = pVtgAttr->u8Code - 1;
1343 pDtAttr->dtat_data = pVtgAttr->u8Data - 1;
1344 pDtAttr->dtat_class = pVtgAttr->u8DataDep - 1;
1345}
1346
1347/**
1348 * Gets a string from the string table.
1349 *
1350 * @returns Pointer to the string.
1351 * @param pVtgHdr The VTG object header.
1352 * @param offStrTab The string table offset.
1353 */
1354static const char *vboxDtVtgGetString(PVTGOBJHDR pVtgHdr, uint32_t offStrTab)
1355{
1356 Assert(offStrTab < pVtgHdr->cbStrTab);
1357 return (const char *)pVtgHdr + pVtgHdr->offStrTab + offStrTab;
1358}
1359
1360
1361
1362/*
1363 *
1364 * DTrace Provider Interface.
1365 * DTrace Provider Interface.
1366 * DTrace Provider Interface.
1367 *
1368 */
1369
1370
1371/**
1372 * @callback_method_impl{dtrace_pops_t,dtps_provide}
1373 */
1374static void vboxDtPOps_Provide(void *pvProv, const dtrace_probedesc_t *pDtProbeDesc)
1375{
1376 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1377
1378 if (pDtProbeDesc)
1379 return; /* We don't generate probes, so never mind these requests. */
1380
1381 if (pProv->TracerData.DTrace.fZombie)
1382 return;
1383
1384 dtrace_provider_id_t const idProvider = pProv->TracerData.DTrace.idProvider;
1385 AssertPtrReturnVoid(idProvider);
1386
1387 AssertPtrReturnVoid(pProv->pHdr);
1388 AssertReturnVoid(pProv->pHdr->offProbeLocs != 0);
1389 uint32_t const cProbeLocs = pProv->pHdr->cbProbeLocs / sizeof(VTGPROBELOC);
1390
1391
1392 /* Need a buffer for extracting the function names and mangling them in
1393 case of collision. */
1394 size_t const cbFnNmBuf = _4K + _1K;
1395 char *pszFnNmBuf = (char *)RTMemAlloc(cbFnNmBuf);
1396 if (!pszFnNmBuf)
1397 return;
1398
1399 /*
1400 * Itereate the probe location list and register all probes related to
1401 * this provider.
1402 */
1403 uint16_t const idxProv = (uint16_t)((PVTGDESCPROVIDER)((uintptr_t)pProv->pHdr + pProv->pHdr->offProviders) - pProv->pDesc);
1404 for (uint32_t idxProbeLoc = 0; idxProbeLoc < cProbeLocs; idxProbeLoc++)
1405 {
1406 /* Skip probe location belonging to other providers or once that
1407 we've already reported. */
1408 PCVTGPROBELOC pProbeLocRO = &pProv->paProbeLocsRO[idxProbeLoc];
1409 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLocRO->pbProbe;
1410 if (pProbeDesc->idxProvider != idxProv)
1411 continue;
1412
1413 uint32_t *pidProbe;
1414 if (!pProv->fUmod)
1415 pidProbe = (uint32_t *)&pProbeLocRO->idProbe;
1416 else
1417 pidProbe = &pProv->paR0ProbeLocs[idxProbeLoc].idProbe;
1418 if (*pidProbe != 0)
1419 continue;
1420
1421 /* The function name may need to be stripped since we're using C++
1422 compilers for most of the code. ASSUMES nobody are brave/stupid
1423 enough to use function pointer returns without typedef'ing
1424 properly them (e.g. signal). */
1425 const char *pszPrbName = vboxDtVtgGetString(pProv->pHdr, pProbeDesc->offName);
1426 const char *pszFunc = pProbeLocRO->pszFunction;
1427 const char *psz = strchr(pProbeLocRO->pszFunction, '(');
1428 size_t cch;
1429 if (psz)
1430 {
1431 /* skip blanks preceeding the parameter parenthesis. */
1432 while ( (uintptr_t)psz > (uintptr_t)pProbeLocRO->pszFunction
1433 && RT_C_IS_BLANK(psz[-1]))
1434 psz--;
1435
1436 /* Find the start of the function name. */
1437 pszFunc = psz - 1;
1438 while ((uintptr_t)pszFunc > (uintptr_t)pProbeLocRO->pszFunction)
1439 {
1440 char ch = pszFunc[-1];
1441 if (!RT_C_IS_ALNUM(ch) && ch != '_' && ch != ':')
1442 break;
1443 pszFunc--;
1444 }
1445 cch = psz - pszFunc;
1446 }
1447 else
1448 cch = strlen(pszFunc);
1449 RTStrCopyEx(pszFnNmBuf, cbFnNmBuf, pszFunc, cch);
1450
1451 /* Look up the probe, if we have one in the same function, mangle
1452 the function name a little to avoid having to deal with having
1453 multiple location entries with the same probe ID. (lazy bird) */
1454 Assert(!*pidProbe);
1455 if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
1456 {
1457 RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u", pProbeLocRO->uLine);
1458 if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
1459 {
1460 unsigned iOrd = 2;
1461 while (iOrd < 128)
1462 {
1463 RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u-%u", pProbeLocRO->uLine, iOrd);
1464 if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) == DTRACE_IDNONE)
1465 break;
1466 iOrd++;
1467 }
1468 if (iOrd >= 128)
1469 {
1470 LogRel(("VBoxDrv: More than 128 duplicate probe location instances %s at line %u in function %s [%s], probe %s\n",
1471 pProbeLocRO->uLine, pProbeLocRO->pszFunction, pszFnNmBuf, pszPrbName));
1472 continue;
1473 }
1474 }
1475 }
1476
1477 /* Create the probe. */
1478 AssertCompile(sizeof(*pidProbe) == sizeof(dtrace_id_t));
1479 *pidProbe = dtrace_probe_create(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName,
1480 1 /*aframes*/, (void *)(uintptr_t)idxProbeLoc);
1481 pProv->TracerData.DTrace.cProvidedProbes++;
1482 }
1483
1484 RTMemFree(pszFnNmBuf);
1485}
1486
1487
1488/**
1489 * @callback_method_impl{dtrace_pops_t,dtps_enable}
1490 */
1491static int vboxDtPOps_Enable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
1492{
1493 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1494 if (!pProv->TracerData.DTrace.fZombie)
1495 {
1496 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
1497 PVTGPROBELOC32 pProbeLocEn = (PVTGPROBELOC32)( (uintptr_t)pProv->pvProbeLocsEn + idxProbeLoc * pProv->cbProbeLocsEn);
1498 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
1499 PCVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLocRO->pbProbe;
1500 uint32_t const idxProbe = pProbeDesc->idxEnabled;
1501
1502 if (!pProv->fUmod)
1503 {
1504 if (!pProbeLocEn->fEnabled)
1505 {
1506 pProbeLocEn->fEnabled = 1;
1507 ASMAtomicIncU32(&pProv->pacProbeEnabled[idxProbe]);
1508 }
1509 }
1510 else
1511 {
1512 /* Update kernel mode structure */
1513 if (!pProv->paR0ProbeLocs[idxProbeLoc].fEnabled)
1514 {
1515 pProv->paR0ProbeLocs[idxProbeLoc].fEnabled = 1;
1516 ASMAtomicIncU32(&pProv->paR0Probes[idxProbe].cEnabled);
1517 }
1518
1519 /* Update user mode structure. */
1520 pProbeLocEn->fEnabled = 1;
1521 pProv->pacProbeEnabled[idxProbe] = pProv->paR0Probes[idxProbe].cEnabled;
1522 }
1523 }
1524
1525 return 0;
1526}
1527
1528
1529/**
1530 * @callback_method_impl{dtrace_pops_t,dtps_disable}
1531 */
1532static void vboxDtPOps_Disable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
1533{
1534 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1535 if (!pProv->TracerData.DTrace.fZombie)
1536 {
1537 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
1538 PVTGPROBELOC32 pProbeLocEn = (PVTGPROBELOC32)( (uintptr_t)pProv->pvProbeLocsEn + idxProbeLoc * pProv->cbProbeLocsEn);
1539 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
1540 PCVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLocRO->pbProbe;
1541 uint32_t const idxProbe = pProbeDesc->idxEnabled;
1542
1543 if (!pProv->fUmod)
1544 {
1545 if (pProbeLocEn->fEnabled)
1546 {
1547 pProbeLocEn->fEnabled = 0;
1548 ASMAtomicDecU32(&pProv->pacProbeEnabled[idxProbe]);
1549 }
1550 }
1551 else
1552 {
1553 /* Update kernel mode structure */
1554 if (pProv->paR0ProbeLocs[idxProbeLoc].fEnabled)
1555 {
1556 pProv->paR0ProbeLocs[idxProbeLoc].fEnabled = 0;
1557 ASMAtomicDecU32(&pProv->paR0Probes[idxProbe].cEnabled);
1558 }
1559
1560 /* Update user mode structure. */
1561 pProbeLocEn->fEnabled = 0;
1562 pProv->pacProbeEnabled[idxProbe] = pProv->paR0Probes[idxProbe].cEnabled;
1563 }
1564 }
1565}
1566
1567
1568/**
1569 * @callback_method_impl{dtrace_pops_t,dtps_getargdesc}
1570 */
1571static void vboxDtPOps_GetArgDesc(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
1572 dtrace_argdesc_t *pArgDesc)
1573{
1574 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1575 unsigned uArg = pArgDesc->dtargd_ndx;
1576 pArgDesc->dtargd_ndx = DTRACE_ARGNONE;
1577
1578 if (!pProv->TracerData.DTrace.fZombie)
1579 {
1580 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
1581 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
1582 PCVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLocRO->pbProbe;
1583 PCVTGDESCARGLIST pArgList = (PCVTGDESCARGLIST)( (uintptr_t)pProv->pHdr
1584 + pProv->pHdr->offArgLists
1585 + pProbeDesc->offArgList);
1586 AssertReturnVoid(pProbeDesc->offArgList < pProv->pHdr->cbArgLists);
1587
1588 if (uArg < pArgList->cArgs)
1589 {
1590 const char *pszType = vboxDtVtgGetString(pProv->pHdr, pArgList->aArgs[uArg].offType);
1591 size_t cchType = strlen(pszType);
1592 if (cchType < sizeof(pArgDesc->dtargd_native))
1593 {
1594 memcpy(pArgDesc->dtargd_native, pszType, cchType + 1);
1595 pArgDesc->dtargd_ndx = uArg;
1596 /** @todo mapping? */
1597 return;
1598 }
1599 }
1600 }
1601
1602}
1603
1604
1605/**
1606 * @callback_method_impl{dtrace_pops_t,dtps_getargval}
1607 */
1608static uint64_t vboxDtPOps_GetArgVal(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
1609 int iArg, int cFrames)
1610{
1611 PVBDTSTACKDATA pData = vboxDtGetStackData();
1612 AssertReturn(iArg >= 5, UINT64_MAX);
1613
1614 if (pData->enmCaller == kVBoxDtCaller_ProbeFireKernel)
1615 return pData->u.ProbeFireKernel.pauStackArgs[iArg - 5];
1616
1617 if (pData->enmCaller == kVBoxDtCaller_ProbeFireUser)
1618 {
1619 PCSUPDRVTRACERUSRCTX pCtx = pData->u.ProbeFireUser.pCtx;
1620 if (pCtx->cBits == 32)
1621 {
1622 if ((unsigned)iArg < RT_ELEMENTS(pCtx->u.X86.aArgs))
1623 return pCtx->u.X86.aArgs[iArg];
1624 }
1625 else if (pCtx->cBits == 64)
1626 {
1627 if ((unsigned)iArg < RT_ELEMENTS(pCtx->u.Amd64.aArgs))
1628 return pCtx->u.Amd64.aArgs[iArg];
1629 }
1630 else
1631 AssertFailed();
1632 }
1633
1634 NOREF(pvProbe);
1635 return UINT64_MAX;
1636}
1637
1638
1639/**
1640 * @callback_method_impl{dtrace_pops_t,dtps_destroy}
1641 */
1642static void vboxDtPOps_Destroy(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
1643{
1644 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1645 if (!pProv->TracerData.DTrace.fZombie)
1646 {
1647 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
1648 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
1649 uint32_t *pidProbe;
1650 if (!pProv->fUmod)
1651 {
1652 pidProbe = (uint32_t *)&pProbeLocRO->idProbe;
1653 Assert(!pProbeLocRO->fEnabled);
1654 Assert(*pidProbe == idProbe);
1655 }
1656 else
1657 {
1658 pidProbe = &pProv->paR0ProbeLocs[idxProbeLoc].idProbe;
1659 Assert(!pProv->paR0ProbeLocs[idxProbeLoc].fEnabled);
1660 Assert(*pidProbe == idProbe); NOREF(idProbe);
1661 }
1662 *pidProbe = 0;
1663 }
1664 pProv->TracerData.DTrace.cProvidedProbes--;
1665}
1666
1667
1668
1669/**
1670 * DTrace provider method table.
1671 */
1672static const dtrace_pops_t g_vboxDtVtgProvOps =
1673{
1674 /* .dtps_provide = */ vboxDtPOps_Provide,
1675 /* .dtps_provide_module = */ NULL,
1676 /* .dtps_enable = */ vboxDtPOps_Enable,
1677 /* .dtps_disable = */ vboxDtPOps_Disable,
1678 /* .dtps_suspend = */ NULL,
1679 /* .dtps_resume = */ NULL,
1680 /* .dtps_getargdesc = */ vboxDtPOps_GetArgDesc,
1681 /* .dtps_getargval = */ vboxDtPOps_GetArgVal,
1682 /* .dtps_usermode = */ NULL,
1683 /* .dtps_destroy = */ vboxDtPOps_Destroy
1684};
1685
1686
1687
1688
1689/*
1690 *
1691 * Support Driver Tracer Interface.
1692 * Support Driver Tracer Interface.
1693 * Support Driver Tracer Interface.
1694 *
1695 */
1696
1697
1698
1699/**
1700 * interface_method_impl{SUPDRVTRACERREG,pfnProbeFireKernel}
1701 */
1702static DECLCALLBACK(void) vbdt_ProbeFireKernel(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2,
1703 uintptr_t uArg3, uintptr_t uArg4)
1704{
1705 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_ProbeFireKernel);
1706
1707 pStackData->u.ProbeFireKernel.uCaller = (uintptr_t)ASMReturnAddress();
1708 pStackData->u.ProbeFireKernel.pauStackArgs = &uArg4 + 1;
1709 dtrace_probe(pVtgProbeLoc->idProbe, uArg0, uArg1, uArg2, uArg3, uArg4);
1710
1711 VBDT_CLEAR_STACK_DATA();
1712 return ;
1713}
1714
1715
1716/**
1717 * interface_method_impl{SUPDRVTRACERREG,pfnProbeFireUser}
1718 */
1719static DECLCALLBACK(void) vbdt_ProbeFireUser(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, PCSUPDRVTRACERUSRCTX pCtx)
1720{
1721 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_ProbeFireUser);
1722
1723 pStackData->u.ProbeFireUser.pCtx = pCtx;
1724 if (pCtx->cBits == 32)
1725 dtrace_probe(pCtx->idProbe,
1726 pCtx->u.X86.aArgs[0],
1727 pCtx->u.X86.aArgs[1],
1728 pCtx->u.X86.aArgs[2],
1729 pCtx->u.X86.aArgs[3],
1730 pCtx->u.X86.aArgs[4]);
1731 else if (pCtx->cBits == 64)
1732 dtrace_probe(pCtx->idProbe,
1733 pCtx->u.Amd64.aArgs[0],
1734 pCtx->u.Amd64.aArgs[1],
1735 pCtx->u.Amd64.aArgs[2],
1736 pCtx->u.Amd64.aArgs[3],
1737 pCtx->u.Amd64.aArgs[4]);
1738 else
1739 AssertFailed();
1740
1741 VBDT_CLEAR_STACK_DATA();
1742}
1743
1744
1745/**
1746 * interface_method_impl{SUPDRVTRACERREG,pfnTracerOpen}
1747 */
1748static DECLCALLBACK(int) vbdt_TracerOpen(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uint32_t uCookie, uintptr_t uArg,
1749 uintptr_t *puSessionData)
1750{
1751 if (uCookie != RT_MAKE_U32_FROM_U8('V', 'B', 'D', 'T'))
1752 return VERR_INVALID_MAGIC;
1753 if (uArg)
1754 return VERR_INVALID_PARAMETER;
1755
1756 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1757
1758 int rc = dtrace_open((dtrace_state_t **)puSessionData, VBoxDtGetCurrentCreds());
1759
1760 VBDT_CLEAR_STACK_DATA();
1761 return RTErrConvertFromErrno(rc);
1762}
1763
1764
1765/**
1766 * interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
1767 */
1768static DECLCALLBACK(int) vbdt_TracerIoCtl(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData,
1769 uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
1770{
1771 AssertPtrReturn(uSessionData, VERR_INVALID_POINTER);
1772 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1773
1774 int rc = dtrace_ioctl((dtrace_state_t *)uSessionData, (intptr_t)uCmd, (intptr_t)uArg, piRetVal);
1775
1776 VBDT_CLEAR_STACK_DATA();
1777 return RTErrConvertFromErrno(rc);
1778}
1779
1780
1781/**
1782 * interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
1783 */
1784static DECLCALLBACK(void) vbdt_TracerClose(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData)
1785{
1786 AssertPtrReturnVoid(uSessionData);
1787 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1788
1789 dtrace_close((dtrace_state_t *)uSessionData);
1790
1791 VBDT_CLEAR_STACK_DATA();
1792}
1793
1794
1795/**
1796 * interface_method_impl{SUPDRVTRACERREG,pfnProviderRegister}
1797 */
1798static DECLCALLBACK(int) vbdt_ProviderRegister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
1799{
1800 AssertReturn(pCore->TracerData.DTrace.idProvider == 0, VERR_INTERNAL_ERROR_3);
1801 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1802
1803 PVTGDESCPROVIDER pDesc = pCore->pDesc;
1804 dtrace_pattr_t DtAttrs;
1805 vboxDtVtgConvAttr(&DtAttrs.dtpa_provider, &pDesc->AttrSelf);
1806 vboxDtVtgConvAttr(&DtAttrs.dtpa_mod, &pDesc->AttrModules);
1807 vboxDtVtgConvAttr(&DtAttrs.dtpa_func, &pDesc->AttrFunctions);
1808 vboxDtVtgConvAttr(&DtAttrs.dtpa_name, &pDesc->AttrNames);
1809 vboxDtVtgConvAttr(&DtAttrs.dtpa_args, &pDesc->AttrArguments);
1810
1811 AssertCompile(sizeof(dtrace_provider_id_t) == sizeof(pCore->TracerData.DTrace.idProvider));
1812 int rc = dtrace_register(pCore->pszName,
1813 &DtAttrs,
1814 DTRACE_PRIV_KERNEL,
1815 NULL /* cred */,
1816 &g_vboxDtVtgProvOps,
1817 pCore,
1818 &pCore->TracerData.DTrace.idProvider);
1819 if (!rc)
1820 {
1821 Assert(pCore->TracerData.DTrace.idProvider != 0);
1822 rc = VINF_SUCCESS;
1823 }
1824 else
1825 rc = RTErrConvertFromErrno(rc);
1826
1827 VBDT_CLEAR_STACK_DATA();
1828 return rc;
1829}
1830
1831
1832/**
1833 * interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregister}
1834 */
1835static DECLCALLBACK(int) vbdt_ProviderDeregister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
1836{
1837 uintptr_t idProvider = pCore->TracerData.DTrace.idProvider;
1838 AssertReturn(idProvider != 0, VERR_INTERNAL_ERROR_4);
1839 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1840
1841 dtrace_invalidate(idProvider);
1842 int rc = dtrace_unregister(idProvider);
1843 if (!rc)
1844 {
1845 pCore->TracerData.DTrace.idProvider = 0;
1846 rc = VINF_SUCCESS;
1847 }
1848 else
1849 {
1850 AssertMsg(rc == EBUSY, ("%d\n", rc));
1851 pCore->TracerData.DTrace.fZombie = true;
1852 rc = VERR_TRY_AGAIN;
1853 }
1854
1855 VBDT_CLEAR_STACK_DATA();
1856 return rc;
1857}
1858
1859
1860/**
1861 * interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregisterZombie}
1862 */
1863static DECLCALLBACK(int) vbdt_ProviderDeregisterZombie(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
1864{
1865 uintptr_t idProvider = pCore->TracerData.DTrace.idProvider;
1866 AssertReturn(idProvider != 0, VERR_INTERNAL_ERROR_4);
1867 Assert(pCore->TracerData.DTrace.fZombie);
1868 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1869
1870 int rc = dtrace_unregister(idProvider);
1871 if (!rc)
1872 {
1873 pCore->TracerData.DTrace.idProvider = 0;
1874 rc = VINF_SUCCESS;
1875 }
1876 else
1877 {
1878 AssertMsg(rc == EBUSY, ("%d\n", rc));
1879 rc = VERR_TRY_AGAIN;
1880 }
1881
1882 VBDT_CLEAR_STACK_DATA();
1883 return rc;
1884}
1885
1886
1887
1888/**
1889 * The tracer registration record of the VBox DTrace implementation
1890 */
1891static SUPDRVTRACERREG g_VBoxDTraceReg =
1892{
1893 SUPDRVTRACERREG_MAGIC,
1894 SUPDRVTRACERREG_VERSION,
1895 vbdt_ProbeFireKernel,
1896 vbdt_ProbeFireUser,
1897 vbdt_TracerOpen,
1898 vbdt_TracerIoCtl,
1899 vbdt_TracerClose,
1900 vbdt_ProviderRegister,
1901 vbdt_ProviderDeregister,
1902 vbdt_ProviderDeregisterZombie,
1903 SUPDRVTRACERREG_MAGIC
1904};
1905
1906
1907
1908/**
1909 * Module termination code.
1910 *
1911 * @param hMod Opque module handle.
1912 */
1913DECLEXPORT(void) ModuleTerm(void *hMod)
1914{
1915 SUPR0TracerDeregisterImpl(hMod, NULL);
1916 dtrace_detach();
1917}
1918
1919
1920/**
1921 * Module initialization code.
1922 *
1923 * @param hMod Opque module handle.
1924 */
1925DECLEXPORT(int) ModuleInit(void *hMod)
1926{
1927 int rc = dtrace_attach();
1928 if (rc == DDI_SUCCESS)
1929 {
1930 rc = SUPR0TracerRegisterImpl(hMod, NULL, &g_VBoxDTraceReg, &g_pVBoxDTraceHlp);
1931 if (RT_SUCCESS(rc))
1932 return rc;
1933
1934 dtrace_detach();
1935 }
1936 else
1937 {
1938 SUPR0Printf("dtrace_attach -> %d\n", rc);
1939 rc = VERR_INTERNAL_ERROR_5;
1940 }
1941
1942 return rc;
1943}
1944
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