VirtualBox

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

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

VBoxDTrace: If windows can use standard RTMemAlloc, so can we (doesn't work otherwise). Don't access pHdr before checking fZombie, duh. (r72)

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