SUPDrv-dtrace.cpp revision f714516da18876b1836a804fc0cac5e8ff589e83
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/* $Id$ */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/** @file
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * VBoxDrv - The VirtualBox Support Driver - DTrace Provider.
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/*
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * Copyright (C) 2012 Oracle Corporation
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync *
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * available from http://www.virtualbox.org. This file is free software;
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * you can redistribute it and/or modify it under the terms of the GNU
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * General Public License (GPL) as published by the Free Software
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync *
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * The contents of this file may alternatively be used under the terms
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * of the Common Development and Distribution License Version 1.0
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * VirtualBox OSE distribution, in which case the provisions of the
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * CDDL are applicable instead of those of the GPL.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync *
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * You may elect to license modified versions of this file under the
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * terms and conditions of either the GPL or the CDDL or both.
7b9f0c34e9ea328981c99e97054bdf8684d9d620vboxsync */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/*******************************************************************************
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync* Header Files *
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync*******************************************************************************/
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync#define LOG_GROUP LOG_GROUP_SUP_DRV
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#include "SUPDrvInternal.h"
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#include <VBox/err.h>
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#include <VBox/log.h>
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#include <VBox/VBoxTpG.h>
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync#include <iprt/assert.h>
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync#include <iprt/ctype.h>
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync#include <iprt/mem.h>
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync#include <iprt/errno.h>
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync#ifdef RT_OS_DARWIN
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# include <iprt/dbg.h>
13f1ce3859ee77d9b9f4d2ca9f93e1633cb133bcvboxsync#endif
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync#ifdef RT_OS_DARWIN
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# include VBOX_PATH_MACOSX_DTRACE_H
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync#elif defined(RT_OS_LINUX)
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/* Avoid type and define conflicts. */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# undef UINT8_MAX
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# undef UINT16_MAX
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# undef UINT32_MAX
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# undef UINT64_MAX
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# undef INT64_MAX
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# undef INT64_MIN
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# define intptr_t dtrace_intptr_t
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# if 0
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/* DTrace experiments with the Unbreakable Enterprise Kernel (UEK2)
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync (Oracle Linux).
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync 1. The dtrace.h here is from the dtrace module source, not
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync /usr/include/sys/dtrace.h nor /usr/include/dtrace.h.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync 2. To generate the missing entries for the dtrace module in Module.symvers
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync of UEK:
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync nm /lib/modules/....../kernel/drivers/dtrace/dtrace.ko \
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync | grep _crc_ \
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync | sed -e 's/^......../0x/' -e 's/ A __crc_/\t/' \
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync -e 's/$/\tdrivers\/dtrace\/dtrace\tEXPORT_SYMBOL/' \
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync >> Module.symvers
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync Update: Althernative workaround (active), resolve symbols dynamically.
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync 3. No tracepoints in vboxdrv, vboxnet* or vboxpci yet. This requires yasm
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync and VBoxTpG and build time. */
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync# include "dtrace.h"
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync# else
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync/* DTrace experiments with the Unbreakable Enterprise Kernel (UEKR3)
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync (Oracle Linux).
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync 1. To generate the missing entries for the dtrace module in Module.symvers
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync of UEK:
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync nm /lib/modules/....../kernel/drivers/dtrace/dtrace.ko \
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync | grep _crc_ \
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync | sed -e 's/^......../0x/' -e 's/ A __crc_/\t/' \
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync -e 's/$/\tdrivers\/dtrace\/dtrace\tEXPORT_SYMBOL/' \
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync >> Module.symvers
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync Update: Althernative workaround (active), resolve symbols dynamically.
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync 2. No tracepoints in vboxdrv, vboxnet* or vboxpci yet. This requires yasm
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync and VBoxTpG and build time. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync# include <dtrace/provider.h>
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync# include <dtrace/enabling.h> /* Missing from provider.h. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync# include <dtrace/arg.h> /* Missing from provider.h. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync# endif
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync# include <linux/kallsyms.h>
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync/** Status code fixer (UEK uses linux convension unlike the others). */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync# define FIX_UEK_RC(a_rc) (-(a_rc))
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync#else
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync# include <sys/dtrace.h>
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync#endif
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync/**
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * The UEK DTrace port is trying to be smart and seems to have turned all
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * errno return codes negative. While this conforms to the linux kernel way of
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * doing things, it breaks with the way the interfaces work on Solaris and
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * Mac OS X.
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync#ifndef FIX_UEK_RC
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# define FIX_UEK_RC(a_rc) (a_rc)
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync#endif
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/*******************************************************************************
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync* Structures and Typedefs *
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync*******************************************************************************/
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/* Seems there is some return code difference here. Keep the return code and
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync case it to whatever the host desires. */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync#ifdef RT_OS_DARWIN
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2f3883b126a405f92b19e829472f614c7352b4f9vboxsynctypedef void FNPOPS_ENABLE(void *, dtrace_id_t, void *);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# else
2f3883b126a405f92b19e829472f614c7352b4f9vboxsynctypedef int FNPOPS_ENABLE(void *, dtrace_id_t, void *);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync# endif
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync#else
2f3883b126a405f92b19e829472f614c7352b4f9vboxsynctypedef int FNPOPS_ENABLE(void *, dtrace_id_t, void *);
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync#endif
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/** Caller indicator. */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsynctypedef enum VBOXDTCALLER
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync{
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync kVBoxDtCaller_Invalid = 0,
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync kVBoxDtCaller_Generic,
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync kVBoxDtCaller_ProbeFireUser,
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync kVBoxDtCaller_ProbeFireKernel
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync} VBOXDTCALLER;
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/**
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * Stack data planted before calling dtrace_probe so that we can easily find the
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * stack argument later.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsynctypedef struct VBDTSTACKDATA
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync{
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync /** Eyecatcher no. 1 (SUPDRVDT_STACK_DATA_MAGIC2). */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync uint32_t u32Magic1;
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync /** Eyecatcher no. 2 (SUPDRVDT_STACK_DATA_MAGIC2). */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync uint32_t u32Magic2;
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync /** The format of the caller specific data. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync VBOXDTCALLER enmCaller;
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync /** Caller specific data. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync union
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync {
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync /** kVBoxDtCaller_ProbeFireKernel. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync struct
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync {
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync /** Pointer to the stack arguments of a probe function call. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync uintptr_t *pauStackArgs;
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync } ProbeFireKernel;
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync /** kVBoxDtCaller_ProbeFireUser. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync struct
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync {
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync /** The user context. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync PCSUPDRVTRACERUSRCTX pCtx;
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync /** The argument displacement caused by 64-bit arguments passed directly to
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * dtrace_probe. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync int offArg;
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync } ProbeFireUser;
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync } u;
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync /** Pointer to this structure.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * This is the final bit of integrity checking. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync struct VBDTSTACKDATA *pSelf;
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync} VBDTSTACKDATA;
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync/** Pointer to the on-stack thread specific data. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsynctypedef VBDTSTACKDATA *PVBDTSTACKDATA;
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync/*******************************************************************************
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync* Defined Constants And Macros *
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync*******************************************************************************/
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync/** The first magic value. */
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#define SUPDRVDT_STACK_DATA_MAGIC1 RT_MAKE_U32_FROM_U8('S', 'U', 'P', 'D')
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync/** The second magic value. */
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync#define SUPDRVDT_STACK_DATA_MAGIC2 RT_MAKE_U32_FROM_U8('D', 'T', 'r', 'c')
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync/** The alignment of the stack data.
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync * The data doesn't require more than sizeof(uintptr_t) alignment, but the
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync * greater alignment the quicker lookup. */
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync#define SUPDRVDT_STACK_DATA_ALIGN 32
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync/** Plants the stack data. */
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync#define VBDT_SETUP_STACK_DATA(a_enmCaller) \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync uint8_t abBlob[sizeof(VBDTSTACKDATA) + SUPDRVDT_STACK_DATA_ALIGN - 1]; \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync PVBDTSTACKDATA pStackData = (PVBDTSTACKDATA)( (uintptr_t)&abBlob[SUPDRVDT_STACK_DATA_ALIGN - 1] \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync & ~(uintptr_t)(SUPDRVDT_STACK_DATA_ALIGN - 1)); \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync pStackData->u32Magic1 = SUPDRVDT_STACK_DATA_MAGIC1; \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync pStackData->u32Magic2 = SUPDRVDT_STACK_DATA_MAGIC2; \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync pStackData->enmCaller = a_enmCaller; \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync pStackData->pSelf = pStackData
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync/** Passifies the stack data and frees up resource held within it. */
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync#define VBDT_CLEAR_STACK_DATA() \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync do \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync { \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync pStackData->u32Magic1 = 0; \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync pStackData->u32Magic2 = 0; \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync pStackData->pSelf = NULL; \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync } while (0)
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync/** Simple SUPR0Printf-style logging. */
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#if 0 /*def DEBUG_bird*/
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync# define LOG_DTRACE(a) SUPR0Printf a
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#else
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync# define LOG_DTRACE(a) do { } while (0)
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#endif
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync
510567648d46488f4166e5f69ffffe3eeeeec4d9vboxsync/*******************************************************************************
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync* Global Variables *
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync*******************************************************************************/
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX)
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync/** @name DTrace kernel interface used on Darwin and Linux.
35e6d303696e46d969aaf9a59cc381333a483b0bvboxsync * @{ */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsyncstatic void (* g_pfnDTraceProbeFire)(dtrace_id_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsyncstatic dtrace_id_t (* g_pfnDTraceProbeCreate)(dtrace_provider_id_t, const char *, const char *, const char *, int, void *);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsyncstatic dtrace_id_t (* g_pfnDTraceProbeLookup)(dtrace_provider_id_t, const char *, const char *, const char *);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsyncstatic int (* g_pfnDTraceProviderRegister)(const char *, const dtrace_pattr_t *, uint32_t, /*cred_t*/ void *,
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync const dtrace_pops_t *, void *, dtrace_provider_id_t *);
8bc8d66f188d5357155b8340e2d489573be2b607vboxsyncstatic void (* g_pfnDTraceProviderInvalidate)(dtrace_provider_id_t);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsyncstatic int (* g_pfnDTraceProviderUnregister)(dtrace_provider_id_t);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync#define dtrace_probe g_pfnDTraceProbeFire
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync#define dtrace_probe_create g_pfnDTraceProbeCreate
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync#define dtrace_probe_lookup g_pfnDTraceProbeLookup
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync#define dtrace_register g_pfnDTraceProviderRegister
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync#define dtrace_invalidate g_pfnDTraceProviderInvalidate
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync#define dtrace_unregister g_pfnDTraceProviderUnregister
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync/** @} */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync#endif
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync/**
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * Gets the stack data.
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync *
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * @returns Pointer to the stack data. Never NULL.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsyncstatic PVBDTSTACKDATA vboxDtGetStackData(void)
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync{
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync /*
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * Locate the caller of probe_dtrace.
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync int volatile iDummy = 1; /* use this to get the stack address. */
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync PVBDTSTACKDATA pData = (PVBDTSTACKDATA)( ((uintptr_t)&iDummy + SUPDRVDT_STACK_DATA_ALIGN - 1)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync & ~(uintptr_t)(SUPDRVDT_STACK_DATA_ALIGN - 1));
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync for (;;)
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync {
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync if ( pData->u32Magic1 == SUPDRVDT_STACK_DATA_MAGIC1
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync && pData->u32Magic2 == SUPDRVDT_STACK_DATA_MAGIC2
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync && pData->pSelf == pData)
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync return pData;
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync pData = (PVBDTSTACKDATA)((uintptr_t)pData + SUPDRVDT_STACK_DATA_ALIGN);
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync }
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync}
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync/*
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync *
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * Helpers for handling VTG structures.
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * Helpers for handling VTG structures.
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * Helpers for handling VTG structures.
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync *
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync */
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync/**
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * Converts an attribute from VTG description speak to DTrace.
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync *
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * @param pDtAttr The DTrace attribute (dst).
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * @param pVtgAttr The VTG attribute descriptor (src).
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync */
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsyncstatic void vboxDtVtgConvAttr(dtrace_attribute_t *pDtAttr, PCVTGDESCATTR pVtgAttr)
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync{
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync pDtAttr->dtat_name = pVtgAttr->u8Code - 1;
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync pDtAttr->dtat_data = pVtgAttr->u8Data - 1;
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync pDtAttr->dtat_class = pVtgAttr->u8DataDep - 1;
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync}
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync/**
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * Gets a string from the string table.
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync *
b8bb9c9f6b8ebfd0a7d6df0c0289f9fe80241750vboxsync * @returns Pointer to the string.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * @param pVtgHdr The VTG object header.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * @param offStrTab The string table offset.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync */
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsyncstatic const char *vboxDtVtgGetString(PVTGOBJHDR pVtgHdr, uint32_t offStrTab)
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync{
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync Assert(offStrTab < pVtgHdr->cbStrTab);
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync return (const char *)pVtgHdr + pVtgHdr->offStrTab + offStrTab;
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync}
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync/*
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync *
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * DTrace Provider Interface.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * DTrace Provider Interface.
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * DTrace Provider Interface.
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync *
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync */
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync/**
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * @callback_method_impl{dtrace_pops_t,dtps_provide}
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsyncstatic void vboxDtPOps_Provide(void *pvProv, const dtrace_probedesc_t *pDtProbeDesc)
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync{
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
510567648d46488f4166e5f69ffffe3eeeeec4d9vboxsync AssertPtrReturnVoid(pProv);
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync LOG_DTRACE(("%s: %p / %p pDtProbeDesc=%p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, pDtProbeDesc));
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync if (pDtProbeDesc)
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync return; /* We don't generate probes, so never mind these requests. */
if (pProv->TracerData.DTrace.fZombie)
return;
dtrace_provider_id_t const idProvider = pProv->TracerData.DTrace.idProvider;
AssertPtrReturnVoid(idProvider);
AssertPtrReturnVoid(pProv->pHdr);
AssertReturnVoid(pProv->pHdr->offProbeLocs != 0);
uint32_t const cProbeLocs = pProv->pHdr->cbProbeLocs / sizeof(VTGPROBELOC);
/* Need a buffer for extracting the function names and mangling them in
case of collision. */
size_t const cbFnNmBuf = _4K + _1K;
char *pszFnNmBuf = (char *)RTMemAlloc(cbFnNmBuf);
if (!pszFnNmBuf)
return;
/*
* Itereate the probe location list and register all probes related to
* this provider.
*/
uint16_t const idxProv = (uint16_t)((PVTGDESCPROVIDER)((uintptr_t)pProv->pHdr + pProv->pHdr->offProviders) - pProv->pDesc);
uint32_t idxProbeLoc;
for (idxProbeLoc = 0; idxProbeLoc < cProbeLocs; idxProbeLoc++)
{
/* Skip probe location belonging to other providers or once that
we've already reported. */
PCVTGPROBELOC pProbeLocRO = &pProv->paProbeLocsRO[idxProbeLoc];
PVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
if (pProbeDesc->idxProvider != idxProv)
continue;
uint32_t *pidProbe;
if (!pProv->fUmod)
pidProbe = (uint32_t *)&pProbeLocRO->idProbe;
else
pidProbe = &pProv->paR0ProbeLocs[idxProbeLoc].idProbe;
if (*pidProbe != 0)
continue;
/* The function name may need to be stripped since we're using C++
compilers for most of the code. ASSUMES nobody are brave/stupid
enough to use function pointer returns without typedef'ing
properly them (e.g. signal). */
const char *pszPrbName = vboxDtVtgGetString(pProv->pHdr, pProbeDesc->offName);
const char *pszFunc = pProbeLocRO->pszFunction;
const char *psz = strchr(pProbeLocRO->pszFunction, '(');
size_t cch;
if (psz)
{
/* skip blanks preceeding the parameter parenthesis. */
while ( (uintptr_t)psz > (uintptr_t)pProbeLocRO->pszFunction
&& RT_C_IS_BLANK(psz[-1]))
psz--;
/* Find the start of the function name. */
pszFunc = psz - 1;
while ((uintptr_t)pszFunc > (uintptr_t)pProbeLocRO->pszFunction)
{
char ch = pszFunc[-1];
if (!RT_C_IS_ALNUM(ch) && ch != '_' && ch != ':')
break;
pszFunc--;
}
cch = psz - pszFunc;
}
else
cch = strlen(pszFunc);
RTStrCopyEx(pszFnNmBuf, cbFnNmBuf, pszFunc, cch);
/* Look up the probe, if we have one in the same function, mangle
the function name a little to avoid having to deal with having
multiple location entries with the same probe ID. (lazy bird) */
Assert(!*pidProbe);
if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
{
RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u", pProbeLocRO->uLine);
if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
{
unsigned iOrd = 2;
while (iOrd < 128)
{
RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u-%u", pProbeLocRO->uLine, iOrd);
if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) == DTRACE_IDNONE)
break;
iOrd++;
}
if (iOrd >= 128)
{
LogRel(("VBoxDrv: More than 128 duplicate probe location instances %s at line %u in function %s [%s], probe %s\n",
pProbeLocRO->uLine, pProbeLocRO->pszFunction, pszFnNmBuf, pszPrbName));
continue;
}
}
}
/* Create the probe. */
AssertCompile(sizeof(*pidProbe) == sizeof(dtrace_id_t));
*pidProbe = dtrace_probe_create(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName,
1 /*aframes*/, (void *)(uintptr_t)idxProbeLoc);
pProv->TracerData.DTrace.cProvidedProbes++;
}
RTMemFree(pszFnNmBuf);
LOG_DTRACE(("%s: returns\n", __FUNCTION__));
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_enable}
*/
static int vboxDtPOps_Enable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
{
PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
LOG_DTRACE(("%s: %p / %p - %#x / %p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
AssertPtrReturn(pProv->TracerData.DTrace.idProvider, EINVAL);
if (!pProv->TracerData.DTrace.fZombie)
{
uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
PVTGPROBELOC32 pProbeLocEn = (PVTGPROBELOC32)( (uintptr_t)pProv->pvProbeLocsEn + idxProbeLoc * pProv->cbProbeLocsEn);
PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
uint32_t const idxProbe = pProbeDesc->idxEnabled;
if (!pProv->fUmod)
{
if (!pProbeLocEn->fEnabled)
{
pProbeLocEn->fEnabled = 1;
ASMAtomicIncU32(&pProv->pacProbeEnabled[idxProbe]);
}
}
else
{
/* Update kernel mode structure */
if (!pProv->paR0ProbeLocs[idxProbeLoc].fEnabled)
{
pProv->paR0ProbeLocs[idxProbeLoc].fEnabled = 1;
ASMAtomicIncU32(&pProv->paR0Probes[idxProbe].cEnabled);
}
/* Update user mode structure. */
pProbeLocEn->fEnabled = 1;
pProv->pacProbeEnabled[idxProbe] = pProv->paR0Probes[idxProbe].cEnabled;
}
}
return 0;
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_disable}
*/
static void vboxDtPOps_Disable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
{
PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
AssertPtrReturnVoid(pProv);
LOG_DTRACE(("%s: %p / %p - %#x / %p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
if (!pProv->TracerData.DTrace.fZombie)
{
uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
PVTGPROBELOC32 pProbeLocEn = (PVTGPROBELOC32)( (uintptr_t)pProv->pvProbeLocsEn + idxProbeLoc * pProv->cbProbeLocsEn);
PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
uint32_t const idxProbe = pProbeDesc->idxEnabled;
if (!pProv->fUmod)
{
if (pProbeLocEn->fEnabled)
{
pProbeLocEn->fEnabled = 0;
ASMAtomicDecU32(&pProv->pacProbeEnabled[idxProbe]);
}
}
else
{
/* Update kernel mode structure */
if (pProv->paR0ProbeLocs[idxProbeLoc].fEnabled)
{
pProv->paR0ProbeLocs[idxProbeLoc].fEnabled = 0;
ASMAtomicDecU32(&pProv->paR0Probes[idxProbe].cEnabled);
}
/* Update user mode structure. */
pProbeLocEn->fEnabled = 0;
pProv->pacProbeEnabled[idxProbe] = pProv->paR0Probes[idxProbe].cEnabled;
}
}
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_getargdesc}
*/
static void vboxDtPOps_GetArgDesc(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
dtrace_argdesc_t *pArgDesc)
{
PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
unsigned uArg = pArgDesc->dtargd_ndx;
pArgDesc->dtargd_ndx = DTRACE_ARGNONE;
AssertPtrReturnVoid(pProv);
LOG_DTRACE(("%s: %p / %p - %#x / %p uArg=%d\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe, uArg));
AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
if (!pProv->TracerData.DTrace.fZombie)
{
uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
PCVTGDESCARGLIST pArgList = (PCVTGDESCARGLIST)( (uintptr_t)pProv->pHdr
+ pProv->pHdr->offArgLists
+ pProbeDesc->offArgList);
AssertReturnVoid(pProbeDesc->offArgList < pProv->pHdr->cbArgLists);
if (uArg < pArgList->cArgs)
{
const char *pszType = vboxDtVtgGetString(pProv->pHdr, pArgList->aArgs[uArg].offType);
size_t cchType = strlen(pszType);
if (cchType < sizeof(pArgDesc->dtargd_native))
{
memcpy(pArgDesc->dtargd_native, pszType, cchType + 1);
/** @todo mapping? */
pArgDesc->dtargd_ndx = uArg;
LOG_DTRACE(("%s: returns dtargd_native = %s\n", __FUNCTION__, pArgDesc->dtargd_native));
return;
}
}
}
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_getargval}
*
*
* We just cook our own stuff here, using a stack marker for finding the
* required information. That's more reliable than subjecting oneself to the
* solaris bugs and 32-bit apple peculiarities.
*
*
* @remarks Solaris Bug
*
* dtrace_getarg on AMD64 has a different opinion about how to use the cFrames
* argument than dtrace_caller() and/or dtrace_getpcstack(), at least when the
* probe is fired by dtrace_probe() the way we do.
*
* Setting aframes to 1 when calling dtrace_probe_create gives me the right
* arguments, but the wrong 'caller'. Since I cannot do anything about
* 'caller', the only solution is this hack.
*
* Not sure why the Solaris guys hasn't seen this issue before, but maybe there
* isn't anyone using the default argument getter path for ring-0 dtrace_probe()
* calls, SDT surely isn't.
*
* @todo File a solaris bug on dtrace_probe() + dtrace_getarg().
*
*
* @remarks 32-bit XNU (Apple)
*
* The dtrace_probe arguments are 64-bit unsigned integers instead of uintptr_t,
* so we need to make an extra call.
*
*/
static uint64_t vboxDtPOps_GetArgVal(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
int iArg, int cFrames)
{
PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
AssertPtrReturn(pProv, UINT64_MAX);
LOG_DTRACE(("%s: %p / %p - %#x / %p iArg=%d cFrames=%u\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe, iArg, cFrames));
AssertReturn(iArg >= 5, UINT64_MAX);
if (pProv->TracerData.DTrace.fZombie)
return UINT64_MAX;
uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
PCVTGDESCARGLIST pArgList = (PCVTGDESCARGLIST)( (uintptr_t)pProv->pHdr
+ pProv->pHdr->offArgLists
+ pProbeDesc->offArgList);
AssertReturn(pProbeDesc->offArgList < pProv->pHdr->cbArgLists, UINT64_MAX);
PVBDTSTACKDATA pData = vboxDtGetStackData();
/*
* Get the stack data. This is a wee bit complicated on 32-bit systems
* since we want to support 64-bit integer arguments.
*/
uint64_t u64Ret;
if (iArg >= 20)
u64Ret = UINT64_MAX;
else if (pData->enmCaller == kVBoxDtCaller_ProbeFireKernel)
{
#if ARCH_BITS == 64
u64Ret = pData->u.ProbeFireKernel.pauStackArgs[iArg - 5];
#else
if ( !pArgList->fHaveLargeArgs
|| iArg >= pArgList->cArgs)
u64Ret = pData->u.ProbeFireKernel.pauStackArgs[iArg - 5];
else
{
/* Similar to what we did for mac in when calling dtrace_probe(). */
uint32_t offArg = 0;
for (int i = 5; i < iArg; i++)
if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
offArg++;
u64Ret = pData->u.ProbeFireKernel.pauStackArgs[iArg - 5 + offArg];
if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
u64Ret |= (uint64_t)pData->u.ProbeFireKernel.pauStackArgs[iArg - 5 + offArg + 1] << 32;
}
#endif
}
else if (pData->enmCaller == kVBoxDtCaller_ProbeFireUser)
{
int offArg = pData->u.ProbeFireUser.offArg;
PCSUPDRVTRACERUSRCTX pCtx = pData->u.ProbeFireUser.pCtx;
AssertPtrReturn(pCtx, UINT64_MAX);
if (pCtx->cBits == 32)
{
if ( !pArgList->fHaveLargeArgs
|| iArg >= pArgList->cArgs)
{
if (iArg + offArg < (int)RT_ELEMENTS(pCtx->u.X86.aArgs))
u64Ret = pCtx->u.X86.aArgs[iArg + offArg];
else
u64Ret = UINT64_MAX;
}
else
{
int i;
for (i = 5; i < iArg; i++)
if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
offArg++;
if (offArg + iArg < (int)RT_ELEMENTS(pCtx->u.X86.aArgs))
{
u64Ret = pCtx->u.X86.aArgs[iArg + offArg];
if ( VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType)
&& offArg + iArg + 1 < (int)RT_ELEMENTS(pCtx->u.X86.aArgs))
u64Ret |= (uint64_t)pCtx->u.X86.aArgs[iArg + offArg + 1] << 32;
}
else
u64Ret = UINT64_MAX;
}
}
else
{
if (iArg + offArg < (int)RT_ELEMENTS(pCtx->u.Amd64.aArgs))
u64Ret = pCtx->u.Amd64.aArgs[iArg + offArg];
else
u64Ret = UINT64_MAX;
}
}
else
AssertFailedReturn(UINT64_MAX);
LOG_DTRACE(("%s: returns %#llx\n", __FUNCTION__, u64Ret));
return u64Ret;
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_destroy}
*/
static void vboxDtPOps_Destroy(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
{
PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
AssertPtrReturnVoid(pProv);
LOG_DTRACE(("%s: %p / %p - %#x / %p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
AssertReturnVoid(pProv->TracerData.DTrace.cProvidedProbes > 0);
AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
if (!pProv->TracerData.DTrace.fZombie)
{
uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
uint32_t *pidProbe;
if (!pProv->fUmod)
{
pidProbe = (uint32_t *)&pProbeLocRO->idProbe;
Assert(!pProbeLocRO->fEnabled);
Assert(*pidProbe == idProbe);
}
else
{
pidProbe = &pProv->paR0ProbeLocs[idxProbeLoc].idProbe;
Assert(!pProv->paR0ProbeLocs[idxProbeLoc].fEnabled);
Assert(*pidProbe == idProbe); NOREF(idProbe);
}
*pidProbe = 0;
}
pProv->TracerData.DTrace.cProvidedProbes--;
}
/**
* DTrace provider method table.
*/
static const dtrace_pops_t g_vboxDtVtgProvOps =
{
/* .dtps_provide = */ vboxDtPOps_Provide,
/* .dtps_provide_module = */ NULL,
/* .dtps_enable = */ (FNPOPS_ENABLE *)vboxDtPOps_Enable,
/* .dtps_disable = */ vboxDtPOps_Disable,
/* .dtps_suspend = */ NULL,
/* .dtps_resume = */ NULL,
/* .dtps_getargdesc = */ vboxDtPOps_GetArgDesc,
/* .dtps_getargval = */ vboxDtPOps_GetArgVal,
/* .dtps_usermode = */ NULL,
/* .dtps_destroy = */ vboxDtPOps_Destroy
};
/*
*
* Support Driver Tracer Interface.
* Support Driver Tracer Interface.
* Support Driver Tracer Interface.
*
*/
/**
* interface_method_impl{SUPDRVTRACERREG,pfnProbeFireKernel}
*/
static DECLCALLBACK(void) vboxDtTOps_ProbeFireKernel(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2,
uintptr_t uArg3, uintptr_t uArg4)
{
AssertPtrReturnVoid(pVtgProbeLoc);
LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pVtgProbeLoc, pVtgProbeLoc->idProbe));
AssertPtrReturnVoid(pVtgProbeLoc->pProbe);
AssertPtrReturnVoid(pVtgProbeLoc->pszFunction);
VBDT_SETUP_STACK_DATA(kVBoxDtCaller_ProbeFireKernel);
pStackData->u.ProbeFireKernel.pauStackArgs = &uArg4 + 1;
#if defined(RT_OS_DARWIN) && ARCH_BITS == 32
/*
* Convert arguments from uintptr_t to uint64_t.
*/
PVTGDESCPROBE pProbe = (PVTGDESCPROBE)((PVTGPROBELOC)pVtgProbeLoc)->pProbe;
AssertPtrReturnVoid(pProbe);
PVTGOBJHDR pVtgHdr = (PVTGOBJHDR)((uintptr_t)pProbe + pProbe->offObjHdr);
AssertPtrReturnVoid(pVtgHdr);
PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbe->offArgList);
AssertPtrReturnVoid(pArgList);
if (!pArgList->fHaveLargeArgs)
dtrace_probe(pVtgProbeLoc->idProbe, uArg0, uArg1, uArg2, uArg3, uArg4);
else
{
uintptr_t *auSrcArgs = &uArg0;
uint32_t iSrcArg = 0;
uint32_t iDstArg = 0;
uint64_t au64DstArgs[5];
while ( iDstArg < RT_ELEMENTS(au64DstArgs)
&& iSrcArg < pArgList->cArgs)
{
au64DstArgs[iDstArg] = auSrcArgs[iSrcArg];
if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iDstArg].fType))
au64DstArgs[iDstArg] |= (uint64_t)auSrcArgs[++iSrcArg] << 32;
iSrcArg++;
iDstArg++;
}
while (iDstArg < RT_ELEMENTS(au64DstArgs))
au64DstArgs[iDstArg++] = auSrcArgs[iSrcArg++];
pStackData->u.ProbeFireKernel.pauStackArgs = &auSrcArgs[iSrcArg];
dtrace_probe(pVtgProbeLoc->idProbe, au64DstArgs[0], au64DstArgs[1], au64DstArgs[2], au64DstArgs[3], au64DstArgs[4]);
}
#else
dtrace_probe(pVtgProbeLoc->idProbe, uArg0, uArg1, uArg2, uArg3, uArg4);
#endif
VBDT_CLEAR_STACK_DATA();
LOG_DTRACE(("%s: returns\n", __FUNCTION__));
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnProbeFireUser}
*/
static DECLCALLBACK(void) vboxDtTOps_ProbeFireUser(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, PCSUPDRVTRACERUSRCTX pCtx,
PCVTGOBJHDR pVtgHdr, PCVTGPROBELOC pProbeLocRO)
{
LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pCtx, pCtx->idProbe));
AssertPtrReturnVoid(pProbeLocRO);
AssertPtrReturnVoid(pVtgHdr);
VBDT_SETUP_STACK_DATA(kVBoxDtCaller_ProbeFireUser);
if (pCtx->cBits == 32)
{
pStackData->u.ProbeFireUser.pCtx = pCtx;
pStackData->u.ProbeFireUser.offArg = 0;
#if ARCH_BITS == 64 || defined(RT_OS_DARWIN)
/*
* Combine two 32-bit arguments into one 64-bit argument where needed.
*/
PVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
AssertPtrReturnVoid(pProbeDesc);
PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbeDesc->offArgList);
AssertPtrReturnVoid(pArgList);
if (!pArgList->fHaveLargeArgs)
dtrace_probe(pCtx->idProbe,
pCtx->u.X86.aArgs[0],
pCtx->u.X86.aArgs[1],
pCtx->u.X86.aArgs[2],
pCtx->u.X86.aArgs[3],
pCtx->u.X86.aArgs[4]);
else
{
uint32_t const *auSrcArgs = &pCtx->u.X86.aArgs[0];
uint32_t iSrcArg = 0;
uint32_t iDstArg = 0;
uint64_t au64DstArgs[5];
while ( iDstArg < RT_ELEMENTS(au64DstArgs)
&& iSrcArg < pArgList->cArgs)
{
au64DstArgs[iDstArg] = auSrcArgs[iSrcArg];
if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iDstArg].fType))
au64DstArgs[iDstArg] |= (uint64_t)auSrcArgs[++iSrcArg] << 32;
iSrcArg++;
iDstArg++;
}
while (iDstArg < RT_ELEMENTS(au64DstArgs))
au64DstArgs[iDstArg++] = auSrcArgs[iSrcArg++];
pStackData->u.ProbeFireUser.offArg = iSrcArg - RT_ELEMENTS(au64DstArgs);
dtrace_probe(pCtx->idProbe, au64DstArgs[0], au64DstArgs[1], au64DstArgs[2], au64DstArgs[3], au64DstArgs[4]);
}
#else
dtrace_probe(pCtx->idProbe,
pCtx->u.X86.aArgs[0],
pCtx->u.X86.aArgs[1],
pCtx->u.X86.aArgs[2],
pCtx->u.X86.aArgs[3],
pCtx->u.X86.aArgs[4]);
#endif
}
else if (pCtx->cBits == 64)
{
pStackData->u.ProbeFireUser.pCtx = pCtx;
pStackData->u.ProbeFireUser.offArg = 0;
dtrace_probe(pCtx->idProbe,
pCtx->u.Amd64.aArgs[0],
pCtx->u.Amd64.aArgs[1],
pCtx->u.Amd64.aArgs[2],
pCtx->u.Amd64.aArgs[3],
pCtx->u.Amd64.aArgs[4]);
}
else
AssertFailed();
VBDT_CLEAR_STACK_DATA();
LOG_DTRACE(("%s: returns\n", __FUNCTION__));
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnTracerOpen}
*/
static DECLCALLBACK(int) vboxDtTOps_TracerOpen(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uint32_t uCookie,
uintptr_t uArg, uintptr_t *puSessionData)
{
NOREF(pThis); NOREF(pSession); NOREF(uCookie); NOREF(uArg);
*puSessionData = 0;
return VERR_NOT_SUPPORTED;
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
*/
static DECLCALLBACK(int) vboxDtTOps_TracerIoCtl(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData,
uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
{
NOREF(pThis); NOREF(pSession); NOREF(uSessionData);
NOREF(uCmd); NOREF(uArg); NOREF(piRetVal);
return VERR_NOT_SUPPORTED;
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
*/
static DECLCALLBACK(void) vboxDtTOps_TracerClose(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData)
{
NOREF(pThis); NOREF(pSession); NOREF(uSessionData);
return;
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnProviderRegister}
*/
static DECLCALLBACK(int) vboxDtTOps_ProviderRegister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
{
LOG_DTRACE(("%s: %p %s/%s\n", __FUNCTION__, pThis, pCore->pszModName, pCore->pszName));
AssertReturn(pCore->TracerData.DTrace.idProvider == 0, VERR_INTERNAL_ERROR_3);
PVTGDESCPROVIDER pDesc = pCore->pDesc;
dtrace_pattr_t DtAttrs;
vboxDtVtgConvAttr(&DtAttrs.dtpa_provider, &pDesc->AttrSelf);
vboxDtVtgConvAttr(&DtAttrs.dtpa_mod, &pDesc->AttrModules);
vboxDtVtgConvAttr(&DtAttrs.dtpa_func, &pDesc->AttrFunctions);
vboxDtVtgConvAttr(&DtAttrs.dtpa_name, &pDesc->AttrNames);
vboxDtVtgConvAttr(&DtAttrs.dtpa_args, &pDesc->AttrArguments);
/* Note! DTrace may call us back before dtrace_register returns, so we
have to point it to pCore->TracerData.DTrace.idProvider. */
AssertCompile(sizeof(dtrace_provider_id_t) == sizeof(pCore->TracerData.DTrace.idProvider));
int rc = dtrace_register(pCore->pszName,
&DtAttrs,
DTRACE_PRIV_KERNEL,
NULL /* cred */,
&g_vboxDtVtgProvOps,
pCore,
&pCore->TracerData.DTrace.idProvider);
if (!rc)
{
LOG_DTRACE(("%s: idProvider=%p\n", __FUNCTION__, pCore->TracerData.DTrace.idProvider));
AssertPtr(pCore->TracerData.DTrace.idProvider);
rc = VINF_SUCCESS;
}
else
{
pCore->TracerData.DTrace.idProvider = 0;
rc = RTErrConvertFromErrno(FIX_UEK_RC(rc));
}
LOG_DTRACE(("%s: returns %Rrc\n", __FUNCTION__, rc));
return rc;
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregister}
*/
static DECLCALLBACK(int) vboxDtTOps_ProviderDeregister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
{
uintptr_t idProvider = pCore->TracerData.DTrace.idProvider;
LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pThis, idProvider));
AssertPtrReturn(idProvider, VERR_INTERNAL_ERROR_3);
dtrace_invalidate(idProvider);
int rc = dtrace_unregister(idProvider);
if (!rc)
{
pCore->TracerData.DTrace.idProvider = 0;
rc = VINF_SUCCESS;
}
else
{
AssertMsg(FIX_UEK_RC(rc) == EBUSY, ("%d\n", rc));
pCore->TracerData.DTrace.fZombie = true;
rc = VERR_TRY_AGAIN;
}
LOG_DTRACE(("%s: returns %Rrc\n", __FUNCTION__, rc));
return rc;
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregisterZombie}
*/
static DECLCALLBACK(int) vboxDtTOps_ProviderDeregisterZombie(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
{
uintptr_t idProvider = pCore->TracerData.DTrace.idProvider;
LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pThis, idProvider));
AssertPtrReturn(idProvider, VERR_INTERNAL_ERROR_3);
Assert(pCore->TracerData.DTrace.fZombie);
int rc = dtrace_unregister(idProvider);
if (!rc)
{
pCore->TracerData.DTrace.idProvider = 0;
rc = VINF_SUCCESS;
}
else
{
AssertMsg(FIX_UEK_RC(rc) == EBUSY, ("%d\n", rc));
rc = VERR_TRY_AGAIN;
}
LOG_DTRACE(("%s: returns %Rrc\n", __FUNCTION__, rc));
return rc;
}
/**
* The tracer registration record of the VBox DTrace implementation
*/
static SUPDRVTRACERREG g_VBoxDTraceReg =
{
SUPDRVTRACERREG_MAGIC,
SUPDRVTRACERREG_VERSION,
vboxDtTOps_ProbeFireKernel,
vboxDtTOps_ProbeFireUser,
vboxDtTOps_TracerOpen,
vboxDtTOps_TracerIoCtl,
vboxDtTOps_TracerClose,
vboxDtTOps_ProviderRegister,
vboxDtTOps_ProviderDeregister,
vboxDtTOps_ProviderDeregisterZombie,
SUPDRVTRACERREG_MAGIC
};
/**
* Module initialization code.
*
* @param hMod Opque module handle.
*/
const SUPDRVTRACERREG * VBOXCALL supdrvDTraceInit(void)
{
#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX)
/*
* Resolve the kernel symbols we need.
*/
# ifndef RT_OS_LINUX
RTDBGKRNLINFO hKrnlInfo;
int rc = RTR0DbgKrnlInfoOpen(&hKrnlInfo, 0);
if (RT_FAILURE(rc))
{
SUPR0Printf("supdrvDTraceInit: RTR0DbgKrnlInfoOpen failed with rc=%d.\n", rc);
return NULL;
}
# endif
static const struct
{
const char *pszName;
PFNRT *ppfn;
} s_aDTraceFunctions[] =
{
{ "dtrace_probe", (PFNRT*)&dtrace_probe },
{ "dtrace_probe_create", (PFNRT*)&dtrace_probe_create },
{ "dtrace_probe_lookup", (PFNRT*)&dtrace_probe_lookup },
{ "dtrace_register", (PFNRT*)&dtrace_register },
{ "dtrace_invalidate", (PFNRT*)&dtrace_invalidate },
{ "dtrace_unregister", (PFNRT*)&dtrace_unregister },
};
unsigned i;
for (i = 0; i < RT_ELEMENTS(s_aDTraceFunctions); i++)
{
# ifndef RT_OS_LINUX
rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, s_aDTraceFunctions[i].pszName,
(void **)s_aDTraceFunctions[i].ppfn);
if (RT_FAILURE(rc))
{
SUPR0Printf("supdrvDTraceInit: Failed to resolved '%s' (rc=%Rrc, i=%u).\n", s_aDTraceFunctions[i].pszName, rc, i);
break;
}
# else
unsigned long ulAddr = kallsyms_lookup_name(s_aDTraceFunctions[i].pszName);
if (!ulAddr)
{
SUPR0Printf("supdrvDTraceInit: Failed to resolved '%s' (i=%u).\n", s_aDTraceFunctions[i].pszName, i);
break;
}
SUPR0Printf("supdrvDTraceInit: '%s' -> %lx.\n", s_aDTraceFunctions[i].pszName, ulAddr);
*s_aDTraceFunctions[i].ppfn = (PFNRT)ulAddr;
# endif
}
# ifndef RT_OS_LINUX
RTR0DbgKrnlInfoRelease(hKrnlInfo);
if (RT_FAILURE(rc))
return NULL;
# endif
#endif
return &g_VBoxDTraceReg;
}
#ifndef VBOX_WITH_NATIVE_DTRACE
# error "VBOX_WITH_NATIVE_DTRACE is not defined as it should"
#endif