VirtualBox

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

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

VBoxDTrace: implemented a bunch of glue and reduced the required solaris glue. (r44)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.1 KB
Line 
1/* $Id: VBoxDTraceR0.cpp 53667 2015-01-02 12:32:53Z vboxsync $ */
2/** @file
3 * VBoxDTraceR0.
4 */
5
6/*
7 * Copyright (c) 2012 bird
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <VBox/sup.h>
36#include <VBox/log.h>
37
38#include <iprt/asm-amd64-x86.h>
39#include <iprt/assert.h>
40#include <iprt/ctype.h>
41#include <iprt/err.h>
42#include <iprt/mem.h>
43#include <iprt/mp.h>
44#include <iprt/spinlock.h>
45#include <iprt/string.h>
46#include <iprt/time.h>
47
48#include <sys/dtrace_impl.h>
49
50#include <VBox/VBoxTpG.h>
51
52
53
54/*******************************************************************************
55* Structures and Typedefs *
56*******************************************************************************/
57struct VBoxDtDevInfo
58{
59 /** The major device cdoe. */
60 RTDEV uMajor;
61};
62
63
64/** Caller indicator. */
65typedef enum VBOXDTCALLER
66{
67 kVBoxDtCaller_Invalid = 0,
68 kVBoxDtCaller_Generic,
69 kVBoxDtCaller_ProbeFireUser,
70 kVBoxDtCaller_ProbeFireKernel
71} VBOXDTCALLER;
72
73/**
74 * Stack data used for thread structure and such.
75 *
76 * This is planted in every external entry point and used to emulate solaris
77 * curthread, CRED, curproc and similar. It is also used to get at the
78 * uncached probe arguments.
79 */
80typedef struct VBoxDtStackData
81{
82 /** Eyecatcher no. 1 (VBDT_STACK_DATA_MAGIC2). */
83 uint32_t u32Magic1;
84 /** Eyecatcher no. 2 (VBDT_STACK_DATA_MAGIC2). */
85 uint32_t u32Magic2;
86 /** The format of the caller specific data. */
87 VBOXDTCALLER enmCaller;
88 /** Caller specific data. */
89 union
90 {
91 /** kVBoxDtCaller_ProbeFireKernel. */
92 struct
93 {
94 /** The caller. */
95 uintptr_t uCaller;
96 /** Pointer to the stack arguments of a probe function call. */
97 uintptr_t *pauStackArgs;
98 } ProbeFireKernel;
99 /** kVBoxDtCaller_ProbeFireUser. */
100 struct
101 {
102 /** The user context. */
103 PCSUPDRVTRACERUSRCTX pCtx;
104 } ProbeFireUser;
105 } u;
106 /** Credentials allocated by VBoxDtGetCurrentCreds. */
107 struct VBoxDtCred *pCred;
108 /** Pointer to this structure.
109 * This is the final bit of integrity checking. */
110 struct VBoxDtStackData *pSelf;
111} VBDTSTACKDATA;
112/** Pointer to the on-stack thread specific data. */
113typedef VBDTSTACKDATA *PVBDTSTACKDATA;
114
115/** The first magic value. */
116#define VBDT_STACK_DATA_MAGIC1 RT_MAKE_U32_FROM_U8('V', 'B', 'o', 'x')
117/** The second magic value. */
118#define VBDT_STACK_DATA_MAGIC2 RT_MAKE_U32_FROM_U8('D', 'T', 'r', 'c')
119
120/** The alignment of the stack data.
121 * The data doesn't require more than sizeof(uintptr_t) alignment, but the
122 * greater alignment the quicker lookup. */
123#define VBDT_STACK_DATA_ALIGN 32
124
125/** Plants the stack data. */
126#define VBDT_SETUP_STACK_DATA(a_enmCaller) \
127 uint8_t abBlob[sizeof(VBoxDtStackData) + VBDT_STACK_DATA_ALIGN - 1]; \
128 PVBDTSTACKDATA pStackData = (PVBDTSTACKDATA)( (uintptr_t)&abBlob[VBDT_STACK_DATA_ALIGN - 1] \
129 & ~(uintptr_t)(VBDT_STACK_DATA_ALIGN - 1)); \
130 pStackData->u32Magic1 = VBDT_STACK_DATA_MAGIC1; \
131 pStackData->u32Magic2 = VBDT_STACK_DATA_MAGIC2; \
132 pStackData->enmCaller = a_enmCaller; \
133 pStackData->pCred = 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 } while (0)
146
147
148/*******************************************************************************
149* Global Variables *
150*******************************************************************************/
151/** Per CPU information */
152cpucore_t g_aVBoxDtCpuCores[RTCPUSET_MAX_CPUS];
153/** Dummy mutex. */
154struct VBoxDtMutex g_DummyMtx;
155/** Fake dtrace device info. */
156static struct VBoxDtDevInfo g_DevInfo =
157{
158 /* .uMajor = */ 127
159};
160
161void (*dtrace_cpu_init)(processorid_t);
162void (*dtrace_modload)(struct modctl *);
163void (*dtrace_modunload)(struct modctl *);
164void (*dtrace_helpers_cleanup)(void);
165void (*dtrace_helpers_fork)(proc_t *, proc_t *);
166void (*dtrace_cpustart_init)(void);
167void (*dtrace_cpustart_fini)(void);
168void (*dtrace_cpc_fire)(uint64_t);
169void (*dtrace_debugger_init)(void);
170void (*dtrace_debugger_fini)(void);
171dtrace_cacheid_t dtrace_predcache_id = DTRACE_CACHEIDNONE + 1;
172
173
174/**
175 * Gets the stack data.
176 *
177 * @returns Pointer to the stack data. Never NULL.
178 */
179static PVBDTSTACKDATA vboxDtGetStackData(void)
180{
181 int volatile iDummy = 1; /* use this to get the stack address. */
182 PVBDTSTACKDATA pData = (PVBDTSTACKDATA)( ((uintptr_t)&iDummy + VBDT_STACK_DATA_ALIGN - 1)
183 & ~(uintptr_t)(VBDT_STACK_DATA_ALIGN - 1));
184 for (;;)
185 {
186 if ( pData->u32Magic1 == VBDT_STACK_DATA_MAGIC1
187 && pData->u32Magic2 == VBDT_STACK_DATA_MAGIC2
188 && pData->pSelf == pData)
189 return pData;
190 pData = (PVBDTSTACKDATA)((uintptr_t)pData + VBDT_STACK_DATA_ALIGN);
191 }
192}
193
194
195void dtrace_toxic_ranges(void (*pfnAddOne)(uintptr_t uBase, uintptr_t cbRange))
196{
197 /** @todo ? */
198}
199
200
201
202/**
203 * Dummy callback used by dtrace_sync.
204 */
205static DECLCALLBACK(void) vboxDtSyncCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
206{
207 NOREF(idCpu); NOREF(pvUser1); NOREF(pvUser2);
208}
209
210
211/**
212 * Synchronzie across all CPUs (expensive).
213 */
214void dtrace_sync(void)
215{
216 int rc = RTMpOnAll(vboxDtSyncCallback, NULL, NULL);
217 AssertRC(rc);
218}
219
220
221/**
222 * Fetch a 8-bit "word" from userland.
223 *
224 * @return The byte value.
225 * @param pvUserAddr The userland address.
226 */
227uint8_t dtrace_fuword8( void *pvUserAddr)
228{
229 uint8_t u8;
230 int rc = RTR0MemUserCopyFrom(&u8, (uintptr_t)pvUserAddr, sizeof(u8));
231 if (RT_FAILURE(rc))
232 {
233 RTCPUID iCpu = VBDT_GET_CPUID();
234 cpu_core[iCpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
235 cpu_core[iCpu].cpuc_dtrace_illval = (uintptr_t)pvUserAddr;
236 u8 = 0;
237 }
238 return u8;
239}
240
241
242/**
243 * Fetch a 16-bit word from userland.
244 *
245 * @return The word value.
246 * @param pvUserAddr The userland address.
247 */
248uint16_t dtrace_fuword16(void *pvUserAddr)
249{
250 uint16_t u16;
251 int rc = RTR0MemUserCopyFrom(&u16, (uintptr_t)pvUserAddr, sizeof(u16));
252 if (RT_FAILURE(rc))
253 {
254 RTCPUID iCpu = VBDT_GET_CPUID();
255 cpu_core[iCpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
256 cpu_core[iCpu].cpuc_dtrace_illval = (uintptr_t)pvUserAddr;
257 u16 = 0;
258 }
259 return u16;
260}
261
262
263/**
264 * Fetch a 32-bit word from userland.
265 *
266 * @return The dword value.
267 * @param pvUserAddr The userland address.
268 */
269uint32_t dtrace_fuword32(void *pvUserAddr)
270{
271 uint32_t u32;
272 int rc = RTR0MemUserCopyFrom(&u32, (uintptr_t)pvUserAddr, sizeof(u32));
273 if (RT_FAILURE(rc))
274 {
275 RTCPUID iCpu = VBDT_GET_CPUID();
276 cpu_core[iCpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
277 cpu_core[iCpu].cpuc_dtrace_illval = (uintptr_t)pvUserAddr;
278 u32 = 0;
279 }
280 return u32;
281}
282
283
284/**
285 * Fetch a 64-bit word from userland.
286 *
287 * @return The qword value.
288 * @param pvUserAddr The userland address.
289 */
290uint64_t dtrace_fuword64(void *pvUserAddr)
291{
292 uint64_t u64;
293 int rc = RTR0MemUserCopyFrom(&u64, (uintptr_t)pvUserAddr, sizeof(u64));
294 if (RT_FAILURE(rc))
295 {
296 RTCPUID iCpu = VBDT_GET_CPUID();
297 cpu_core[iCpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
298 cpu_core[iCpu].cpuc_dtrace_illval = (uintptr_t)pvUserAddr;
299 u64 = 0;
300 }
301 return u64;
302}
303
304
305/** copyin implementation */
306int VBoxDtCopyIn(void const *pvUser, void *pvDst, size_t cb)
307{
308 int rc = RTR0MemUserCopyFrom(pvDst, (uintptr_t)pvUser, cb);
309 return RT_SUCCESS(rc) ? 0 : -1;
310}
311
312
313/** copyout implementation */
314int VBoxDtCopyOut(void const *pvSrc, void *pvUser, size_t cb)
315{
316 int rc = RTR0MemUserCopyTo((uintptr_t)pvUser, pvSrc, cb);
317 return RT_SUCCESS(rc) ? 0 : -1;
318}
319
320
321/**
322 * Copy data from userland into the kernel.
323 *
324 * @param uUserAddr The userland address.
325 * @param uKrnlAddr The kernel buffer address.
326 * @param cb The number of bytes to copy.
327 * @param pfFlags Pointer to the relevant cpuc_dtrace_flags.
328 */
329void dtrace_copyin( uintptr_t uUserAddr, uintptr_t uKrnlAddr, size_t cb, volatile uint16_t *pfFlags)
330{
331 int rc = RTR0MemUserCopyFrom((void *)uKrnlAddr, uUserAddr, cb);
332 if (RT_FAILURE(rc))
333 {
334 *pfFlags |= CPU_DTRACE_BADADDR;
335 cpu_core[VBDT_GET_CPUID()].cpuc_dtrace_illval = uUserAddr;
336 }
337}
338
339
340/**
341 * Copy data from the kernel into userlad.
342 *
343 * @param uKrnlAddr The kernel buffer address.
344 * @param uUserAddr The userland address.
345 * @param cb The number of bytes to copy.
346 * @param pfFlags Pointer to the relevant cpuc_dtrace_flags.
347 */
348void dtrace_copyout( uintptr_t uKrnlAddr, uintptr_t uUserAddr, size_t cb, volatile uint16_t *pfFlags)
349{
350 int rc = RTR0MemUserCopyTo(uUserAddr, (void const *)uKrnlAddr, cb);
351 if (RT_FAILURE(rc))
352 {
353 *pfFlags |= CPU_DTRACE_BADADDR;
354 cpu_core[VBDT_GET_CPUID()].cpuc_dtrace_illval = uUserAddr;
355 }
356}
357
358
359/**
360 * Copy a string from userland into the kernel.
361 *
362 * @param uUserAddr The userland address.
363 * @param uKrnlAddr The kernel buffer address.
364 * @param cbMax The maximum number of bytes to copy. May stop
365 * earlier if zero byte is encountered.
366 * @param pfFlags Pointer to the relevant cpuc_dtrace_flags.
367 */
368void dtrace_copyinstr( uintptr_t uUserAddr, uintptr_t uKrnlAddr, size_t cbMax, volatile uint16_t *pfFlags)
369{
370 if (!cbMax)
371 return;
372
373 char *pszDst = (char *)uKrnlAddr;
374 int rc = RTR0MemUserCopyFrom(pszDst, uUserAddr, cbMax);
375 if (RT_FAILURE(rc))
376 {
377 /* Byte by byte - lazy bird! */
378 size_t off = 0;
379 while (off < cbMax)
380 {
381 rc = RTR0MemUserCopyFrom(&pszDst[off], uUserAddr + off, 1);
382 if (RT_FAILURE(rc))
383 {
384 *pfFlags |= CPU_DTRACE_BADADDR;
385 cpu_core[VBDT_GET_CPUID()].cpuc_dtrace_illval = uUserAddr;
386 pszDst[off] = '\0';
387 return;
388 }
389 if (!pszDst[off])
390 return;
391 off++;
392 }
393 }
394
395 pszDst[cbMax - 1] = '\0';
396}
397
398
399/**
400 * Copy a string from the kernel and into user land.
401 *
402 * @param uKrnlAddr The kernel string address.
403 * @param uUserAddr The userland address.
404 * @param cbMax The maximum number of bytes to copy. Will stop
405 * earlier if zero byte is encountered.
406 * @param pfFlags Pointer to the relevant cpuc_dtrace_flags.
407 */
408void dtrace_copyoutstr(uintptr_t uKrnlAddr, uintptr_t uUserAddr, size_t cbMax, volatile uint16_t *pfFlags)
409{
410 const char *pszSrc = (const char *)uKrnlAddr;
411 size_t cbActual = RTStrNLen(pszSrc, cbMax);
412 cbActual += cbActual < cbMax;
413 dtrace_copyout(uKrnlAddr,uUserAddr, cbActual, pfFlags);
414}
415
416
417/**
418 * Get the caller @a cCallFrames call frames up the stack.
419 *
420 * @returns The caller's return address or ~(uintptr_t)0.
421 * @param cCallFrames The number of frames.
422 */
423uintptr_t dtrace_caller(int cCallFrames)
424{
425 PVBDTSTACKDATA pData = vboxDtGetStackData();
426 if (pData->enmCaller == kVBoxDtCaller_ProbeFireKernel)
427 return pData->u.ProbeFireKernel.uCaller;
428 return ~(uintptr_t)0;
429}
430
431
432/**
433 * Get argument number @a iArg @a cCallFrames call frames up the stack.
434 *
435 * @returns The caller's return address or ~(uintptr_t)0.
436 * @param iArg The argument to get.
437 * @param cCallFrames The number of frames.
438 */
439uint64_t dtrace_getarg(int iArg, int cCallFrames)
440{
441 PVBDTSTACKDATA pData = vboxDtGetStackData();
442 AssertReturn(iArg >= 5, UINT64_MAX);
443
444 if (pData->enmCaller == kVBoxDtCaller_ProbeFireKernel)
445 return pData->u.ProbeFireKernel.pauStackArgs[iArg - 5];
446 return UINT64_MAX;
447}
448
449
450/**
451 * Produce a traceback of the kernel stack.
452 *
453 * @param paPcStack Where to return the program counters.
454 * @param cMaxFrames The maximum number of PCs to return.
455 * @param cSkipFrames The number of artificial callstack frames to
456 * skip at the top.
457 * @param pIntr Not sure what this is...
458 */
459void dtrace_getpcstack(pc_t *paPcStack, int cMaxFrames, int cSkipFrames, uint32_t *pIntr)
460{
461 int iFrame = 0;
462 while (iFrame < cMaxFrames)
463 {
464 paPcStack[iFrame] = NULL;
465 iFrame++;
466 }
467}
468
469
470/**
471 * Get the number of call frames on the stack.
472 *
473 * @returns The stack depth.
474 * @param cSkipFrames The number of artificial callstack frames to
475 * skip at the top.
476 */
477int dtrace_getstackdepth(int cSkipFrames)
478{
479 return 1;
480}
481
482
483/**
484 * Produce a traceback of the userland stack.
485 *
486 * @param paPcStack Where to return the program counters.
487 * @param paFpStack Where to return the frame pointers.
488 * @param cMaxFrames The maximum number of frames to return.
489 */
490void dtrace_getufpstack(uint64_t *paPcStack, uint64_t *paFpStack, int cMaxFrames)
491{
492 int iFrame = 0;
493 while (iFrame < cMaxFrames)
494 {
495 paPcStack[iFrame] = 0;
496 paFpStack[iFrame] = 0;
497 iFrame++;
498 }
499}
500
501
502/**
503 * Produce a traceback of the userland stack.
504 *
505 * @param paPcStack Where to return the program counters.
506 * @param cMaxFrames The maximum number of frames to return.
507 */
508void dtrace_getupcstack(uint64_t *paPcStack, int cMaxFrames)
509{
510 int iFrame = 0;
511 while (iFrame < cMaxFrames)
512 {
513 paPcStack[iFrame] = 0;
514 iFrame++;
515 }
516}
517
518
519/**
520 * Computes the depth of the userland stack.
521 */
522int dtrace_getustackdepth(void)
523{
524 return 0;
525}
526
527
528/**
529 * Get the current IPL/IRQL.
530 *
531 * @returns Current level.
532 */
533int dtrace_getipl(void)
534{
535#ifdef RT_ARCH_AMD64
536 /* CR8 is normally the same as IRQL / IPL on AMD64. */
537 return ASMGetCR8();
538#else
539 /* Just fake it on x86. */
540 return !ASMIntAreEnabled();
541#endif
542}
543
544
545/**
546 * Get current monotonic timestamp.
547 *
548 * @returns Timestamp, nano seconds.
549 */
550hrtime_t dtrace_gethrtime(void)
551{
552 return RTTimeNanoTS();
553}
554
555
556/**
557 * Get current walltime.
558 *
559 * @returns Timestamp, nano seconds.
560 */
561hrtime_t dtrace_gethrestime(void)
562{
563 /** @todo try get better resolution here somehow ... */
564 RTTIMESPEC Now;
565 return RTTimeSpecGetNano(RTTimeNow(&Now));
566}
567
568
569/**
570 * DTrace panic routine.
571 *
572 * @param pszFormat Panic message.
573 * @param va Arguments to the panic message.
574 */
575void dtrace_vpanic(const char *pszFormat, va_list va)
576{
577 RTAssertMsg1(NULL, __LINE__, __FILE__, __FUNCTION__);
578 RTAssertMsg2WeakV(pszFormat, va);
579 RTR0AssertPanicSystem();
580 for (;;)
581 {
582 ASMBreakpoint();
583 volatile char *pchCrash = (volatile char *)~(uintptr_t)0;
584 *pchCrash = '\0';
585 }
586}
587
588
589/**
590 * DTrace panic routine.
591 *
592 * @param pszFormat Panic message.
593 * @param ... Arguments to the panic message.
594 */
595void VBoxDtPanic(const char *pszFormat, ...)
596{
597 va_list va;
598 va_start(va, pszFormat);
599 dtrace_vpanic(pszFormat, va);
600 va_end(va);
601}
602
603
604/**
605 * DTrace kernel message routine.
606 *
607 * @param pszFormat Kernel message.
608 * @param ... Arguments to the panic message.
609 */
610void VBoxDtCmnErr(int iLevel, const char *pszFormat, ...)
611{
612 va_list va;
613 va_start(va, pszFormat);
614 SUPR0Printf("%N", pszFormat, va);
615 va_end(va);
616}
617
618
619/** uprintf implementation */
620void VBoxDtUPrintf(const char *pszFormat, ...)
621{
622 va_list va;
623 va_start(va, pszFormat);
624 VBoxDtUPrintfV(pszFormat, va);
625 va_end(va);
626}
627
628
629/** vuprintf implementation */
630void VBoxDtUPrintfV(const char *pszFormat, va_list va)
631{
632 SUPR0Printf("%N", pszFormat, va);
633}
634
635
636/* CRED implementation. */
637cred_t *VBoxDtGetCurrentCreds(void)
638{
639 PVBDTSTACKDATA pData = vboxDtGetStackData();
640 if (!pData->pCred)
641 {
642 struct VBoxDtCred *pCred;
643 int rc = RTMemAllocEx(sizeof(*pCred), 0, RTMEMALLOCEX_FLAGS_ANY_CTX, (void **)&pCred);
644 AssertFatalRC(rc);
645 pCred->cr_refs = 1;
646 /** @todo get the right creds on unix systems. */
647 pCred->cr_uid = 0;
648 pCred->cr_ruid = 0;
649 pCred->cr_suid = 0;
650 pCred->cr_gid = 0;
651 pCred->cr_rgid = 0;
652 pCred->cr_sgid = 0;
653 pCred->cr_zone = 0;
654 pData->pCred = pCred;
655 }
656
657 return pData->pCred;
658}
659
660
661/* crhold implementation */
662void VBoxDtCredHold(struct VBoxDtCred *pCred)
663{
664 int32_t cRefs = ASMAtomicIncS32(&pCred->cr_refs);
665 Assert(cRefs > 1);
666}
667
668
669/* crfree implementation */
670void VBoxDtCredFree(struct VBoxDtCred *pCred)
671{
672 int32_t cRefs = ASMAtomicDecS32(&pCred->cr_refs);
673 Assert(cRefs >= 0);
674 if (!cRefs)
675 RTMemFree(pCred);
676}
677
678
679/** The number of bits per chunk.
680 * @remarks The 32 bytes are for heap headers and such like. */
681#define VBOXDTVMEMCHUNK_BITS ( ((_64K - 32 - sizeof(uint32_t) * 2) / sizeof(uint32_t)) * 32)
682
683/**
684 * Resource allocator chunk.
685 */
686typedef struct VBoxDtVMemChunk
687{
688 /** The ordinal (unbased) of the first item. */
689 uint32_t iFirst;
690 /** The current number of free items in this chunk. */
691 uint32_t cCurFree;
692 /** The allocation bitmap. */
693 uint32_t bm[VBOXDTVMEMCHUNK_BITS / 32];
694} VBOXDTVMEMCHUNK;
695/** Pointer to a resource allocator chunk. */
696typedef VBOXDTVMEMCHUNK *PVBOXDTVMEMCHUNK;
697
698
699
700/**
701 * Resource allocator instance.
702 */
703typedef struct VBoxDtVMem
704{
705 /** Spinlock protecting the data. */
706 RTSPINLOCK hSpinlock;
707 /** Magic value. */
708 uint32_t u32Magic;
709 /** The current number of free items in the chunks. */
710 uint32_t cCurFree;
711 /** The current number of chunks that we have allocated. */
712 uint32_t cCurChunks;
713 /** The configured resource base. */
714 uint32_t uBase;
715 /** The configured resource end (base included). */
716 uint32_t uEnd;
717 /** The size of the apChunks array. */
718 uint32_t cMaxChunks;
719 /** Array of chunk pointers.
720 * (The size is determined at creation.) */
721 PVBOXDTVMEMCHUNK apChunks[1];
722} VBOXDTVMEM;
723/** Pointer to a resource allocator instance. */
724typedef VBOXDTVMEM *PVBOXDTVMEM;
725
726/** Magic value for the VBOXDTVMEM structure. */
727#define VBOXDTVMEM_MAGIC RT_MAKE_U32_FROM_U8('V', 'M', 'e', 'm')
728
729
730/* vmem_create implementation */
731struct VBoxDtVMem *VBoxDtVMemCreate(const char *pszName, void *pvBase, size_t cb, size_t cbUnit,
732 PFNRT pfnAlloc, PFNRT pfnFree, struct VBoxDtVMem *pSrc,
733 size_t cbQCacheMax, uint32_t fFlags)
734{
735 /*
736 * Assert preconditions of this implementation.
737 */
738 AssertMsgReturn((uintptr_t)pvBase <= UINT32_MAX, ("%p\n", pvBase), NULL);
739 AssertMsgReturn((uintptr_t)pvBase + cb - 1 <= UINT32_MAX, ("%p %zu\n", pvBase, cb), NULL);
740 AssertMsgReturn(cbUnit == 1, ("%zu\n", cbUnit), NULL);
741 AssertReturn(!pfnAlloc, NULL);
742 AssertReturn(!pfnFree, NULL);
743 AssertReturn(!pSrc, NULL);
744 AssertReturn(!cbQCacheMax, NULL);
745 AssertReturn(fFlags & VM_SLEEP, NULL);
746 AssertReturn(fFlags & VMC_IDENTIFIER, NULL);
747
748 /*
749 * Allocate the instance.
750 */
751 uint32_t cChunks = (uint32_t)(cb - (uintptr_t)pvBase);
752 cChunks += VBOXDTVMEMCHUNK_BITS - 1;
753 cChunks /= VBOXDTVMEMCHUNK_BITS;
754 PVBOXDTVMEM pThis = (PVBOXDTVMEM)RTMemAllocZ(RT_OFFSETOF(VBOXDTVMEM, apChunks[cChunks]));
755 if (!pThis)
756 return NULL;
757 int rc = RTSpinlockCreate(&pThis->hSpinlock);
758 if (RT_FAILURE(rc))
759 {
760 RTMemFree(pThis);
761 return NULL;
762 }
763 pThis->u32Magic = VBOXDTVMEM_MAGIC;
764 pThis->cCurFree = 0;
765 pThis->cCurChunks = 0;
766 pThis->uBase = (uint32_t)(uintptr_t)pvBase;
767 pThis->uEnd = (uint32_t)cb;
768 pThis->cMaxChunks = cChunks;
769
770 return pThis;
771}
772
773
774/* vmem_destroy implementation */
775void VBoxDtVMemDestroy(struct VBoxDtVMem *pThis)
776{
777 if (!pThis)
778 return;
779 AssertPtrReturnVoid(pThis);
780 AssertReturnVoid(pThis->u32Magic == VBOXDTVMEM_MAGIC);
781
782 /*
783 * Invalidate the instance.
784 */
785 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
786 RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp); /* paranoia */
787 pThis->u32Magic = 0;
788 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
789 RTSpinlockDestroy(pThis->hSpinlock);
790
791 /*
792 * Free the chunks, then the instance.
793 */
794 uint32_t iChunk = pThis->cCurChunks;
795 while (iChunk-- > 0)
796 {
797 RTMemFree(pThis->apChunks[iChunk]);
798 pThis->apChunks[iChunk] = NULL;
799 }
800 RTMemFree(pThis);
801}
802
803
804/* vmem_alloc implementation */
805void *VBoxDtVMemAlloc(struct VBoxDtVMem *pThis, size_t cbMem, uint32_t fFlags)
806{
807 /*
808 * Validate input.
809 */
810 AssertReturn(fFlags & VM_BESTFIT, NULL);
811 AssertReturn(fFlags & VM_SLEEP, NULL);
812 AssertReturn(cbMem == 1, NULL);
813 AssertPtrReturn(pThis, NULL);
814 AssertReturn(pThis->u32Magic == VBOXDTVMEM_MAGIC, NULL);
815
816 /*
817 * Allocation loop.
818 */
819 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
820 RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
821 for (;;)
822 {
823 PVBOXDTVMEMCHUNK pChunk;
824 uint32_t const cChunks = pThis->cCurChunks;
825
826 if (RT_LIKELY(pThis->cCurFree > 0))
827 {
828 for (uint32_t iChunk = 0; iChunk < cChunks; iChunk++)
829 {
830 pChunk = pThis->apChunks[iChunk];
831 if (pChunk->cCurFree > 0)
832 {
833 int iBit = ASMBitFirstClear(pChunk->bm, VBOXDTVMEMCHUNK_BITS);
834 AssertMsgReturnStmt(iBit >= 0 && (unsigned)iBit < VBOXDTVMEMCHUNK_BITS, ("%d\n", iBit),
835 RTSpinlockRelease(pThis->hSpinlock, &Tmp),
836 NULL);
837
838 ASMBitSet(pChunk->bm, iBit);
839 pChunk->cCurFree--;
840 pThis->cCurFree--;
841
842 uint32_t iRet = (uint32_t)iBit + pChunk->iFirst + pThis->uBase;
843 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
844 return (void *)(uintptr_t)iRet;
845 }
846 }
847 AssertFailedBreak();
848 }
849
850 /* Out of resources? */
851 if (cChunks >= pThis->cMaxChunks)
852 break;
853
854 /*
855 * Allocate another chunk.
856 */
857 uint32_t const iFirstBit = cChunks > 0 ? pThis->apChunks[cChunks - 1]->iFirst + VBOXDTVMEMCHUNK_BITS : 0;
858 uint32_t const cFreeBits = cChunks + 1 == pThis->cMaxChunks
859 ? pThis->uEnd - pThis->uBase - iFirstBit
860 : VBOXDTVMEMCHUNK_BITS;
861 Assert(cFreeBits <= VBOXDTVMEMCHUNK_BITS);
862
863 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
864
865 pChunk = (PVBOXDTVMEMCHUNK)RTMemAllocZ(sizeof(*pChunk));
866 if (!pChunk)
867 return NULL;
868
869 pChunk->iFirst = iFirstBit;
870 pChunk->cCurFree = cFreeBits;
871 if (cFreeBits != VBOXDTVMEMCHUNK_BITS)
872 {
873 /* lazy bird. */
874 uint32_t iBit = cFreeBits;
875 while (iBit < VBOXDTVMEMCHUNK_BITS)
876 {
877 ASMBitSet(pChunk->bm, iBit);
878 iBit++;
879 }
880 }
881
882 RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
883
884 /*
885 * Insert the new chunk. If someone raced us here, we'll drop it to
886 * avoid wasting resources.
887 */
888 if (pThis->cCurChunks == cChunks)
889 {
890 pThis->apChunks[cChunks] = pChunk;
891 pThis->cCurFree += pChunk->cCurFree;
892 pThis->cCurChunks += 1;
893 }
894 else
895 {
896 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
897 RTMemFree(pChunk);
898 RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
899 }
900 }
901 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
902
903 return NULL;
904}
905
906/* vmem_free implementation */
907void VBoxDtVMemFree(struct VBoxDtVMem *pThis, void *pvMem, size_t cbMem)
908{
909 /*
910 * Validate input.
911 */
912 AssertReturnVoid(cbMem == 1);
913 AssertPtrReturnVoid(pThis);
914 AssertReturnVoid(pThis->u32Magic == VBOXDTVMEM_MAGIC);
915
916 AssertReturnVoid((uintptr_t)pvMem < UINT32_MAX);
917 uint32_t uMem = (uint32_t)(uintptr_t)pvMem;
918 AssertReturnVoid(uMem >= pThis->uBase);
919 AssertReturnVoid(uMem < pThis->uEnd);
920
921 uMem -= pThis->uBase;
922
923 /*
924 * Free it.
925 */
926 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
927 RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
928 uint32_t const iChunk = uMem / VBOXDTVMEMCHUNK_BITS;
929 if (iChunk < pThis->cCurChunks)
930 {
931 PVBOXDTVMEMCHUNK pChunk = pThis->apChunks[iChunk];
932 uint32_t iBit = uMem - pChunk->iFirst;
933 AssertReturnVoidStmt(iBit < VBOXDTVMEMCHUNK_BITS, RTSpinlockRelease(pThis->hSpinlock, &Tmp));
934 AssertReturnVoidStmt(ASMBitTestAndClear(pChunk->bm, iBit), RTSpinlockRelease(pThis->hSpinlock, &Tmp));
935
936 pChunk->cCurFree++;
937 pThis->cCurFree++;
938 }
939
940 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
941}
942
943#if 0
944VBoxDtMutexIsOwner
945VBoxDtMutexExit
946VBoxDtMutexEnter
947
948VBoxDtKMemFree
949VBoxDtKMemCacheFree
950VBoxDtKMemCacheDestroy
951VBoxDtKMemCacheCreate
952VBoxDtKMemCacheAlloc
953
954VBoxDtKMemAllocZ
955VBoxDtKMemAlloc
956
957VBoxDtGetKernelBase
958VBoxDtGetCurrentThread
959VBoxDtGetCurrentProc
960#endif
961
962
963/*
964 *
965 * Helpers for handling VTG structures.
966 * Helpers for handling VTG structures.
967 * Helpers for handling VTG structures.
968 *
969 */
970
971
972
973/**
974 * Converts an attribute from VTG description speak to DTrace.
975 *
976 * @param pDtAttr The DTrace attribute (dst).
977 * @param pVtgAttr The VTG attribute descriptor (src).
978 */
979static void vboxDtVtgConvAttr(dtrace_attribute_t *pDtAttr, PCVTGDESCATTR pVtgAttr)
980{
981 pDtAttr->dtat_name = pVtgAttr->u8Code - 1;
982 pDtAttr->dtat_data = pVtgAttr->u8Data - 1;
983 pDtAttr->dtat_class = pVtgAttr->u8DataDep - 1;
984}
985
986/**
987 * Gets a string from the string table.
988 *
989 * @returns Pointer to the string.
990 * @param pVtgHdr The VTG object header.
991 * @param offStrTab The string table offset.
992 */
993static const char *vboxDtVtgGetString(PVTGOBJHDR pVtgHdr, uint32_t offStrTab)
994{
995 Assert(offStrTab < pVtgHdr->cbStrTab);
996 return &pVtgHdr->pachStrTab[offStrTab];
997}
998
999
1000
1001/*
1002 *
1003 * DTrace Provider Interface.
1004 * DTrace Provider Interface.
1005 * DTrace Provider Interface.
1006 *
1007 */
1008
1009
1010/**
1011 * @callback_method_impl{dtrace_pops_t,dtps_provide}
1012 */
1013static void vboxDtPOps_Provide(void *pvProv, const dtrace_probedesc_t *pDtProbeDesc)
1014{
1015 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1016 PVTGPROBELOC pProbeLoc = pProv->pHdr->paProbLocs;
1017 PVTGPROBELOC pProbeLocEnd = pProv->pHdr->paProbLocsEnd;
1018 dtrace_provider_id_t idProvider = pProv->TracerData.DTrace.idProvider;
1019 size_t const cbFnNmBuf = _4K + _1K;
1020 char *pszFnNmBuf;
1021 uint16_t idxProv;
1022
1023 if (pDtProbeDesc)
1024 return; /* We don't generate probes, so never mind these requests. */
1025
1026 if (pProv->TracerData.DTrace.fZombie)
1027 return;
1028
1029 if (pProv->TracerData.DTrace.cProvidedProbes >= pProbeLocEnd - pProbeLoc)
1030 return;
1031
1032 /* Need a buffer for extracting the function names and mangling them in
1033 case of collision. */
1034 pszFnNmBuf = (char *)RTMemAlloc(cbFnNmBuf);
1035 if (!pszFnNmBuf)
1036 return;
1037
1038 /*
1039 * Itereate the probe location list and register all probes related to
1040 * this provider.
1041 */
1042 idxProv = (uint16_t)(&pProv->pHdr->paProviders[0] - pProv->pDesc);
1043 while ((uintptr_t)pProbeLoc < (uintptr_t)pProbeLocEnd)
1044 {
1045 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
1046 if ( pProbeDesc->idxProvider == idxProv
1047 && pProbeLoc->idProbe == UINT32_MAX)
1048 {
1049 /* The function name normally needs to be stripped since we're
1050 using C++ compilers for most of the code. ASSUMES nobody are
1051 brave/stupid enough to use function pointer returns without
1052 typedef'ing properly them. */
1053 const char *pszPrbName = vboxDtVtgGetString(pProv->pHdr, pProbeDesc->offName);
1054 const char *pszFunc = pProbeLoc->pszFunction;
1055 const char *psz = strchr(pProbeLoc->pszFunction, '(');
1056 size_t cch;
1057 if (psz)
1058 {
1059 /* skip blanks preceeding the parameter parenthesis. */
1060 while ( (uintptr_t)psz > (uintptr_t)pProbeLoc->pszFunction
1061 && RT_C_IS_BLANK(psz[-1]))
1062 psz--;
1063
1064 /* Find the start of the function name. */
1065 pszFunc = psz - 1;
1066 while ((uintptr_t)pszFunc > (uintptr_t)pProbeLoc->pszFunction)
1067 {
1068 char ch = pszFunc[-1];
1069 if (!RT_C_IS_ALNUM(ch) && ch != '_' && ch != ':')
1070 break;
1071 pszFunc--;
1072 }
1073 cch = psz - pszFunc;
1074 }
1075 else
1076 cch = strlen(pszFunc);
1077 RTStrCopyEx(pszFnNmBuf, cbFnNmBuf, pszFunc, cch);
1078
1079 /* Look up the probe, if we have one in the same function, mangle
1080 the function name a little to avoid having to deal with having
1081 multiple location entries with the same probe ID. (lazy bird) */
1082 Assert(pProbeLoc->idProbe == UINT32_MAX);
1083 if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
1084 {
1085 RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u", pProbeLoc->uLine);
1086 if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
1087 {
1088 unsigned iOrd = 2;
1089 while (iOrd < 128)
1090 {
1091 RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u-%u", pProbeLoc->uLine, iOrd);
1092 if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) == DTRACE_IDNONE)
1093 break;
1094 iOrd++;
1095 }
1096 if (iOrd >= 128)
1097 {
1098 LogRel(("VBoxDrv: More than 128 duplicate probe location instances in file %s at line %u, function %s [%s], probe %s\n",
1099 pProbeLoc->pszFile, pProbeLoc->uLine, pProbeLoc->pszFunction, pszFnNmBuf, pszPrbName));
1100 continue;
1101 }
1102 }
1103 }
1104
1105 /* Create the probe. */
1106 AssertCompile(sizeof(pProbeLoc->idProbe) == sizeof(dtrace_id_t));
1107 pProbeLoc->idProbe = dtrace_probe_create(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName,
1108 0 /*aframes*/, pProbeLoc);
1109 pProv->TracerData.DTrace.cProvidedProbes++;
1110 }
1111
1112 pProbeLoc++;
1113 }
1114
1115 RTMemFree(pszFnNmBuf);
1116}
1117
1118
1119/**
1120 * @callback_method_impl{dtrace_pops_t,dtps_enable}
1121 */
1122static int vboxDtPOps_Enable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
1123{
1124 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1125 if (!pProv->TracerData.DTrace.fZombie)
1126 {
1127 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
1128 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
1129
1130 if (!pProbeLoc->fEnabled)
1131 {
1132 pProbeLoc->fEnabled = 1;
1133 if (ASMAtomicIncU32(&pProbeDesc->u32User) == 1)
1134 pProv->pHdr->pafProbeEnabled[pProbeDesc->idxEnabled] = 1;
1135 }
1136 }
1137
1138 return 0;
1139}
1140
1141
1142/**
1143 * @callback_method_impl{dtrace_pops_t,dtps_disable}
1144 */
1145static void vboxDtPOps_Disable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
1146{
1147 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1148 if (!pProv->TracerData.DTrace.fZombie)
1149 {
1150 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
1151 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
1152
1153 if (pProbeLoc->fEnabled)
1154 {
1155 pProbeLoc->fEnabled = 0;
1156 if (ASMAtomicDecU32(&pProbeDesc->u32User) == 0)
1157 pProv->pHdr->pafProbeEnabled[pProbeDesc->idxEnabled] = 1;
1158 }
1159 }
1160}
1161
1162
1163/**
1164 * @callback_method_impl{dtrace_pops_t,dtps_getargdesc}
1165 */
1166static void vboxDtPOps_GetArgDesc(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
1167 dtrace_argdesc_t *pArgDesc)
1168{
1169 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1170 unsigned uArg = pArgDesc->dtargd_ndx;
1171
1172 if (!pProv->TracerData.DTrace.fZombie)
1173 {
1174 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
1175 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
1176 PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pProv->pHdr->paArgLists + pProbeDesc->offArgList);
1177
1178 Assert(pProbeDesc->offArgList < pProv->pHdr->cbArgLists);
1179 if (pArgList->cArgs > uArg)
1180 {
1181 const char *pszType = vboxDtVtgGetString(pProv->pHdr, pArgList->aArgs[uArg].offType);
1182 size_t cchType = strlen(pszType);
1183 if (cchType < sizeof(pArgDesc->dtargd_native))
1184 {
1185 memcpy(pArgDesc->dtargd_native, pszType, cchType + 1);
1186 /** @todo mapping */
1187 return;
1188 }
1189 }
1190 }
1191
1192 pArgDesc->dtargd_ndx = DTRACE_ARGNONE;
1193}
1194
1195
1196/**
1197 * @callback_method_impl{dtrace_pops_t,dtps_getargval}
1198 */
1199static uint64_t vboxDtPOps_GetArgVal(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
1200 int iArg, int cFrames)
1201{
1202 PVBDTSTACKDATA pData = vboxDtGetStackData();
1203 AssertReturn(iArg >= 5, UINT64_MAX);
1204
1205 if (pData->enmCaller == kVBoxDtCaller_ProbeFireKernel)
1206 return pData->u.ProbeFireKernel.pauStackArgs[iArg - 5];
1207
1208 if (pData->enmCaller == kVBoxDtCaller_ProbeFireUser)
1209 {
1210 PCSUPDRVTRACERUSRCTX pCtx = pData->u.ProbeFireUser.pCtx;
1211 if (pCtx->cBits == 32)
1212 {
1213 if ((unsigned)iArg < RT_ELEMENTS(pCtx->u.X86.aArgs))
1214 return pCtx->u.X86.aArgs[iArg];
1215 }
1216 else if (pCtx->cBits == 64)
1217 {
1218 if ((unsigned)iArg < RT_ELEMENTS(pCtx->u.Amd64.aArgs))
1219 return pCtx->u.Amd64.aArgs[iArg];
1220 }
1221 else
1222 AssertFailed();
1223 }
1224
1225 return UINT64_MAX;
1226}
1227
1228
1229/**
1230 * @callback_method_impl{dtrace_pops_t,dtps_destroy}
1231 */
1232static void vboxDtPOps_Destroy(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
1233{
1234 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
1235 if (!pProv->TracerData.DTrace.fZombie)
1236 {
1237 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
1238 Assert(!pProbeLoc->fEnabled);
1239 Assert(pProbeLoc->idProbe == idProbe); NOREF(idProbe);
1240 pProbeLoc->idProbe = UINT32_MAX;
1241 }
1242 pProv->TracerData.DTrace.cProvidedProbes--;
1243}
1244
1245
1246
1247/**
1248 * DTrace provider method table.
1249 */
1250static const dtrace_pops_t g_vboxDtVtgProvOps =
1251{
1252 /* .dtps_provide = */ vboxDtPOps_Provide,
1253 /* .dtps_provide_module = */ NULL,
1254 /* .dtps_enable = */ vboxDtPOps_Enable,
1255 /* .dtps_disable = */ vboxDtPOps_Disable,
1256 /* .dtps_suspend = */ NULL,
1257 /* .dtps_resume = */ NULL,
1258 /* .dtps_getargdesc = */ vboxDtPOps_GetArgDesc,
1259 /* .dtps_getargval = */ vboxDtPOps_GetArgVal,
1260 /* .dtps_usermode = */ NULL,
1261 /* .dtps_destroy = */ vboxDtPOps_Destroy
1262};
1263
1264
1265
1266
1267/*
1268 *
1269 * Support Driver Tracer Interface.
1270 * Support Driver Tracer Interface.
1271 * Support Driver Tracer Interface.
1272 *
1273 */
1274
1275
1276
1277/**
1278 * interface_method_impl{SUPDRVTRACERREG,pfnProbeFireUser}
1279 */
1280static DECLCALLBACK(void) vbdt_ProbeFireKernel(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2,
1281 uintptr_t uArg3, uintptr_t uArg4)
1282{
1283 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_ProbeFireKernel);
1284
1285 pStackData->u.ProbeFireKernel.uCaller = (uintptr_t)ASMReturnAddress();
1286 pStackData->u.ProbeFireKernel.pauStackArgs = &uArg4 + 1;
1287 dtrace_probe(pVtgProbeLoc->idProbe, uArg0, uArg1, uArg2, uArg3, uArg4);
1288
1289 VBDT_CLEAR_STACK_DATA();
1290 return ;
1291}
1292
1293
1294/**
1295 * interface_method_impl{SUPDRVTRACERREG,pfnProbeFireUser}
1296 */
1297static DECLCALLBACK(void) vbdt_ProbeFireUser(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, PCSUPDRVTRACERUSRCTX pCtx)
1298{
1299 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_ProbeFireUser);
1300
1301 pStackData->u.ProbeFireUser.pCtx = pCtx;
1302 if (pCtx->cBits == 32)
1303 dtrace_probe(pCtx->idProbe,
1304 pCtx->u.X86.aArgs[0],
1305 pCtx->u.X86.aArgs[1],
1306 pCtx->u.X86.aArgs[2],
1307 pCtx->u.X86.aArgs[3],
1308 pCtx->u.X86.aArgs[4]);
1309 else if (pCtx->cBits == 64)
1310 dtrace_probe(pCtx->idProbe,
1311 pCtx->u.Amd64.aArgs[0],
1312 pCtx->u.Amd64.aArgs[1],
1313 pCtx->u.Amd64.aArgs[2],
1314 pCtx->u.Amd64.aArgs[3],
1315 pCtx->u.Amd64.aArgs[4]);
1316 else
1317 AssertFailed();
1318
1319 VBDT_CLEAR_STACK_DATA();
1320}
1321
1322
1323/**
1324 * interface_method_impl{SUPDRVTRACERREG,pfnTracerOpen}
1325 */
1326static DECLCALLBACK(int) vbdt_TracerOpen(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uint32_t uCookie, uintptr_t uArg,
1327 uintptr_t *puSessionData)
1328{
1329 if (uCookie != RT_MAKE_U32_FROM_U8('V', 'B', 'D', 'T'))
1330 return VERR_INVALID_MAGIC;
1331 if (uArg)
1332 return VERR_INVALID_PARAMETER;
1333
1334 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1335
1336 int rc = dtrace_open((dtrace_state_t **)puSessionData, VBoxDtGetCurrentCreds());
1337
1338 VBDT_CLEAR_STACK_DATA();
1339 return RTErrConvertFromErrno(rc);
1340}
1341
1342
1343/**
1344 * interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
1345 */
1346static DECLCALLBACK(int) vbdt_TracerIoCtl(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData,
1347 uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
1348{
1349 AssertPtrReturn(uSessionData, VERR_INVALID_POINTER);
1350 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1351
1352 int rc = dtrace_ioctl((dtrace_state_t *)uSessionData, (intptr_t)uCmd, (intptr_t)uArg, piRetVal);
1353
1354 VBDT_CLEAR_STACK_DATA();
1355 return VINF_SUCCESS;
1356}
1357
1358
1359/**
1360 * interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
1361 */
1362static DECLCALLBACK(void) vbdt_TracerClose(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData)
1363{
1364 AssertPtrReturnVoid(uSessionData);
1365 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1366
1367 dtrace_close((dtrace_state_t *)uSessionData);
1368
1369 VBDT_CLEAR_STACK_DATA();
1370}
1371
1372
1373/**
1374 * interface_method_impl{SUPDRVTRACERREG,pfnProviderRegister}
1375 */
1376static DECLCALLBACK(int) vbdt_ProviderRegister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
1377{
1378 AssertReturn(pCore->TracerData.DTrace.idProvider == UINT32_MAX || pCore->TracerData.DTrace.idProvider == 0,
1379 VERR_INTERNAL_ERROR_3);
1380 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1381
1382 PVTGDESCPROVIDER pDesc = pCore->pDesc;
1383 dtrace_pattr_t DtAttrs;
1384 vboxDtVtgConvAttr(&DtAttrs.dtpa_provider, &pDesc->AttrSelf);
1385 vboxDtVtgConvAttr(&DtAttrs.dtpa_mod, &pDesc->AttrModules);
1386 vboxDtVtgConvAttr(&DtAttrs.dtpa_func, &pDesc->AttrFunctions);
1387 vboxDtVtgConvAttr(&DtAttrs.dtpa_name, &pDesc->AttrNames);
1388 vboxDtVtgConvAttr(&DtAttrs.dtpa_args, &pDesc->AttrArguments);
1389
1390 dtrace_provider_id_t idProvider;
1391 int rc = dtrace_register(pCore->pszName,
1392 &DtAttrs,
1393 DTRACE_PRIV_KERNEL,
1394 NULL /* cred */,
1395 &g_vboxDtVtgProvOps,
1396 pCore,
1397 &idProvider);
1398 if (!rc)
1399 {
1400 Assert(idProvider != UINT32_MAX && idProvider != 0);
1401 pCore->TracerData.DTrace.idProvider = idProvider;
1402 Assert(pCore->TracerData.DTrace.idProvider == idProvider);
1403 rc = VINF_SUCCESS;
1404 }
1405 else
1406 rc = RTErrConvertFromErrno(rc);
1407
1408 VBDT_CLEAR_STACK_DATA();
1409 return rc;
1410}
1411
1412
1413/**
1414 * interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregister}
1415 */
1416static DECLCALLBACK(int) vbdt_ProviderDeregister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
1417{
1418 uint32_t idProvider = pCore->TracerData.DTrace.idProvider;
1419 AssertReturn(idProvider != UINT32_MAX && idProvider != 0, VERR_INTERNAL_ERROR_4);
1420 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1421
1422 dtrace_invalidate(idProvider);
1423 int rc = dtrace_unregister(idProvider);
1424 if (!rc)
1425 {
1426 pCore->TracerData.DTrace.idProvider = UINT32_MAX;
1427 rc = VINF_SUCCESS;
1428 }
1429 else
1430 {
1431 AssertMsg(rc == EBUSY, ("%d\n", rc));
1432 rc = VERR_TRY_AGAIN;
1433 }
1434
1435 VBDT_CLEAR_STACK_DATA();
1436 return rc;
1437}
1438
1439
1440/**
1441 * interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregisterZombie}
1442 */
1443static DECLCALLBACK(int) vbdt_ProviderDeregisterZombie(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
1444{
1445 uint32_t idProvider = pCore->TracerData.DTrace.idProvider;
1446 AssertReturn(idProvider != UINT32_MAX && idProvider != 0, VERR_INTERNAL_ERROR_4);
1447 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_Generic);
1448
1449 int rc = dtrace_unregister(idProvider);
1450 if (!rc)
1451 {
1452 pCore->TracerData.DTrace.idProvider = UINT32_MAX;
1453 rc = VINF_SUCCESS;
1454 }
1455 else
1456 {
1457 AssertMsg(rc == EBUSY, ("%d\n", rc));
1458 rc = VERR_TRY_AGAIN;
1459 }
1460
1461 VBDT_CLEAR_STACK_DATA();
1462 return rc;
1463}
1464
1465
1466
1467/**
1468 * The tracer registration record of the VBox DTrace implementation
1469 */
1470static SUPDRVTRACERREG g_VBoxDTraceReg =
1471{
1472 SUPDRVTRACERREG_MAGIC,
1473 SUPDRVTRACERREG_VERSION,
1474 vbdt_ProbeFireKernel,
1475 vbdt_ProbeFireUser,
1476 vbdt_TracerOpen,
1477 vbdt_TracerIoCtl,
1478 vbdt_TracerClose,
1479 vbdt_ProviderRegister,
1480 vbdt_ProviderDeregister,
1481 vbdt_ProviderDeregisterZombie,
1482 SUPDRVTRACERREG_MAGIC
1483};
1484
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette