VirtualBox

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

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

VBoxDTraceR0: Index the right array on x86 (thanks Parfait).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.8 KB
Line 
1/* $Id: VBoxDTraceR0.cpp 54050 2015-01-30 16:37: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 || pMtx->hMtx == NULL)
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 %s 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 }
1515 }
1516 else
1517 {
1518 /* Update kernel mode structure */
1519 if (!pProv->paR0ProbeLocs[idxProbeLoc].fEnabled)
1520 {
1521 pProv->paR0ProbeLocs[idxProbeLoc].fEnabled = 1;
1522 ASMAtomicIncU32(&pProv->paR0Probes[idxProbe].cEnabled);
1523 }
1524
1525 /* Update user mode structure. */
1526 pProbeLocEn->fEnabled = 1;
1527 pProv->pacProbeEnabled[idxProbe] = pProv->paR0Probes[idxProbe].cEnabled;
1528 }
1529 }
1530
1531 return 0;
1532}
1533
1534
1535/**
1536 * @callback_method_impl{dtrace_pops_t,dtps_disable}
1537 */
1538static void vboxDtPOps_Disable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
1539{
1540 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1541 AssertPtrReturnVoid(pProv);
1542 LOG_DTRACE(("%s: %p / %p - %#x / %p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
1543 AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
1544
1545 if (!pProv->TracerData.DTrace.fZombie)
1546 {
1547 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
1548 PVTGPROBELOC32 pProbeLocEn = (PVTGPROBELOC32)( (uintptr_t)pProv->pvProbeLocsEn + idxProbeLoc * pProv->cbProbeLocsEn);
1549 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
1550 PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
1551 uint32_t const idxProbe = pProbeDesc->idxEnabled;
1552
1553 if (!pProv->fUmod)
1554 {
1555 if (pProbeLocEn->fEnabled)
1556 {
1557 pProbeLocEn->fEnabled = 0;
1558 ASMAtomicDecU32(&pProv->pacProbeEnabled[idxProbe]);
1559 }
1560 }
1561 else
1562 {
1563 /* Update kernel mode structure */
1564 if (pProv->paR0ProbeLocs[idxProbeLoc].fEnabled)
1565 {
1566 pProv->paR0ProbeLocs[idxProbeLoc].fEnabled = 0;
1567 ASMAtomicDecU32(&pProv->paR0Probes[idxProbe].cEnabled);
1568 }
1569
1570 /* Update user mode structure. */
1571 pProbeLocEn->fEnabled = 0;
1572 pProv->pacProbeEnabled[idxProbe] = pProv->paR0Probes[idxProbe].cEnabled;
1573 }
1574 }
1575}
1576
1577
1578/**
1579 * @callback_method_impl{dtrace_pops_t,dtps_getargdesc}
1580 */
1581static void vboxDtPOps_GetArgDesc(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
1582 dtrace_argdesc_t *pArgDesc)
1583{
1584 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1585 unsigned uArg = pArgDesc->dtargd_ndx;
1586
1587 pArgDesc->dtargd_ndx = DTRACE_ARGNONE;
1588 AssertPtrReturnVoid(pProv);
1589 LOG_DTRACE(("%s: %p / %p - %#x / %p uArg=%d\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe, uArg));
1590 AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
1591
1592 if (!pProv->TracerData.DTrace.fZombie)
1593 {
1594 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
1595 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
1596 PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
1597 PCVTGDESCARGLIST pArgList = (PCVTGDESCARGLIST)( (uintptr_t)pProv->pHdr
1598 + pProv->pHdr->offArgLists
1599 + pProbeDesc->offArgList);
1600 AssertReturnVoid(pProbeDesc->offArgList < pProv->pHdr->cbArgLists);
1601
1602 if (uArg < pArgList->cArgs)
1603 {
1604 const char *pszType = vboxDtVtgGetString(pProv->pHdr, pArgList->aArgs[uArg].offType);
1605 size_t cchType = strlen(pszType);
1606 if (cchType < sizeof(pArgDesc->dtargd_native))
1607 {
1608 memcpy(pArgDesc->dtargd_native, pszType, cchType + 1);
1609 /** @todo mapping? */
1610 pArgDesc->dtargd_ndx = uArg;
1611 LOG_DTRACE(("%s: returns dtargd_native = %s\n", __FUNCTION__, pArgDesc->dtargd_native));
1612 return;
1613 }
1614 }
1615 }
1616}
1617
1618
1619/**
1620 * @callback_method_impl{dtrace_pops_t,dtps_getargval}
1621 */
1622static uint64_t vboxDtPOps_GetArgVal(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
1623 int iArg, int cFrames)
1624{
1625 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1626 AssertPtrReturn(pProv, UINT64_MAX);
1627 LOG_DTRACE(("%s: %p / %p - %#x / %p iArg=%d cFrames=%u\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe, iArg, cFrames));
1628 AssertReturn(iArg >= 5, UINT64_MAX);
1629 if (pProv->TracerData.DTrace.fZombie)
1630 return UINT64_MAX;
1631
1632 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
1633 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
1634 PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
1635 PCVTGDESCARGLIST pArgList = (PCVTGDESCARGLIST)( (uintptr_t)pProv->pHdr
1636 + pProv->pHdr->offArgLists
1637 + pProbeDesc->offArgList);
1638 AssertReturn(pProbeDesc->offArgList < pProv->pHdr->cbArgLists, UINT64_MAX);
1639
1640 PVBDTSTACKDATA pData = vboxDtGetStackData();
1641
1642 /*
1643 * Get the stack data. This is a wee bit complicated on 32-bit systems
1644 * since we want to support 64-bit integer arguments.
1645 */
1646 uint64_t u64Ret;
1647 if (iArg >= 20)
1648 u64Ret = UINT64_MAX;
1649 else if (pData->enmCaller == kVBoxDtCaller_ProbeFireKernel)
1650 {
1651#if ARCH_BITS == 64
1652 u64Ret = pData->u.ProbeFireKernel.pauStackArgs[iArg - 5];
1653#else
1654 if ( !pArgList->fHaveLargeArgs
1655 || iArg >= pArgList->cArgs)
1656 u64Ret = pData->u.ProbeFireKernel.pauStackArgs[iArg - 5];
1657 else
1658 {
1659 /* Similar to what we did for mac in when calling dtrace_probe(). */
1660 uint32_t offArg = 0;
1661 for (int i = 5; i < iArg; i++)
1662 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
1663 offArg++;
1664 u64Ret = pData->u.ProbeFireKernel.pauStackArgs[iArg - 5 + offArg];
1665 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
1666 u64Ret |= (uint64_t)pData->u.ProbeFireKernel.pauStackArgs[iArg - 5 + offArg + 1] << 32;
1667 }
1668#endif
1669 }
1670 else if (pData->enmCaller == kVBoxDtCaller_ProbeFireUser)
1671 {
1672 int offArg = pData->u.ProbeFireUser.offArg;
1673 PCSUPDRVTRACERUSRCTX pCtx = pData->u.ProbeFireUser.pCtx;
1674 AssertPtrReturn(pCtx, UINT64_MAX);
1675
1676 if (pCtx->cBits == 32)
1677 {
1678 if ( !pArgList->fHaveLargeArgs
1679 || iArg >= pArgList->cArgs)
1680 {
1681 if (iArg + offArg < (int)RT_ELEMENTS(pCtx->u.X86.aArgs))
1682 u64Ret = pCtx->u.X86.aArgs[iArg + offArg];
1683 else
1684 u64Ret = UINT64_MAX;
1685 }
1686 else
1687 {
1688 for (int i = 5; i < iArg; i++)
1689 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
1690 offArg++;
1691 if (offArg + iArg < (int)RT_ELEMENTS(pCtx->u.X86.aArgs))
1692 {
1693 u64Ret = pCtx->u.X86.aArgs[iArg + offArg];
1694 if ( VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType)
1695 && offArg + iArg + 1 < (int)RT_ELEMENTS(pCtx->u.X86.aArgs))
1696 u64Ret |= (uint64_t)pCtx->u.X86.aArgs[iArg + offArg + 1] << 32;
1697 }
1698 else
1699 u64Ret = UINT64_MAX;
1700 }
1701 }
1702 else
1703 {
1704 if (iArg + offArg < (int)RT_ELEMENTS(pCtx->u.Amd64.aArgs))
1705 u64Ret = pCtx->u.Amd64.aArgs[iArg + offArg];
1706 else
1707 u64Ret = UINT64_MAX;
1708 }
1709 }
1710 else
1711 AssertFailedReturn(UINT64_MAX);
1712
1713 LOG_DTRACE(("%s: returns %#llx\n", __FUNCTION__, u64Ret));
1714 return u64Ret;
1715}
1716
1717
1718/**
1719 * @callback_method_impl{dtrace_pops_t,dtps_destroy}
1720 */
1721static void vboxDtPOps_Destroy(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
1722{
1723 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1724 AssertPtrReturnVoid(pProv);
1725 LOG_DTRACE(("%s: %p / %p - %#x / %p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
1726 AssertReturnVoid(pProv->TracerData.DTrace.cProvidedProbes > 0);
1727 AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
1728
1729 if (!pProv->TracerData.DTrace.fZombie)
1730 {
1731 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
1732 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
1733 uint32_t *pidProbe;
1734 if (!pProv->fUmod)
1735 {
1736 pidProbe = (uint32_t *)&pProbeLocRO->idProbe;
1737 Assert(!pProbeLocRO->fEnabled);
1738 Assert(*pidProbe == idProbe);
1739 }
1740 else
1741 {
1742 pidProbe = &pProv->paR0ProbeLocs[idxProbeLoc].idProbe;
1743 Assert(!pProv->paR0ProbeLocs[idxProbeLoc].fEnabled);
1744 Assert(*pidProbe == idProbe); NOREF(idProbe);
1745 }
1746 *pidProbe = 0;
1747 }
1748 pProv->TracerData.DTrace.cProvidedProbes--;
1749}
1750
1751
1752
1753/**
1754 * DTrace provider method table.
1755 */
1756static const dtrace_pops_t g_vboxDtVtgProvOps =
1757{
1758 /* .dtps_provide = */ vboxDtPOps_Provide,
1759 /* .dtps_provide_module = */ NULL,
1760 /* .dtps_enable = */ vboxDtPOps_Enable,
1761 /* .dtps_disable = */ vboxDtPOps_Disable,
1762 /* .dtps_suspend = */ NULL,
1763 /* .dtps_resume = */ NULL,
1764 /* .dtps_getargdesc = */ vboxDtPOps_GetArgDesc,
1765 /* .dtps_getargval = */ vboxDtPOps_GetArgVal,
1766 /* .dtps_usermode = */ NULL,
1767 /* .dtps_destroy = */ vboxDtPOps_Destroy
1768};
1769
1770
1771
1772
1773/*
1774 *
1775 * Support Driver Tracer Interface.
1776 * Support Driver Tracer Interface.
1777 * Support Driver Tracer Interface.
1778 *
1779 */
1780
1781
1782
1783/**
1784 * interface_method_impl{SUPDRVTRACERREG,pfnProbeFireKernel}
1785 */
1786static DECLCALLBACK(void) vboxDtTOps_ProbeFireKernel(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2,
1787 uintptr_t uArg3, uintptr_t uArg4)
1788{
1789 AssertPtrReturnVoid(pVtgProbeLoc);
1790 LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pVtgProbeLoc, pVtgProbeLoc->idProbe));
1791 AssertPtrReturnVoid(pVtgProbeLoc->pProbe);
1792 AssertPtrReturnVoid(pVtgProbeLoc->pszFunction);
1793
1794 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_ProbeFireKernel);
1795
1796 pStackData->u.ProbeFireKernel.pauStackArgs = &uArg4 + 1;
1797
1798#if defined(RT_OS_DARWIN) && ARCH_BITS == 32
1799 /*
1800 * Convert arguments from uintptr_t to uint64_t.
1801 */
1802 PVTGDESCPROBE pProbe = pVtgProbeLoc->pProbe;
1803 AssertPtrReturnVoid(pProbe);
1804 PVTGOBJHDR pVtgHdr = (PVTGOBJHDR)((uintptr_t)pProbe + pProbe->offObjHdr);
1805 AssertPtrReturnVoid(pVtgHdr);
1806 PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbe->offArgList);
1807 AssertPtrReturnVoid(pArgList);
1808 if (!pArgList->fHaveLargeArgs)
1809 dtrace_probe(pVtgProbeLoc->idProbe, uArg0, uArg1, uArg2, uArg3, uArg4);
1810 else
1811 {
1812 uintptr_t *auSrcArgs = &uArg0;
1813 uint32_t iSrcArg = 0;
1814 uint32_t iDstArg = 0;
1815 uint64_t au64DstArgs[5];
1816
1817 while ( iDstArg < RT_ELEMENTS(au64DstArgs)
1818 && iSrcArg < pArgList->cArgs)
1819 {
1820 au64DstArgs[iDstArg] = auSrcArgs[iSrcArg];
1821 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iDstArg].fType))
1822 au64DstArgs[iDstArg] |= (uint64_t)auSrcArgs[++iSrcArg] << 32;
1823 iSrcArg++;
1824 iDstArg++;
1825 }
1826 while (iDstArg < RT_ELEMENTS(au64DstArgs))
1827 au64DstArgs[iDstArg++] = auSrcArgs[iSrcArg++];
1828
1829 pStackData->u.ProbeFireKernel.pauStackArgs = &auSrcArgs[iSrcArg];
1830 dtrace_probe(pVtgProbeLoc->idProbe, au64DstArgs[0], au64DstArgs[1], au64DstArgs[2], au64DstArgs[3], au64DstArgs[4]);
1831 }
1832#else
1833 dtrace_probe(pVtgProbeLoc->idProbe, uArg0, uArg1, uArg2, uArg3, uArg4);
1834#endif
1835
1836 VBDT_CLEAR_STACK_DATA();
1837 LOG_DTRACE(("%s: returns\n", __FUNCTION__));
1838}
1839
1840
1841/**
1842 * interface_method_impl{SUPDRVTRACERREG,pfnProbeFireUser}
1843 */
1844static DECLCALLBACK(void) vboxDtTOps_ProbeFireUser(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, PCSUPDRVTRACERUSRCTX pCtx,
1845 PCVTGOBJHDR pVtgHdr, PCVTGPROBELOC pProbeLocRO)
1846{
1847 LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pCtx, pCtx->idProbe));
1848 AssertPtrReturnVoid(pProbeLocRO);
1849 AssertPtrReturnVoid(pVtgHdr);
1850
1851 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_ProbeFireUser);
1852
1853 if (pCtx->cBits == 32)
1854 {
1855 pStackData->u.ProbeFireUser.pCtx = pCtx;
1856 pStackData->u.ProbeFireUser.offArg = 0;
1857
1858#if ARCH_BITS == 64 || defined(RT_OS_DARWIN)
1859 /*
1860 * Combine two 32-bit arguments into one 64-bit argument where needed.
1861 */
1862 PVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
1863 AssertPtrReturnVoid(pProbeDesc);
1864 PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbeDesc->offArgList);
1865 AssertPtrReturnVoid(pArgList);
1866
1867 if (!pArgList->fHaveLargeArgs)
1868 dtrace_probe(pCtx->idProbe,
1869 pCtx->u.X86.aArgs[0],
1870 pCtx->u.X86.aArgs[1],
1871 pCtx->u.X86.aArgs[2],
1872 pCtx->u.X86.aArgs[3],
1873 pCtx->u.X86.aArgs[4]);
1874 else
1875 {
1876 uint32_t const *auSrcArgs = &pCtx->u.X86.aArgs[0];
1877 uint32_t iSrcArg = 0;
1878 uint32_t iDstArg = 0;
1879 uint64_t au64DstArgs[5];
1880
1881 while ( iDstArg < RT_ELEMENTS(au64DstArgs)
1882 && iSrcArg < pArgList->cArgs)
1883 {
1884 au64DstArgs[iDstArg] = auSrcArgs[iSrcArg];
1885 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iDstArg].fType))
1886 au64DstArgs[iDstArg] |= (uint64_t)auSrcArgs[++iSrcArg] << 32;
1887 iSrcArg++;
1888 iDstArg++;
1889 }
1890 while (iDstArg < RT_ELEMENTS(au64DstArgs))
1891 au64DstArgs[iDstArg++] = auSrcArgs[iSrcArg++];
1892
1893 pStackData->u.ProbeFireUser.offArg = iSrcArg - RT_ELEMENTS(au64DstArgs);
1894 dtrace_probe(pCtx->idProbe, au64DstArgs[0], au64DstArgs[1], au64DstArgs[2], au64DstArgs[3], au64DstArgs[4]);
1895 }
1896#else
1897 dtrace_probe(pCtx->idProbe,
1898 pCtx->u.X86.aArgs[0],
1899 pCtx->u.X86.aArgs[1],
1900 pCtx->u.X86.aArgs[2],
1901 pCtx->u.X86.aArgs[3],
1902 pCtx->u.X86.aArgs[4]);
1903#endif
1904 }
1905 else if (pCtx->cBits == 64)
1906 {
1907 pStackData->u.ProbeFireUser.pCtx = pCtx;
1908 pStackData->u.ProbeFireUser.offArg = 0;
1909 dtrace_probe(pCtx->idProbe,
1910 pCtx->u.Amd64.aArgs[0],
1911 pCtx->u.Amd64.aArgs[1],
1912 pCtx->u.Amd64.aArgs[2],
1913 pCtx->u.Amd64.aArgs[3],
1914 pCtx->u.Amd64.aArgs[4]);
1915 }
1916 else
1917 AssertFailed();
1918
1919 VBDT_CLEAR_STACK_DATA();
1920 LOG_DTRACE(("%s: returns\n", __FUNCTION__));
1921}
1922
1923
1924/**
1925 * interface_method_impl{SUPDRVTRACERREG,pfnTracerOpen}
1926 */
1927static DECLCALLBACK(int) vboxDtTOps_TracerOpen(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uint32_t uCookie,
1928 uintptr_t uArg, uintptr_t *puSessionData)
1929{
1930 if (uCookie != RT_MAKE_U32_FROM_U8('V', 'B', 'D', 'T'))
1931 return VERR_INVALID_MAGIC;
1932 if (uArg)
1933 return VERR_INVALID_PARAMETER;
1934
1935 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1936
1937 int rc = dtrace_open((dtrace_state_t **)puSessionData, VBoxDtGetCurrentCreds());
1938
1939 VBDT_CLEAR_STACK_DATA();
1940 return RTErrConvertFromErrno(rc);
1941}
1942
1943
1944/**
1945 * interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
1946 */
1947static DECLCALLBACK(int) vboxDtTOps_TracerIoCtl(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData,
1948 uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
1949{
1950 AssertPtrReturn(uSessionData, VERR_INVALID_POINTER);
1951 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1952
1953 int rc = dtrace_ioctl((dtrace_state_t *)uSessionData, (intptr_t)uCmd, (intptr_t)uArg, piRetVal);
1954
1955 VBDT_CLEAR_STACK_DATA();
1956 return RTErrConvertFromErrno(rc);
1957}
1958
1959
1960/**
1961 * interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
1962 */
1963static DECLCALLBACK(void) vboxDtTOps_TracerClose(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData)
1964{
1965 AssertPtrReturnVoid(uSessionData);
1966 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1967
1968 dtrace_close((dtrace_state_t *)uSessionData);
1969
1970 VBDT_CLEAR_STACK_DATA();
1971}
1972
1973
1974/**
1975 * interface_method_impl{SUPDRVTRACERREG,pfnProviderRegister}
1976 */
1977static DECLCALLBACK(int) vboxDtTOps_ProviderRegister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
1978{
1979 LOG_DTRACE(("%s: %p %s/%s\n", __FUNCTION__, pThis, pCore->pszModName, pCore->pszName));
1980 AssertReturn(pCore->TracerData.DTrace.idProvider == 0, VERR_INTERNAL_ERROR_3);
1981 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1982
1983 PVTGDESCPROVIDER pDesc = pCore->pDesc;
1984 dtrace_pattr_t DtAttrs;
1985 vboxDtVtgConvAttr(&DtAttrs.dtpa_provider, &pDesc->AttrSelf);
1986 vboxDtVtgConvAttr(&DtAttrs.dtpa_mod, &pDesc->AttrModules);
1987 vboxDtVtgConvAttr(&DtAttrs.dtpa_func, &pDesc->AttrFunctions);
1988 vboxDtVtgConvAttr(&DtAttrs.dtpa_name, &pDesc->AttrNames);
1989 vboxDtVtgConvAttr(&DtAttrs.dtpa_args, &pDesc->AttrArguments);
1990
1991 /* Note! DTrace may call us back before dtrace_register returns, so we
1992 have to point it to pCore->TracerData.DTrace.idProvider. */
1993 AssertCompile(sizeof(dtrace_provider_id_t) == sizeof(pCore->TracerData.DTrace.idProvider));
1994 int rc = dtrace_register(pCore->pszName,
1995 &DtAttrs,
1996 DTRACE_PRIV_KERNEL,
1997 NULL /* cred */,
1998 &g_vboxDtVtgProvOps,
1999 pCore,
2000 &pCore->TracerData.DTrace.idProvider);
2001 if (!rc)
2002 {
2003 LOG_DTRACE(("%s: idProvider=%p\n", __FUNCTION__, pCore->TracerData.DTrace.idProvider));
2004 AssertPtr(pCore->TracerData.DTrace.idProvider);
2005 rc = VINF_SUCCESS;
2006 }
2007 else
2008 {
2009 pCore->TracerData.DTrace.idProvider = 0;
2010 rc = RTErrConvertFromErrno(rc);
2011 }
2012
2013 VBDT_CLEAR_STACK_DATA();
2014 LOG_DTRACE(("%s: returns %Rrc\n", __FUNCTION__, rc));
2015 return rc;
2016}
2017
2018
2019/**
2020 * interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregister}
2021 */
2022static DECLCALLBACK(int) vboxDtTOps_ProviderDeregister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
2023{
2024 uintptr_t idProvider = pCore->TracerData.DTrace.idProvider;
2025 LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pThis, idProvider));
2026 AssertPtrReturn(idProvider, VERR_INTERNAL_ERROR_3);
2027 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
2028
2029 dtrace_invalidate(idProvider);
2030 int rc = dtrace_unregister(idProvider);
2031 if (!rc)
2032 {
2033 pCore->TracerData.DTrace.idProvider = 0;
2034 rc = VINF_SUCCESS;
2035 }
2036 else
2037 {
2038 AssertMsg(rc == EBUSY, ("%d\n", rc));
2039 pCore->TracerData.DTrace.fZombie = true;
2040 rc = VERR_TRY_AGAIN;
2041 }
2042
2043 VBDT_CLEAR_STACK_DATA();
2044 LOG_DTRACE(("%s: returns %Rrc\n", __FUNCTION__, rc));
2045 return rc;
2046}
2047
2048
2049/**
2050 * interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregisterZombie}
2051 */
2052static DECLCALLBACK(int) vboxDtTOps_ProviderDeregisterZombie(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
2053{
2054 uintptr_t idProvider = pCore->TracerData.DTrace.idProvider;
2055 LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pThis, idProvider));
2056 AssertPtrReturn(idProvider, VERR_INTERNAL_ERROR_3);
2057 Assert(pCore->TracerData.DTrace.fZombie);
2058 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
2059
2060 int rc = dtrace_unregister(idProvider);
2061 if (!rc)
2062 {
2063 pCore->TracerData.DTrace.idProvider = 0;
2064 rc = VINF_SUCCESS;
2065 }
2066 else
2067 {
2068 AssertMsg(rc == EBUSY, ("%d\n", rc));
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/**
2080 * The tracer registration record of the VBox DTrace implementation
2081 */
2082static SUPDRVTRACERREG g_VBoxDTraceReg =
2083{
2084 SUPDRVTRACERREG_MAGIC,
2085 SUPDRVTRACERREG_VERSION,
2086 vboxDtTOps_ProbeFireKernel,
2087 vboxDtTOps_ProbeFireUser,
2088 vboxDtTOps_TracerOpen,
2089 vboxDtTOps_TracerIoCtl,
2090 vboxDtTOps_TracerClose,
2091 vboxDtTOps_ProviderRegister,
2092 vboxDtTOps_ProviderDeregister,
2093 vboxDtTOps_ProviderDeregisterZombie,
2094 SUPDRVTRACERREG_MAGIC
2095};
2096
2097
2098
2099/**
2100 * Module termination code.
2101 *
2102 * @param hMod Opque module handle.
2103 */
2104DECLEXPORT(void) ModuleTerm(void *hMod)
2105{
2106 SUPR0TracerDeregisterImpl(hMod, NULL);
2107 dtrace_detach();
2108}
2109
2110
2111/**
2112 * Module initialization code.
2113 *
2114 * @param hMod Opque module handle.
2115 */
2116DECLEXPORT(int) ModuleInit(void *hMod)
2117{
2118 int rc = dtrace_attach();
2119 if (rc == DDI_SUCCESS)
2120 {
2121 rc = SUPR0TracerRegisterImpl(hMod, NULL, &g_VBoxDTraceReg, &g_pVBoxDTraceHlp);
2122 if (RT_SUCCESS(rc))
2123 return rc;
2124
2125 dtrace_detach();
2126 }
2127 else
2128 {
2129 SUPR0Printf("dtrace_attach -> %d\n", rc);
2130 rc = VERR_INTERNAL_ERROR_5;
2131 }
2132
2133 return rc;
2134}
2135
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