VirtualBox

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

Last change on this file since 93963 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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