VirtualBox

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

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

VBoxDTraceR0: NIL_RTSEMMUTEX == NULL (gcc6 complains)

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