SUPDrvTracer.cpp revision a66ec044d2a64d926996cd24da5faadccb070be3
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/* $Id$ */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** @file
248c89033c87fed7229aa29bbbc4f4698fb13687vboxsync * VBoxDrv - The VirtualBox Support Driver - Tracer Interface.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/*
248c89033c87fed7229aa29bbbc4f4698fb13687vboxsync * Copyright (C) 2012 Oracle Corporation
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * available from http://www.virtualbox.org. This file is free software;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * General Public License (GPL) as published by the Free Software
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * The contents of this file may alternatively be used under the terms
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * of the Common Development and Distribution License Version 1.0
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * VirtualBox OSE distribution, in which case the provisions of the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * CDDL are applicable instead of those of the GPL.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * You may elect to license modified versions of this file under the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * terms and conditions of either the GPL or the CDDL or both.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync/*******************************************************************************
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync* Header Files *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync*******************************************************************************/
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define LOG_GROUP LOG_GROUP_SUP_DRV
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define SUPDRV_AGNOSTIC
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#include "SUPDrvInternal.h"
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#include <VBox/err.h>
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#include <VBox/log.h>
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#include <VBox/VBoxTpG.h>
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#include <iprt/assert.h>
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#include <iprt/ctype.h>
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#include <iprt/list.h>
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#include <iprt/mem.h>
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#include <iprt/semaphore.h>
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync#include <iprt/thread.h>
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync#include <iprt/param.h>
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync#include <iprt/uuid.h>
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync/*******************************************************************************
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync* Structures and Typedefs *
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync*******************************************************************************/
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync/** Pointer to a user tracer module registration record. */
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsynctypedef struct SUPDRVTRACERUMOD *PSUPDRVTRACERUMOD;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync/**
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * Data for a tracepoint provider.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync */
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsynctypedef struct SUPDRVTPPROVIDER
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync{
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync /** The entry in the provider list for this image. */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync RTLISTNODE ListEntry;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The entry in the per session provider list for this image. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTLISTNODE SessionListEntry;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The core structure. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPDRVVDTPROVIDERCORE Core;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Pointer to the image this provider resides in. NULL if it's a
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * driver. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PSUPDRVLDRIMAGE pImage;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The session this provider is associated with if registered via
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * SUPR0VtgRegisterDrv. NULL if pImage is set. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PSUPDRVSESSION pSession;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The user tracepoint module associated with this provider. NULL if
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * pImage is set. */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync PSUPDRVTRACERUMOD pUmod;
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync /** Used to indicate that we've called pfnProviderDeregistered already and it
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * failed because the provider was busy. Next time we must try
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * pfnProviderDeregisterZombie.
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync *
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * @remarks This does not necessiarly mean the provider is in the zombie
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * list. See supdrvTracerCommonDeregisterImpl. */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync bool fZombie;
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync /** Set if the provider has been successfully registered with the
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * tracer. */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync bool fRegistered;
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync /** The provider name (for logging purposes). */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync char szName[1];
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync} SUPDRVTPPROVIDER;
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync/** Pointer to the data for a tracepoint provider. */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsynctypedef SUPDRVTPPROVIDER *PSUPDRVTPPROVIDER;
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/**
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * User tracer module VTG data copy.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsynctypedef struct SUPDRVVTGCOPY
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync{
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Magic (SUDPRVVTGCOPY_MAGIC). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t u32Magic;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Refernece counter (we expect to share a lot of these). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t cRefs;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The size of the */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t cbStrTab;
ffb50166c9adb4ae583b914d405197035cf890advboxsync /** Image type flags. */
ffb50166c9adb4ae583b914d405197035cf890advboxsync uint32_t fFlags;
ffb50166c9adb4ae583b914d405197035cf890advboxsync /** Hash list entry (SUPDRVDEVEXT::aTrackerUmodHash). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTLISTNODE ListEntry;
ffb50166c9adb4ae583b914d405197035cf890advboxsync /** The VTG object header.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * The rest of the data follows immediately afterwards. First the object,
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * then the probe locations and finally the probe location string table. All
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * pointers are fixed up to point within this data. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync VTGOBJHDR Hdr;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync} SUPDRVVTGCOPY;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Pointer to a VTG object copy. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsynctypedef SUPDRVVTGCOPY *PSUPDRVVTGCOPY;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Magic value for SUPDRVVTGCOPY. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define SUDPRVVTGCOPY_MAGIC UINT32_C(0x00080386)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/**
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * User tracer module registration record.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsynctypedef struct SUPDRVTRACERUMOD
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync{
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Magic (SUPDRVTRACERUMOD_MAGIC). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t u32Magic;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** List entry. This is anchored in SUPDRVSESSION::UmodList. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTLISTNODE ListEntry;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The address of the ring-3 VTG header. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTR3PTR R3PtrVtgHdr;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Pointer to the ring-0 copy of the VTG data. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PSUPDRVVTGCOPY pVtgCopy;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The memory object that locks down the user memory. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTR0MEMOBJ hMemObjLock;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The memory object that maps the locked memory into kernel space. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTR0MEMOBJ hMemObjMap;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Pointer to the probe enabled-count array within the mapping. */
248c89033c87fed7229aa29bbbc4f4698fb13687vboxsync uint32_t *pacProbeEnabled;
248c89033c87fed7229aa29bbbc4f4698fb13687vboxsync /** Pointer to the probe location array within the mapping. */
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync void *pvProbeLocs;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The address of the ring-3 probe locations. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTR3PTR R3PtrProbeLocs;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The lookup table index. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint8_t iLookupTable;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The module bit count. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint8_t cBits;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The size of a probe location record. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint8_t cbProbeLoc;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The number of probe locations. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t cProbeLocs;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Ring-0 probe location info. */
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync SUPDRVPROBELOC aProbeLocs[1];
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync} SUPDRVTRACERUMOD;
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync/** Magic value for SUPDRVVTGCOPY. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define SUPDRVTRACERUMOD_MAGIC UINT32_C(0x00080486)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/*******************************************************************************
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync* Defined Constants And Macros *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync*******************************************************************************/
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync/** Simple SUPR0Printf-style logging. */
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync#ifdef DEBUG_bird
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync# define LOG_TRACER(a_Args) SUPR0Printf a_Args
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync#else
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync# define LOG_TRACER(a_Args) do { } while (0)
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync#endif
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync/*******************************************************************************
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync* Global Variables *
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync*******************************************************************************/
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync/** The address of the current probe fire routine for kernel mode. */
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsyncPFNRT g_pfnSupdrvProbeFireKernel = supdrvTracerProbeFireStub;
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync
3fb3de312d1ff675e0f7cc62a7d46cbb1d5d9353vboxsync/*******************************************************************************
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync* Internal Functions *
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync*******************************************************************************/
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsyncstatic void supdrvVtgReleaseObjectCopy(PSUPDRVDEVEXT pDevExt, PSUPDRVVTGCOPY pThis);
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync/**
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync * Validates a VTG string against length and characterset limitations.
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync *
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync * @returns VINF_SUCCESS, VERR_SUPDRV_VTG_BAD_STRING or
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync * VERR_SUPDRV_VTG_STRING_TOO_LONG.
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync * @param psz The string.
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync */
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsyncstatic int supdrvVtgValidateString(const char *psz)
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync{
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync size_t off = 0;
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync while (off < _4K)
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync {
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync char const ch = psz[off++];
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync if (!ch)
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync return VINF_SUCCESS;
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync if ( !RTLocCIsAlNum(ch)
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync && ch != ' '
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync && ch != '_'
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync && ch != '-'
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync && ch != '('
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync && ch != ')'
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync && ch != ','
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync && ch != '*'
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync && ch != '&'
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync )
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync {
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync /*RTAssertMsg2("off=%u '%s'\n", off, psz);*/
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync return VERR_SUPDRV_VTG_BAD_STRING;
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync }
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync }
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync return VERR_SUPDRV_VTG_STRING_TOO_LONG;
3fb3de312d1ff675e0f7cc62a7d46cbb1d5d9353vboxsync}
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Used by the validation code below. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define MY_CHECK_RET(a_Expr, a_rc) \
11b175175a0ed424b8e8354acda681ad0adde0f8vboxsync MY_CHECK_MSG_RET(a_Expr, ("%s: Validation failed on line " RT_XSTR(__LINE__) ": " #a_Expr "\n", __FUNCTION__), a_rc)
11b175175a0ed424b8e8354acda681ad0adde0f8vboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Used by the validation code below. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define MY_CHECK_MSG_RET(a_Expr, a_PrintfArgs, a_rc) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync do { if (RT_UNLIKELY(!(a_Expr))) { SUPR0Printf a_PrintfArgs; return (a_rc); } } while (0)
11b175175a0ed424b8e8354acda681ad0adde0f8vboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Used by the validation code below. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define MY_WITHIN_IMAGE(p, rc) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync do { \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pbImage) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync { \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ((uintptr_t)(p) - (uintptr_t)pbImage > cbImage) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync { \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidate: " #rc " - p=%p pbImage=%p cbImage=%#zxline=%u %s\n", \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync p, pbImage, cbImage, #p); \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return (rc); \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync } \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync } \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else if (!RT_VALID_PTR(p)) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return (rc); \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync } while (0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/**
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Validates the VTG object header.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @returns VBox status code.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pVtgHdr The header.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param uVtgHdrAddr The address where the header is actually
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * loaded.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param cbVtgObj The alleged size of the header.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pbImage The image base, if available.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param cbImage The image size, if available.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param fUmod Whether this is a user module.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic int supdrvVtgValidateHdr(PVTGOBJHDR pVtgHdr, RTUINTPTR uVtgHdrAddr, const uint8_t *pbImage, size_t cbImage, bool fUmod)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync{
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync struct VTGAREAS
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t off;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t cb;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync } const *paAreas;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync unsigned cAreas;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync unsigned i;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t cbVtgObj;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t off;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define MY_VALIDATE_SIZE(cb, cMin, cMax, cbUnit, rcBase) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync do { \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ((cb) < (cMin) * (cbUnit)) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync { \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidateHdr: " #rcBase "_TOO_FEW - cb=%#zx cMin=%#zx cbUnit=%#zx line=%u %s\n", \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync (size_t)(cb), (size_t)(cMin), (size_t)cbUnit, __LINE__, #cb); \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return rcBase ## _TOO_FEW; \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync } \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ((cb) >= (cMax) * (cbUnit)) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync { \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidateHdr: " #rcBase "_TOO_MUCH - cb=%#zx cMax=%#zx cbUnit=%#zx line=%u %s\n", \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync (size_t)(cb), (size_t)(cMax), (size_t)cbUnit, __LINE__, #cb); \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return rcBase ## _TOO_MUCH; \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync } \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ((cb) / (cbUnit) * (cbUnit) != (cb)) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync { \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidateHdr: " #rcBase "_NOT_MULTIPLE - cb=%#zx cbUnit=%#zx line=%u %s\n", \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync (size_t)(cb), (size_t)cbUnit, __LINE__, #cb); \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return rcBase ## _NOT_MULTIPLE; \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync } \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync } while (0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define MY_VALIDATE_OFF(off, cb, cMin, cMax, cbUnit, cbAlign, rcBase) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync do { \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ( (cb) >= cbVtgObj \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync || off > cbVtgObj - (cb) ) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync { \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidateHdr: " #rcBase "_OFF - off=%#x cb=%#x pVtgHdr=%p cbVtgHdr=%#zx line=%u %s\n", \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync (off), (cb), pVtgHdr, cbVtgObj, __LINE__, #off); \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return rcBase ## _OFF; \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync } \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (RT_ALIGN(off, cbAlign) != (off)) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync { \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidateHdr: " #rcBase "_OFF - off=%#x align=%#zx line=%u %s\n", \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync (off), (size_t)(cbAlign), __LINE__, #off); \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return rcBase ## _OFF; \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync } \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_SIZE(cb, cMin, cMax, cbUnit, rcBase); \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync } while (0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Make sure both pbImage and cbImage are NULL/0 if one if of them is.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (!pbImage || !cbImage)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pbImage = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync cbImage = 0;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync cbVtgObj = pVtgHdr->cbObj;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_WITHIN_IMAGE(pVtgHdr, VERR_SUPDRV_VTG_BAD_HDR_PTR);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync cbVtgObj = pVtgHdr->cbObj;
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync MY_WITHIN_IMAGE((uint8_t *)pVtgHdr + cbVtgObj - 1, VERR_SUPDRV_VTG_BAD_HDR_PTR);
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (cbVtgObj > _1M)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_TRACER_TOO_LARGE - cbVtgObj=%#x\n", cbVtgObj);
b8bb9c9f6b8ebfd0a7d6df0c0289f9fe80241750vboxsync return VERR_SUPDRV_TRACER_TOO_LARGE;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync /*
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * Set the probe location array offset and size members.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync if (!pVtgHdr->offProbeLocs)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync uint64_t u64Tmp = pVtgHdr->uProbeLocsEnd.u64 - pVtgHdr->uProbeLocs.u64;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync if (u64Tmp >= UINT32_MAX)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH - u64Tmp=%#llx ProbeLocs=%#llx ProbeLocsEnd=%#llx\n",
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync u64Tmp, pVtgHdr->uProbeLocs.u64, pVtgHdr->uProbeLocsEnd.u64);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync return VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync pVtgHdr->cbProbeLocs = (uint32_t)u64Tmp;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync u64Tmp = pVtgHdr->uProbeLocs.u64 - uVtgHdrAddr;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#ifdef RT_OS_DARWIN
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /* The loader and/or ld64-97.17 seems not to generate fixups for our
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync __VTGObj section. Detect this by comparing them with the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync u64VtgObjSectionStart member and assume max image size of 4MB. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ( (int64_t)u64Tmp != (int32_t)u64Tmp
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && pVtgHdr->u64VtgObjSectionStart != uVtgHdrAddr
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && pVtgHdr->u64VtgObjSectionStart < _4M
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync && pVtgHdr->uProbeLocsEnd.u64 < _4M
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && !fUmod)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync uint64_t offDelta = uVtgHdrAddr - pVtgHdr->u64VtgObjSectionStart;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pVtgHdr->uProbeLocs.u64 += offDelta;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pVtgHdr->uProbeLocsEnd.u64 += offDelta;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync u64Tmp += offDelta;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#endif
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ((int64_t)u64Tmp != (int32_t)u64Tmp)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
510567648d46488f4166e5f69ffffe3eeeeec4d9vboxsync SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_PTR - u64Tmp=%#llx uProbeLocs=%#llx uVtgHdrAddr=%RTptr\n",
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync u64Tmp, pVtgHdr->uProbeLocs.u64, uVtgHdrAddr);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_VTG_BAD_HDR_PTR;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pVtgHdr->offProbeLocs = (int32_t)u64Tmp;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * The non-area description fields.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)))
ebe46865faa75932265b29148843c6c54ffcb6a4vboxsync return VERR_SUPDRV_VTG_MAGIC;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ( pVtgHdr->cBits != ARCH_BITS
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && ( !fUmod
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync || ( pVtgHdr->cBits != 32
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && pVtgHdr->cBits != 64)) )
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_VTG_BITS;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_CHECK_RET(pVtgHdr->au32Reserved1[0] == 0, VERR_SUPDRV_VTG_BAD_HDR_MISC);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_CHECK_RET(pVtgHdr->au32Reserved1[1] == 0, VERR_SUPDRV_VTG_BAD_HDR_MISC);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_CHECK_RET(!RTUuidIsNull(&pVtgHdr->Uuid), VERR_SUPDRV_VTG_BAD_HDR_MISC);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Check the individual area descriptors.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_OFF(pVtgHdr->offStrTab, pVtgHdr->cbStrTab, 4, _1M, sizeof(char), sizeof(uint8_t), VERR_SUPDRV_VTG_BAD_HDR);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_OFF(pVtgHdr->offArgLists, pVtgHdr->cbArgLists, 1, _32K, sizeof(uint32_t), sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_OFF(pVtgHdr->offProbes, pVtgHdr->cbProbes, 1, _32K, sizeof(VTGDESCPROBE), sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_OFF(pVtgHdr->offProviders, pVtgHdr->cbProviders, 1, 16, sizeof(VTGDESCPROVIDER), sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync MY_VALIDATE_OFF(pVtgHdr->offProbeEnabled, pVtgHdr->cbProbeEnabled, 1, _32K, sizeof(uint32_t), sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (!fUmod)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_WITHIN_IMAGE(pVtgHdr->uProbeLocs.p, VERR_SUPDRV_VTG_BAD_HDR_PTR);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_WITHIN_IMAGE(pVtgHdr->uProbeLocsEnd.p, VERR_SUPDRV_VTG_BAD_HDR_PTR);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_SIZE( pVtgHdr->cbProbeLocs, 1, _128K, sizeof(VTGPROBELOC), VERR_SUPDRV_VTG_BAD_HDR);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pVtgHdr->cBits == 32)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_SIZE( pVtgHdr->cbProbeLocs, 1, _8K, sizeof(VTGPROBELOC32), VERR_SUPDRV_VTG_BAD_HDR);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_SIZE( pVtgHdr->cbProbeLocs, 1, _8K, sizeof(VTGPROBELOC64), VERR_SUPDRV_VTG_BAD_HDR);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync /* Will check later that offProbeLocs are following closely on the
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync enable count array, so no need to validate the offset here. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * Some additional consistency checks.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ( pVtgHdr->uProbeLocsEnd.u64 - pVtgHdr->uProbeLocs.u64 != pVtgHdr->cbProbeLocs
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync || (int64_t)(pVtgHdr->uProbeLocs.u64 - uVtgHdrAddr) != pVtgHdr->offProbeLocs)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - uProbeLocs=%#llx uProbeLocsEnd=%#llx offProbeLocs=%#llx cbProbeLocs=%#x uVtgHdrAddr=%RTptr\n",
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pVtgHdr->uProbeLocs.u64, pVtgHdr->uProbeLocsEnd.u64, pVtgHdr->offProbeLocs, pVtgHdr->cbProbeLocs, uVtgHdrAddr);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_VTG_BAD_HDR_MISC;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pVtgHdr->cbProbes / sizeof(VTGDESCPROBE) != pVtgHdr->cbProbeEnabled / sizeof(uint32_t))
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - cbProbeEnabled=%#zx cbProbes=%#zx\n",
b8bb9c9f6b8ebfd0a7d6df0c0289f9fe80241750vboxsync pVtgHdr->cbProbeEnabled, pVtgHdr->cbProbes);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync return VERR_SUPDRV_VTG_BAD_HDR_MISC;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync /*
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * Check that there are no overlapping areas. This is a little bit ugly...
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync paAreas = (struct VTGAREAS const *)&pVtgHdr->offStrTab;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync cAreas = pVtgHdr->offProbeLocs >= 0 ? 6 : 5;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync off = sizeof(VTGOBJHDR);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync for (i = 0; i < cAreas; i++)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (paAreas[i].off < off)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - overlapping areas %d and %d\n", i, i-1);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_VTG_BAD_HDR_MISC;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync off = paAreas[i].off + paAreas[i].cb;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ( pVtgHdr->offProbeLocs > 0
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && (uint32_t)-pVtgHdr->offProbeLocs < pVtgHdr->cbProbeLocs)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - probe locations overlaps the header\n");
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync return VERR_SUPDRV_VTG_BAD_HDR_MISC;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Check that the object size is correct.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pVtgHdr->cbObj != pVtgHdr->offProbeEnabled + pVtgHdr->cbProbeEnabled)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - bad header size %#x, expected %#x\n",
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pVtgHdr->cbObj, pVtgHdr->offProbeEnabled + pVtgHdr->cbProbeEnabled);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_VTG_BAD_HDR_MISC;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VINF_SUCCESS;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#undef MY_VALIDATE_OFF
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#undef MY_VALIDATE_SIZE
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync}
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync/**
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync * Validates the VTG data.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @returns VBox status code.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pVtgHdr The VTG object header of the data to validate.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param uVtgHdrAddr The address where the header is actually
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * loaded.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pbImage The image base. For validating the probe
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * locations.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param cbImage The image size to go with @a pbImage.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param fUmod Whether this is a user module.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic int supdrvVtgValidate(PVTGOBJHDR pVtgHdr, RTUINTPTR uVtgHdrAddr, const uint8_t *pbImage, size_t cbImage, bool fUmod)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync{
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uintptr_t offTmp;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync uintptr_t i;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync uintptr_t cProviders;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync int rc;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (!pbImage || !cbImage)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pbImage = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync cbImage = 0;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync#define MY_VALIDATE_STR(a_offStrTab) \
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync do { \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ((a_offStrTab) >= pVtgHdr->cbStrTab) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_VTG_STRTAB_OFF; \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rc = supdrvVtgValidateString((char *)pVtgHdr + pVtgHdr->offStrTab + (a_offStrTab)); \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (rc != VINF_SUCCESS) \
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync return rc; \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync } while (0)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync#define MY_VALIDATE_ATTR(Attr) \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync do { \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ((Attr).u8Code <= (uint8_t)kVTGStability_Invalid || (Attr).u8Code >= (uint8_t)kVTGStability_End) \
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync return VERR_SUPDRV_VTG_BAD_ATTR; \
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync if ((Attr).u8Data <= (uint8_t)kVTGStability_Invalid || (Attr).u8Data >= (uint8_t)kVTGStability_End) \
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync return VERR_SUPDRV_VTG_BAD_ATTR; \
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ((Attr).u8DataDep <= (uint8_t)kVTGClass_Invalid || (Attr).u8DataDep >= (uint8_t)kVTGClass_End) \
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync return VERR_SUPDRV_VTG_BAD_ATTR; \
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync } while (0)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync /*
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * The header.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rc = supdrvVtgValidateHdr(pVtgHdr, uVtgHdrAddr, pbImage, cbImage, fUmod);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (RT_FAILURE(rc))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return rc;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Validate the providers.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync cProviders = i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync while (i-- > 0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PCVTGDESCPROVIDER pProvider = (PCVTGDESCPROVIDER)((uintptr_t)pVtgHdr + pVtgHdr->offProviders) + i;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync MY_VALIDATE_STR(pProvider->offName);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync MY_CHECK_RET(pProvider->iFirstProbe < pVtgHdr->cbProbeEnabled / sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_PROVIDER);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync MY_CHECK_RET((uint32_t)pProvider->iFirstProbe + pProvider->cProbes <= pVtgHdr->cbProbeEnabled / sizeof(uint32_t),
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync VERR_SUPDRV_VTG_BAD_PROVIDER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_ATTR(pProvider->AttrSelf);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_ATTR(pProvider->AttrModules);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_ATTR(pProvider->AttrFunctions);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_ATTR(pProvider->AttrNames);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_ATTR(pProvider->AttrArguments);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_CHECK_RET(pProvider->bReserved == 0, VERR_SUPDRV_VTG_BAD_PROVIDER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Validate probes.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync i = pVtgHdr->cbProbes / sizeof(VTGDESCPROBE);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync while (i-- > 0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PCVTGDESCPROBE pProbe = (PCVTGDESCPROBE)( (uintptr_t)pVtgHdr + pVtgHdr->offProbes) + i;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PCVTGDESCPROVIDER pProvider = (PCVTGDESCPROVIDER)((uintptr_t)pVtgHdr + pVtgHdr->offProviders) + pProbe->idxProvider;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PCVTGDESCARGLIST pArgList = (PCVTGDESCARGLIST)( (uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbe->offArgList );
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync unsigned iArg;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync bool fHaveLargeArgs;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_STR(pProbe->offName);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_CHECK_RET(pProbe->offArgList < pVtgHdr->cbArgLists, VERR_SUPDRV_VTG_BAD_PROBE);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_CHECK_RET((pProbe->offArgList & 3) == 0, VERR_SUPDRV_VTG_BAD_PROBE);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_CHECK_RET(pProbe->idxEnabled == i, VERR_SUPDRV_VTG_BAD_PROBE); /* The lists are parallel. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_CHECK_RET(pProbe->idxProvider < cProviders, VERR_SUPDRV_VTG_BAD_PROBE);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_CHECK_RET(i - pProvider->iFirstProbe < pProvider->cProbes, VERR_SUPDRV_VTG_BAD_PROBE);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pProbe->offObjHdr != (intptr_t)pVtgHdr - (intptr_t)pProbe)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - iProbe=%u offObjHdr=%d expected %zd\n",
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync i, pProbe->offObjHdr, (intptr_t)pVtgHdr - (intptr_t)pProbe);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_VTG_BAD_PROBE;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /* The referenced argument list. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pArgList->cArgs > 16)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - iProbe=%u cArgs=%u\n", i, pArgList->cArgs);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_VTG_BAD_ARGLIST;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pArgList->fHaveLargeArgs >= 2)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - iProbe=%u fHaveLargeArgs=%d\n", i, pArgList->fHaveLargeArgs);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_VTG_BAD_ARGLIST;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ( pArgList->abReserved[0]
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync || pArgList->abReserved[1])
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - reserved MBZ iProbe=%u\n", i);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_VTG_BAD_ARGLIST;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync fHaveLargeArgs = false;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync iArg = pArgList->cArgs;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync while (iArg-- > 0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t const fType = pArgList->aArgs[iArg].fType;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (fType & ~VTG_TYPE_VALID_MASK)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - fType=%#x iArg=%u iProbe=%u (#0)\n", fType, iArg, i);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync switch (pArgList->aArgs[iArg].fType & VTG_TYPE_SIZE_MASK)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync case 0:
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pArgList->aArgs[iArg].fType & VTG_TYPE_FIXED_SIZED)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - fType=%#x iArg=%u iProbe=%u (#1)\n", fType, iArg, i);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync break;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync case 1: case 2: case 4: case 8:
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync break;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync default:
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - fType=%#x iArg=%u iProbe=%u (#2)\n", fType, iArg, i);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync fHaveLargeArgs = true;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_VALIDATE_STR(pArgList->aArgs[iArg].offType);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ((uint8_t)fHaveLargeArgs != pArgList->fHaveLargeArgs)
c99b597540585068d22dde4c9f74730305f24097vboxsync {
c99b597540585068d22dde4c9f74730305f24097vboxsync SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - iProbe=%u fHaveLargeArgs=%d expected %d\n",
c99b597540585068d22dde4c9f74730305f24097vboxsync i, pArgList->fHaveLargeArgs, fHaveLargeArgs);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return VERR_SUPDRV_VTG_BAD_PROBE;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Check that pacProbeEnabled is all zeros.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t const *pcProbeEnabled = (uint32_t const *)((uintptr_t)pVtgHdr + pVtgHdr->offProbeEnabled);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync i = pVtgHdr->cbProbeEnabled / sizeof(uint32_t);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync while (i-- > 0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_CHECK_RET(pcProbeEnabled[0] == 0, VERR_SUPDRV_VTG_BAD_PROBE_ENABLED);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Probe locations.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PVTGPROBELOC paProbeLocs = (PVTGPROBELOC)((intptr_t)pVtgHdr + pVtgHdr->offProbeLocs);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync i = pVtgHdr->cbProbeLocs / sizeof(VTGPROBELOC);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync while (i-- > 0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_CHECK_RET(paProbeLocs[i].uLine < _1G, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_CHECK_RET(paProbeLocs[i].fEnabled == false, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync MY_CHECK_RET(paProbeLocs[i].idProbe == 0, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
c99b597540585068d22dde4c9f74730305f24097vboxsync MY_WITHIN_IMAGE(paProbeLocs[i].pszFunction, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync offTmp = (uintptr_t)paProbeLocs[i].pProbe - (uintptr_t)pVtgHdr->offProbes - (uintptr_t)pVtgHdr;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#ifdef RT_OS_DARWIN /* See header validation code. */
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync if ( offTmp >= pVtgHdr->cbProbes
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync && pVtgHdr->u64VtgObjSectionStart != uVtgHdrAddr
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && pVtgHdr->u64VtgObjSectionStart < _4M
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && (uintptr_t)paProbeLocs[i].pProbe < _4M
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync && !fUmod )
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
b8bb9c9f6b8ebfd0a7d6df0c0289f9fe80241750vboxsync uint64_t offDelta = uVtgHdrAddr - pVtgHdr->u64VtgObjSectionStart;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync paProbeLocs[i].pProbe = (PVTGDESCPROBE)((uintptr_t)paProbeLocs[i].pProbe + offDelta);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync offTmp += offDelta;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync#endif
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync MY_CHECK_RET(offTmp < pVtgHdr->cbProbes, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync MY_CHECK_RET(offTmp / sizeof(VTGDESCPROBE) * sizeof(VTGDESCPROBE) == offTmp, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync return VINF_SUCCESS;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync}
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#undef MY_VALIDATE_STR
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync#undef MY_VALIDATE_ATTR
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#undef MY_WITHIN_IMAGE
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/**
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Gets a string from the string table.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @returns Pointer to the string.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pVtgHdr The VTG object header.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param offStrTab The string table offset.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsyncstatic const char *supdrvVtgGetString(PVTGOBJHDR pVtgHdr, uint32_t offStrTab)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync{
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync Assert(offStrTab < pVtgHdr->cbStrTab);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync return (char *)pVtgHdr + pVtgHdr->offStrTab + offStrTab;
b8bb9c9f6b8ebfd0a7d6df0c0289f9fe80241750vboxsync}
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync/**
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * Frees the provider structure and associated resources.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync *
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * @param pProv The provider to free.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsyncstatic void supdrvTracerFreeProvider(PSUPDRVTPPROVIDER pProv)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync{
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync LOG_TRACER(("Freeing tracepoint provider '%s' / %p\n", pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync pProv->fRegistered = false;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync pProv->fZombie = true;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync pProv->Core.pDesc = NULL;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync pProv->Core.pHdr = NULL;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync pProv->Core.paProbeLocsRO = NULL;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync pProv->Core.pvProbeLocsEn = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.pacProbeEnabled = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.paR0ProbeLocs = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.paR0Probes = NULL;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync RT_ZERO(pProv->Core.TracerData);
510567648d46488f4166e5f69ffffe3eeeeec4d9vboxsync RTMemFree(pProv);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync}
510567648d46488f4166e5f69ffffe3eeeeec4d9vboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/**
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * Unlinks and deregisters a provider.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * If the provider is still busy, it will be put in the zombie list.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync *
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * @param pDevExt The device extension.
b8bb9c9f6b8ebfd0a7d6df0c0289f9fe80241750vboxsync * @param pProv The provider.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync *
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * @remarks The caller owns mtxTracer.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsyncstatic void supdrvTracerDeregisterVtgObj(PSUPDRVDEVEXT pDevExt, PSUPDRVTPPROVIDER pProv)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync{
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync int rc;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync RTListNodeRemove(&pProv->ListEntry);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync if (pProv->pSession)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync RTListNodeRemove(&pProv->SessionListEntry);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTListInit(&pProv->SessionListEntry);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->pSession->cTpProviders--;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (!pProv->fRegistered || !pDevExt->pTracerOps)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rc = VINF_SUCCESS;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rc = pDevExt->pTracerOps->pfnProviderDeregister(pDevExt->pTracerOps, &pProv->Core);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (RT_SUCCESS(rc))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync supdrvTracerFreeProvider(pProv);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->fZombie = true;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->pImage = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->pSession = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->pUmod = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.pDesc = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.pHdr = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.paProbeLocsRO = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.pvProbeLocsEn = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.pacProbeEnabled = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.paR0ProbeLocs = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTListAppend(&pDevExt->TracerProviderZombieList, &pProv->ListEntry);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync LOG_TRACER(("Invalidated provider '%s' / %p and put it on the zombie list (rc=%Rrc)\n",
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync}
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/**
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * Processes the zombie list.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pDevExt The device extension.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsyncstatic void supdrvTracerProcessZombies(PSUPDRVDEVEXT pDevExt)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync{
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PSUPDRVTPPROVIDER pProv, pProvNext;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync RTSemFastMutexRequest(pDevExt->mtxTracer);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync int rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (RT_SUCCESS(rc))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTListNodeRemove(&pProv->ListEntry);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync supdrvTracerFreeProvider(pProv);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync}
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/**
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Unregisters all providers, including zombies, waiting for busy providers to
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * go idle and unregister smoothly.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * This may block.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pDevExt The device extension.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic void supdrvTracerRemoveAllProviders(PSUPDRVDEVEXT pDevExt)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync{
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t i;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PSUPDRVTPPROVIDER pProv;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PSUPDRVTPPROVIDER pProvNext;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Unregister all probes (there should only be one).
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTSemFastMutexRequest(pDevExt->mtxTracer);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync supdrvTracerDeregisterVtgObj(pDevExt, pProv);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Try unregister zombies now, sleep on busy ones and tracer opens.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync for (i = 0; ; i++)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync bool fEmpty;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTSemFastMutexRequest(pDevExt->mtxTracer);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync /* Zombies */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync int rc;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync LOG_TRACER(("supdrvTracerRemoveAllProviders: Attemting to unregister '%s' / %p...\n",
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pDevExt->pTracerOps)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rc = VINF_SUCCESS;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (!rc)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTListNodeRemove(&pProv->ListEntry);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync supdrvTracerFreeProvider(pProv);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else if (!(i & 0xf))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvTracerRemoveAllProviders: Waiting on busy provider '%s' / %p (rc=%d)\n",
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync LOG_TRACER(("supdrvTracerRemoveAllProviders: Failed to unregister provider '%s' / %p - rc=%d\n",
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync fEmpty = RTListIsEmpty(&pDevExt->TracerProviderZombieList);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /* Tracer opens. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ( pDevExt->cTracerOpens
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && pDevExt->pTracerOps)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync fEmpty = false;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (!(i & 0xf))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUPR0Printf("supdrvTracerRemoveAllProviders: Waiting on %u opens\n", pDevExt->cTracerOpens);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync LOG_TRACER(("supdrvTracerRemoveAllProviders: Waiting on %u opens\n", pDevExt->cTracerOpens));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync if (fEmpty)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync break;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /* Delay...*/
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync RTThreadSleep(1000);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync}
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/**
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Registers the VTG tracepoint providers of a driver.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @returns VBox status code.
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync * @param pszName The driver name.
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync * @param pVtgHdr The VTG object header.
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync * @param pImage The image if applicable.
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync * @param pSession The session if applicable.
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync * @param pUmod The associated user tracepoint module if
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync * applicable.
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync * @param pszModName The module name.
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync */
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsyncstatic int supdrvTracerRegisterVtgObj(PSUPDRVDEVEXT pDevExt, PVTGOBJHDR pVtgHdr, PSUPDRVLDRIMAGE pImage,
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync PSUPDRVSESSION pSession, PSUPDRVTRACERUMOD pUmod, const char *pszModName)
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync{
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync int rc;
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync uintptr_t i;
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync PSUPDRVTPPROVIDER pProv;
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync size_t cchModName;
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync /*
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync * Validate input.
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync */
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync AssertPtrNullReturn(pImage, VERR_INVALID_POINTER);
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync AssertPtrNullReturn(pSession, VERR_INVALID_POINTER);
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync AssertPtrReturn(pszModName, VERR_INVALID_POINTER);
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync cchModName = strlen(pszModName);
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync if (pImage)
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync rc = supdrvVtgValidate(pVtgHdr, (uintptr_t)pVtgHdr,
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync (const uint8_t *)pImage->pvImage, pImage->cbImageBits,
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync false /*fUmod*/);
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync else
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync rc = supdrvVtgValidate(pVtgHdr, (uintptr_t)pVtgHdr, NULL, 0, pUmod != NULL);
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync if (RT_FAILURE(rc))
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync return rc;
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync /*
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync * Check that there aren't any obvious duplicates.
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync * (Yes, this isn't race free, but it's good enough for now.)
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (RT_FAILURE(rc))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return rc;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pImage || !pSession || pSession->R0Process == NIL_RTPROCESS)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTListForEach(&pDevExt->TracerProviderList, pProv, SUPDRVTPPROVIDER, ListEntry)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pProv->Core.pHdr == pVtgHdr)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rc = VERR_SUPDRV_VTG_ALREADY_REGISTERED;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync break;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ( pProv->pSession == pSession
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && pProv->pImage == pImage)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rc = VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync break;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTListForEach(&pSession->TpProviders, pProv, SUPDRVTPPROVIDER, SessionListEntry)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pProv->Core.pHdr == pVtgHdr)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync rc = VERR_SUPDRV_VTG_ALREADY_REGISTERED;
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync break;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (RT_FAILURE(rc))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return rc;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Register the providers.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync while (i-- > 0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PVTGDESCPROVIDER pDesc = (PVTGDESCPROVIDER)((uintptr_t)pVtgHdr + pVtgHdr->offProviders) + i;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync const char *pszName = supdrvVtgGetString(pVtgHdr, pDesc->offName);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync size_t const cchName = strlen(pszName) + (pUmod ? 16 : 0);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv = (PSUPDRVTPPROVIDER)RTMemAllocZ(RT_OFFSETOF(SUPDRVTPPROVIDER, szName[cchName + 1 + cchModName + 1]));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pProv)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.pszName = &pProv->szName[0];
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.pszModName = &pProv->szName[cchName + 1];
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.pDesc = pDesc;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.pHdr = pVtgHdr;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.paProbeLocsRO = (PCVTGPROBELOC )((uintptr_t)pVtgHdr + pVtgHdr->offProbeLocs);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (!pUmod)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.pvProbeLocsEn = (void *)((uintptr_t)pVtgHdr + pVtgHdr->offProbeLocs);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.pacProbeEnabled = (uint32_t *)((uintptr_t)pVtgHdr + pVtgHdr->offProbeEnabled);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.paR0ProbeLocs = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.paR0Probes = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.cbProbeLocsEn = sizeof(VTGPROBELOC);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.cBits = ARCH_BITS;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.fUmod = false;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync {
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync pProv->Core.pvProbeLocsEn = pUmod->pvProbeLocs;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.pacProbeEnabled = pUmod->pacProbeEnabled;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.paR0ProbeLocs = &pUmod->aProbeLocs[0];
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync pProv->Core.paR0Probes = (PSUPDRVPROBEINFO)&pUmod->aProbeLocs[pUmod->cProbeLocs];
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync pProv->Core.cbProbeLocsEn = pUmod->cbProbeLoc;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.cBits = pUmod->cBits;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->Core.fUmod = true;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
ffb50166c9adb4ae583b914d405197035cf890advboxsync pProv->pImage = pImage;
ffb50166c9adb4ae583b914d405197035cf890advboxsync pProv->pSession = pSession;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->pUmod = pUmod;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->fZombie = false;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pProv->fRegistered = true;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync if (!pUmod)
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync memcpy(pProv->szName, pszName, cchName + 1);
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync else
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync RTStrPrintf(pProv->szName, cchName + 1, "%s%u", pszName, (uint32_t)pSession->Process);
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync memcpy((void *)pProv->Core.pszModName, pszModName, cchModName + 1);
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync /*
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * Do the actual registration and list manipulations while holding
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * down the lock.
b8bb9c9f6b8ebfd0a7d6df0c0289f9fe80241750vboxsync */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync if (RT_SUCCESS(rc))
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync if ( pDevExt->pTracerOps
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync && !pDevExt->fTracerUnloading)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync rc = pDevExt->pTracerOps->pfnProviderRegister(pDevExt->pTracerOps, &pProv->Core);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync else
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync pProv->fRegistered = false;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync rc = VINF_SUCCESS;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (RT_SUCCESS(rc))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTListAppend(&pDevExt->TracerProviderList, &pProv->ListEntry);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pSession)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
ebe46865faa75932265b29148843c6c54ffcb6a4vboxsync RTListAppend(&pSession->TpProviders, &pProv->SessionListEntry);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pSession->cTpProviders++;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTListInit(&pProv->SessionListEntry);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync LOG_TRACER(("Registered tracepoint provider '%s' in '%s' -> %p\n",
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pProv->szName, pszModName, pProv->Core.TracerData.DTrace.idProvider));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync LOG_TRACER(("Failed to register tracepoint provider '%s' in '%s' -> %Rrc\n",
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync pProv->szName, pszModName, rc));
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync rc = VERR_NO_MEMORY;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync /*
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * In case of failure, we have to undo any providers we already
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * managed to register.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync if (RT_FAILURE(rc))
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync PSUPDRVTPPROVIDER pProvNext;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync if (pProv)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync supdrvTracerFreeProvider(pProv);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync RTSemFastMutexRequest(pDevExt->mtxTracer);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync if (pImage)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
b8bb9c9f6b8ebfd0a7d6df0c0289f9fe80241750vboxsync RTListForEachReverseSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
d3b1b01528fe21777281edf167f8deca06f86e39vboxsync if (pProv->Core.pHdr == pVtgHdr)
d3b1b01528fe21777281edf167f8deca06f86e39vboxsync supdrvTracerDeregisterVtgObj(pDevExt, pProv);
d3b1b01528fe21777281edf167f8deca06f86e39vboxsync }
d3b1b01528fe21777281edf167f8deca06f86e39vboxsync }
d3b1b01528fe21777281edf167f8deca06f86e39vboxsync else
d3b1b01528fe21777281edf167f8deca06f86e39vboxsync {
d3b1b01528fe21777281edf167f8deca06f86e39vboxsync RTListForEachSafe(&pSession->TpProviders, pProv, pProvNext, SUPDRVTPPROVIDER, SessionListEntry)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync if (pProv->Core.pHdr == pVtgHdr)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync supdrvTracerDeregisterVtgObj(pDevExt, pProv);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync }
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync return rc;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync return VINF_SUCCESS;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync}
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/**
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Registers the VTG tracepoint providers of a driver.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @returns VBox status code.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pSession The support driver session handle.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pVtgHdr The VTG header.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pszName The driver name.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncSUPR0DECL(int) SUPR0TracerRegisterDrv(PSUPDRVSESSION pSession, PVTGOBJHDR pVtgHdr, const char *pszName)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync{
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync int rc;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertPtrReturn(pszName, VERR_INVALID_POINTER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync LOG_TRACER(("SUPR0TracerRegisterDrv: pSession=%p pVtgHdr=%p pszName=%s\n", pSession, pVtgHdr, pszName));
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
0dd3967035b8a02985920baa57f948dc542b9388vboxsync rc = supdrvTracerRegisterVtgObj(pSession->pDevExt, pVtgHdr, NULL /*pImage*/, pSession, NULL /*pUmod*/, pszName);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Try unregister zombies while we have a chance.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync */
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync supdrvTracerProcessZombies(pSession->pDevExt);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync return rc;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync}
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync/**
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * Deregister the VTG tracepoint providers of a driver.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync *
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * @param pSession The support driver session handle.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * @param pVtgHdr The VTG header.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncSUPR0DECL(void) SUPR0TracerDeregisterDrv(PSUPDRVSESSION pSession)
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync{
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync PSUPDRVTPPROVIDER pProv, pProvNext;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync PSUPDRVDEVEXT pDevExt;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertReturnVoid(SUP_IS_SESSION_VALID(pSession));
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertReturnVoid(pSession->R0Process == NIL_RTR0PROCESS);
0dd3967035b8a02985920baa57f948dc542b9388vboxsync LOG_TRACER(("SUPR0TracerDeregisterDrv: pSession=%p\n", pSession));
0dd3967035b8a02985920baa57f948dc542b9388vboxsync
0dd3967035b8a02985920baa57f948dc542b9388vboxsync pDevExt = pSession->pDevExt;
0dd3967035b8a02985920baa57f948dc542b9388vboxsync
0dd3967035b8a02985920baa57f948dc542b9388vboxsync /*
0dd3967035b8a02985920baa57f948dc542b9388vboxsync * Search for providers belonging to this driver session.
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync */
0dd3967035b8a02985920baa57f948dc542b9388vboxsync RTSemFastMutexRequest(pDevExt->mtxTracer);
0dd3967035b8a02985920baa57f948dc542b9388vboxsync RTListForEachSafe(&pSession->TpProviders, pProv, pProvNext, SUPDRVTPPROVIDER, SessionListEntry)
0dd3967035b8a02985920baa57f948dc542b9388vboxsync {
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync supdrvTracerDeregisterVtgObj(pDevExt, pProv);
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync }
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync /*
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * Try unregister zombies while we have a chance.
0dd3967035b8a02985920baa57f948dc542b9388vboxsync */
0dd3967035b8a02985920baa57f948dc542b9388vboxsync supdrvTracerProcessZombies(pDevExt);
0dd3967035b8a02985920baa57f948dc542b9388vboxsync}
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync/**
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * Registers the VTG tracepoint providers of a module loaded by
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * the support driver.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync *
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * This should be called from the ModuleInit code.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync *
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * @returns VBox status code.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * @param hMod The module handle.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * @param pVtgHdr The VTG header.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync */
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsyncSUPR0DECL(int) SUPR0TracerRegisterModule(void *hMod, PVTGOBJHDR pVtgHdr)
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync{
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync PSUPDRVDEVEXT pDevExt;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync int rc;
0dd3967035b8a02985920baa57f948dc542b9388vboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync LOG_TRACER(("SUPR0TracerRegisterModule: %p\n", pVtgHdr));
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync
02651f98b4320e70a300ba1ebe95270096ebfd4dvboxsync /*
0dd3967035b8a02985920baa57f948dc542b9388vboxsync * Validate input and context.
0dd3967035b8a02985920baa57f948dc542b9388vboxsync */
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertPtrReturn(pImage, VERR_INVALID_HANDLE);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertPtrReturn(pImage, VERR_INVALID_POINTER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pDevExt = pImage->pDevExt;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertReturn((uintptr_t)pVtgHdr - (uintptr_t)pImage->pvImage < pImage->cbImageBits, VERR_INVALID_PARAMETER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
3c6306a66deef467e3c13483dd6529e1e1c6b822vboxsync /*
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync * Do the job.
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync */
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync rc = supdrvTracerRegisterVtgObj(pDevExt, pVtgHdr, pImage, NULL /*pSession*/, NULL /*pUmod*/, pImage->szName);
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync LOG_TRACER(("SUPR0TracerRegisterModule: rc=%d\n", rc));
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync /*
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync * Try unregister zombies while we have a chance.
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync */
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync supdrvTracerProcessZombies(pDevExt);
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync return rc;
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync}
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync
0c80e8c5ac4249337af378ff41c60033c9fff59fvboxsync/**
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync * Registers the tracer implementation.
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync *
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync * This should be called from the ModuleInit code or from a ring-0 session.
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync *
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync * @returns VBox status code.
0c80e8c5ac4249337af378ff41c60033c9fff59fvboxsync * @param hMod The module handle.
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync * @param pSession Ring-0 session handle.
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync * @param pReg Pointer to the tracer registration structure.
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync * @param ppHlp Where to return the tracer helper method table.
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync */
805a319b88bdf29b369da48402c58897a5e8b65dvboxsyncSUPR0DECL(int) SUPR0TracerRegisterImpl(void *hMod, PSUPDRVSESSION pSession, PCSUPDRVTRACERREG pReg, PCSUPDRVTRACERHLP *ppHlp)
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync{
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync PSUPDRVDEVEXT pDevExt;
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync PSUPDRVTPPROVIDER pProv;
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync int rc;
0c80e8c5ac4249337af378ff41c60033c9fff59fvboxsync
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync /*
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync * Validate input and context.
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync */
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync AssertPtrReturn(ppHlp, VERR_INVALID_POINTER);
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync *ppHlp = NULL;
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync AssertPtrReturn(pReg, VERR_INVALID_HANDLE);
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync if (pImage)
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync {
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertPtrReturn(pImage, VERR_INVALID_POINTER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
3c6306a66deef467e3c13483dd6529e1e1c6b822vboxsync pDevExt = pImage->pDevExt;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
3c6306a66deef467e3c13483dd6529e1e1c6b822vboxsync AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync }
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync else
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync {
805a319b88bdf29b369da48402c58897a5e8b65dvboxsync AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pDevExt = pSession->pDevExt;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertReturn(pReg->u32Magic == SUPDRVTRACERREG_MAGIC, VERR_INVALID_MAGIC);
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync AssertReturn(pReg->u32Version == SUPDRVTRACERREG_VERSION, VERR_VERSION_MISMATCH);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertReturn(pReg->uEndMagic == SUPDRVTRACERREG_MAGIC, VERR_VERSION_MISMATCH);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertPtrReturn(pReg->pfnProbeFireKernel, VERR_INVALID_POINTER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertPtrReturn(pReg->pfnProbeFireUser, VERR_INVALID_POINTER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertPtrReturn(pReg->pfnTracerOpen, VERR_INVALID_POINTER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertPtrReturn(pReg->pfnTracerIoCtl, VERR_INVALID_POINTER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertPtrReturn(pReg->pfnTracerClose, VERR_INVALID_POINTER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertPtrReturn(pReg->pfnProviderRegister, VERR_INVALID_POINTER);
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync AssertPtrReturn(pReg->pfnProviderDeregister, VERR_INVALID_POINTER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertPtrReturn(pReg->pfnProviderDeregisterZombie, VERR_INVALID_POINTER);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Do the job.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (RT_SUCCESS(rc))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (!pDevExt->pTracerOps)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync LOG_TRACER(("SUPR0TracerRegisterImpl: pReg=%p\n", pReg));
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pDevExt->pTracerOps = pReg;
3c6306a66deef467e3c13483dd6529e1e1c6b822vboxsync pDevExt->pTracerSession = pSession;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pDevExt->pTracerImage = pImage;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync g_pfnSupdrvProbeFireKernel = (PFNRT)pDevExt->pTracerOps->pfnProbeFireKernel;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync *ppHlp = &pDevExt->TracerHlp;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rc = VINF_SUCCESS;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync /*
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * Iterate the already loaded modules and register their providers.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync */
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync RTListForEach(&pDevExt->TracerProviderList, pProv, SUPDRVTPPROVIDER, ListEntry)
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync {
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync Assert(!pProv->fRegistered);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pProv->fRegistered = true;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync int rc2 = pDevExt->pTracerOps->pfnProviderRegister(pDevExt->pTracerOps, &pProv->Core);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync if (RT_FAILURE(rc2))
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync {
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pProv->fRegistered = false;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync SUPR0Printf("SUPR0TracerRegisterImpl: Failed to register provider %s::%s - rc=%d\n",
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync pProv->Core.pszModName, pProv->szName, rc2);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync else
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync rc = VERR_SUPDRV_TRACER_ALREADY_REGISTERED;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync return rc;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
3c6306a66deef467e3c13483dd6529e1e1c6b822vboxsync}
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync/**
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * Common tracer implementation deregistration code.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync *
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * The caller sets fTracerUnloading prior to calling this function.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pDevExt The device extension structure.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic void supdrvTracerCommonDeregisterImpl(PSUPDRVDEVEXT pDevExt)
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync{
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync uint32_t i;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync PSUPDRVTPPROVIDER pProv;
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync PSUPDRVTPPROVIDER pProvNext;
ffb50166c9adb4ae583b914d405197035cf890advboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync RTSemFastMutexRequest(pDevExt->mtxTracer);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync /*
ffb50166c9adb4ae583b914d405197035cf890advboxsync * Reinstall the stub probe-fire function.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync g_pfnSupdrvProbeFireKernel = supdrvTracerProbeFireStub;
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync
b8bb9c9f6b8ebfd0a7d6df0c0289f9fe80241750vboxsync /*
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync * Disassociate the tracer implementation from all providers.
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync * We will have to wait on busy providers.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync for (i = 0; ; i++)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync uint32_t cZombies = 0;
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync /* Live providers. */
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync {
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync int rc;
ffb50166c9adb4ae583b914d405197035cf890advboxsync LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Attemting to unregister '%s' / %p...\n",
ffb50166c9adb4ae583b914d405197035cf890advboxsync pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
ffb50166c9adb4ae583b914d405197035cf890advboxsync
ffb50166c9adb4ae583b914d405197035cf890advboxsync if (!pProv->fRegistered)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync continue;
ffb50166c9adb4ae583b914d405197035cf890advboxsync if (!pProv->fZombie)
ffb50166c9adb4ae583b914d405197035cf890advboxsync {
3c6306a66deef467e3c13483dd6529e1e1c6b822vboxsync rc = pDevExt->pTracerOps->pfnProviderDeregister(pDevExt->pTracerOps, &pProv->Core);
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync if (RT_FAILURE(rc))
ffb50166c9adb4ae583b914d405197035cf890advboxsync pProv->fZombie = true;
ffb50166c9adb4ae583b914d405197035cf890advboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync else
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync if (RT_SUCCESS(rc))
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync pProv->fZombie = pProv->fRegistered = false;
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync else
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync {
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync cZombies++;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync if (!(i & 0xf))
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on busy provider '%s' / %p (rc=%d)\n",
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync else
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Failed to unregister provider '%s' / %p - rc=%d\n",
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync /* Zombies providers. */
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync {
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync int rc;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Attemting to unregister '%s' / %p (zombie)...\n",
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
0dd3967035b8a02985920baa57f948dc542b9388vboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync if (RT_SUCCESS(rc))
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync {
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync RTListNodeRemove(&pProv->ListEntry);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync supdrvTracerFreeProvider(pProv);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync else
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync {
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync cZombies++;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync if (!(i & 0xf))
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on busy provider '%s' / %p (rc=%d)\n",
0dd3967035b8a02985920baa57f948dc542b9388vboxsync pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync else
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Failed to unregister provider '%s' / %p - rc=%d\n",
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync /* Tracer opens. */
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync if (pDevExt->cTracerOpens)
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync {
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync cZombies++;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync if (!(i & 0xf))
ffb50166c9adb4ae583b914d405197035cf890advboxsync SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on %u opens\n", pDevExt->cTracerOpens);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync else
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Waiting on %u opens\n", pDevExt->cTracerOpens));
ffb50166c9adb4ae583b914d405197035cf890advboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync /* Tracer calls. */
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync if (pDevExt->cTracerCallers)
ffb50166c9adb4ae583b914d405197035cf890advboxsync {
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync cZombies++;
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync if (!(i & 0xf))
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on %u callers\n", pDevExt->cTracerCallers);
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync else
ffb50166c9adb4ae583b914d405197035cf890advboxsync LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Waiting on %u callers\n", pDevExt->cTracerCallers));
ffb50166c9adb4ae583b914d405197035cf890advboxsync }
ffb50166c9adb4ae583b914d405197035cf890advboxsync
ffb50166c9adb4ae583b914d405197035cf890advboxsync /* Done? */
ffb50166c9adb4ae583b914d405197035cf890advboxsync if (cZombies == 0)
ffb50166c9adb4ae583b914d405197035cf890advboxsync break;
ffb50166c9adb4ae583b914d405197035cf890advboxsync
ffb50166c9adb4ae583b914d405197035cf890advboxsync /* Delay...*/
ffb50166c9adb4ae583b914d405197035cf890advboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync RTThreadSleep(1000);
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync RTSemFastMutexRequest(pDevExt->mtxTracer);
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync }
2e4df4fd9eace3c61be68bb5eb12a93f9a79334dvboxsync
ffb50166c9adb4ae583b914d405197035cf890advboxsync /*
ffb50166c9adb4ae583b914d405197035cf890advboxsync * Deregister the tracer implementation.
ffb50166c9adb4ae583b914d405197035cf890advboxsync */
ffb50166c9adb4ae583b914d405197035cf890advboxsync pDevExt->pTracerImage = NULL;
ffb50166c9adb4ae583b914d405197035cf890advboxsync pDevExt->pTracerSession = NULL;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pDevExt->pTracerOps = NULL;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pDevExt->fTracerUnloading = false;
ffb50166c9adb4ae583b914d405197035cf890advboxsync
ffb50166c9adb4ae583b914d405197035cf890advboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
ffb50166c9adb4ae583b914d405197035cf890advboxsync}
ffb50166c9adb4ae583b914d405197035cf890advboxsync
ffb50166c9adb4ae583b914d405197035cf890advboxsync
ffb50166c9adb4ae583b914d405197035cf890advboxsync/**
ffb50166c9adb4ae583b914d405197035cf890advboxsync * Deregister a tracer implementation.
ffb50166c9adb4ae583b914d405197035cf890advboxsync *
ffb50166c9adb4ae583b914d405197035cf890advboxsync * This should be called from the ModuleTerm code or from a ring-0 session.
3c6306a66deef467e3c13483dd6529e1e1c6b822vboxsync *
ffb50166c9adb4ae583b914d405197035cf890advboxsync * @returns VBox status code.
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * @param hMod The module handle.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pSession Ring-0 session handle.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncSUPR0DECL(int) SUPR0TracerDeregisterImpl(void *hMod, PSUPDRVSESSION pSession)
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync{
ffb50166c9adb4ae583b914d405197035cf890advboxsync PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
ffb50166c9adb4ae583b914d405197035cf890advboxsync PSUPDRVDEVEXT pDevExt;
ffb50166c9adb4ae583b914d405197035cf890advboxsync int rc;
ffb50166c9adb4ae583b914d405197035cf890advboxsync
ffb50166c9adb4ae583b914d405197035cf890advboxsync /*
ffb50166c9adb4ae583b914d405197035cf890advboxsync * Validate input and context.
ffb50166c9adb4ae583b914d405197035cf890advboxsync */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync if (pImage)
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync {
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync AssertPtrReturn(pImage, VERR_INVALID_POINTER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync pDevExt = pImage->pDevExt;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync else
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync {
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync pDevExt = pSession->pDevExt;
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync /*
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * Do the job.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
ffb50166c9adb4ae583b914d405197035cf890advboxsync if (RT_SUCCESS(rc))
ffb50166c9adb4ae583b914d405197035cf890advboxsync {
ffb50166c9adb4ae583b914d405197035cf890advboxsync if ( pImage
ffb50166c9adb4ae583b914d405197035cf890advboxsync ? pDevExt->pTracerImage == pImage
ffb50166c9adb4ae583b914d405197035cf890advboxsync : pDevExt->pTracerSession == pSession)
ffb50166c9adb4ae583b914d405197035cf890advboxsync {
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync LOG_TRACER(("SUPR0TracerDeregisterImpl: Unloading ...\n"));
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync pDevExt->fTracerUnloading = true;
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync supdrvTracerCommonDeregisterImpl(pDevExt);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync LOG_TRACER(("SUPR0TracerDeregisterImpl: ... done.\n"));
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync }
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync else
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rc = VERR_SUPDRV_TRACER_NOT_REGISTERED;
ffb50166c9adb4ae583b914d405197035cf890advboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
ffb50166c9adb4ae583b914d405197035cf890advboxsync }
ffb50166c9adb4ae583b914d405197035cf890advboxsync }
ffb50166c9adb4ae583b914d405197035cf890advboxsync
ffb50166c9adb4ae583b914d405197035cf890advboxsync return rc;
ffb50166c9adb4ae583b914d405197035cf890advboxsync}
ffb50166c9adb4ae583b914d405197035cf890advboxsync
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync/*
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * The probe function is a bit more fun since we need tail jump optimizating.
ffb50166c9adb4ae583b914d405197035cf890advboxsync *
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * Since we cannot ship yasm sources for linux and freebsd, owing to the cursed
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * rebuilding of the kernel module from scratch at install time, we have to
ffb50166c9adb4ae583b914d405197035cf890advboxsync * deploy some ugly gcc inline assembly here.
ffb50166c9adb4ae583b914d405197035cf890advboxsync */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync#if defined(__GNUC__) && (defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX))
ffb50166c9adb4ae583b914d405197035cf890advboxsync__asm__("\
ffb50166c9adb4ae583b914d405197035cf890advboxsync .section .text \n\
ffb50166c9adb4ae583b914d405197035cf890advboxsync \n\
ffb50166c9adb4ae583b914d405197035cf890advboxsync .p2align 2,,3 \n\
ffb50166c9adb4ae583b914d405197035cf890advboxsync .global SUPR0TracerFireProbe \n\
ffb50166c9adb4ae583b914d405197035cf890advboxsyncSUPR0TracerFireProbe: \n\
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync");
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync# if defined(RT_ARCH_AMD64)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync__asm__(" \
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync movq g_pfnSupdrvProbeFireKernel(%rip), %rax \n\
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync jmp *%rax \n\
ffb50166c9adb4ae583b914d405197035cf890advboxsync");
ffb50166c9adb4ae583b914d405197035cf890advboxsync# elif defined(RT_ARCH_X86)
ffb50166c9adb4ae583b914d405197035cf890advboxsync__asm__("\
ffb50166c9adb4ae583b914d405197035cf890advboxsync movl g_pfnSupdrvProbeFireKernel, %eax \n\
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync jmp *%eax \n\
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync");
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync# else
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync# error "Which arch is this?"
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync# endif
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync__asm__("\
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync \n\
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync .type supdrvTracerProbeFireStub,@function \n\
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync .global supdrvTracerProbeFireStub \n\
6475559a7e0e52892efbab4fbdedc879f6866109vboxsyncsupdrvTracerProbeFireStub: \n\
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync ret \n\
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync \n\
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync .previous \n\
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync");
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync# if 0 /* Slickedit on windows highlighting fix */
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync )
ffb50166c9adb4ae583b914d405197035cf890advboxsync# endif
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync#endif
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync
ffb50166c9adb4ae583b914d405197035cf890advboxsync/**
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync * Module unloading hook, called after execution in the module have ceased.
ffb50166c9adb4ae583b914d405197035cf890advboxsync *
ffb50166c9adb4ae583b914d405197035cf890advboxsync * @param pDevExt The device extension structure.
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * @param pImage The image being unloaded.
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync */
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsyncvoid VBOXCALL supdrvTracerModuleUnloading(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync{
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync PSUPDRVTPPROVIDER pProv, pProvNext;
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync AssertPtrReturnVoid(pImage); /* paranoia */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTSemFastMutexRequest(pDevExt->mtxTracer);
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * If it is the tracer image, we have to unload all the providers.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pDevExt->pTracerImage == pImage)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync LOG_TRACER(("supdrvTracerModuleUnloading: Unloading tracer ...\n"));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pDevExt->fTracerUnloading = true;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync supdrvTracerCommonDeregisterImpl(pDevExt);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync LOG_TRACER(("supdrvTracerModuleUnloading: ... done.\n"));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync else
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Unregister all providers belonging to this image.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync {
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pProv->pImage == pImage)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync supdrvTracerDeregisterVtgObj(pDevExt, pProv);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTSemFastMutexRelease(pDevExt->mtxTracer);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /*
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Try unregister zombies while we have a chance.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync supdrvTracerProcessZombies(pDevExt);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync }
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync}
/**
* Called when a session is being cleaned up.
*
* @param pDevExt The device extension structure.
* @param pSession The session that is being torn down.
*/
void VBOXCALL supdrvTracerCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
{
/*
* Deregister all providers.
*/
SUPDRVTPPROVIDER *pProvNext;
SUPDRVTPPROVIDER *pProv;
RTSemFastMutexRequest(pDevExt->mtxTracer);
RTListForEachSafe(&pSession->TpProviders, pProv, pProvNext, SUPDRVTPPROVIDER, SessionListEntry)
{
supdrvTracerDeregisterVtgObj(pDevExt, pProv);
}
RTSemFastMutexRelease(pDevExt->mtxTracer);
/*
* Clean up instance data the trace may have associated with the session.
*/
if (pSession->uTracerData)
supdrvIOCtl_TracerClose(pDevExt, pSession);
/*
* Deregister any tracer implementation.
*/
if (pSession->R0Process == NIL_RTR0PROCESS)
(void)SUPR0TracerDeregisterImpl(NULL, pSession);
if (pSession->R0Process != NIL_RTR0PROCESS)
{
/*
* Free any lingering user modules. We don't bother holding the lock
* here as there shouldn't be anyone messing with the session at this
* point.
*/
PSUPDRVTRACERUMOD pUmodNext;
PSUPDRVTRACERUMOD pUmod;
RTListForEachSafe(&pSession->TpUmods, pUmod, pUmodNext, SUPDRVTRACERUMOD, ListEntry)
{
RTR0MemObjFree(pUmod->hMemObjMap, false /*fFreeMappings*/);
RTR0MemObjFree(pUmod->hMemObjLock, false /*fFreeMappings*/);
supdrvVtgReleaseObjectCopy(pDevExt, pUmod->pVtgCopy);
RTMemFree(pUmod);
}
}
}
static void supdrvVtgReleaseObjectCopy(PSUPDRVDEVEXT pDevExt, PSUPDRVVTGCOPY pThis)
{
uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
if (!cRefs)
{
RTSemFastMutexRequest(pDevExt->mtxTracer);
pThis->u32Magic = ~SUDPRVVTGCOPY_MAGIC;
RTListNodeRemove(&pThis->ListEntry);
RTSemFastMutexRelease(pDevExt->mtxTracer);
RTMemFree(pThis);
}
}
/**
* Finds a matching VTG object copy, caller owns the lock already.
*
* @returns Copy with reference. NULL if not found.
* @param pHashList The hash list to search.
* @param pHdr The VTG header (valid).
* @param cbStrTab The string table size.
* @param fFlags The user module flags.
*/
static PSUPDRVVTGCOPY supdrvVtgFindObjectCopyLocked(PRTLISTANCHOR pHashList, PCVTGOBJHDR pHdr, uint32_t cbStrTab, uint32_t fFlags)
{
PSUPDRVVTGCOPY pCur;
fFlags &= SUP_TRACER_UMOD_FLAGS_TYPE_MASK;
RTListForEach(pHashList, pCur, SUPDRVVTGCOPY, ListEntry)
{
#define HDR_EQUALS(member) pCur->Hdr.member == pHdr->member
if ( HDR_EQUALS(Uuid.au32[0])
&& HDR_EQUALS(Uuid.au32[1])
&& HDR_EQUALS(Uuid.au32[2])
&& HDR_EQUALS(Uuid.au32[3])
&& HDR_EQUALS(cbObj)
&& HDR_EQUALS(cBits)
&& pCur->cbStrTab == cbStrTab
&& pCur->fFlags == fFlags
)
{
if (RT_LIKELY( HDR_EQUALS(offStrTab)
&& HDR_EQUALS(cbStrTab)
&& HDR_EQUALS(offArgLists)
&& HDR_EQUALS(cbArgLists)
&& HDR_EQUALS(offProbes)
&& HDR_EQUALS(cbProbes)
&& HDR_EQUALS(offProviders)
&& HDR_EQUALS(cbProviders)
&& HDR_EQUALS(offProbeEnabled)
&& HDR_EQUALS(cbProbeEnabled)
&& HDR_EQUALS(offProbeLocs)
&& HDR_EQUALS(cbProbeLocs)
)
)
{
Assert(pCur->cRefs > 0);
Assert(pCur->cRefs < _1M);
pCur->cRefs++;
return pCur;
}
}
#undef HDR_EQUALS
}
return NULL;
}
/**
* Finds a matching VTG object copy.
*
* @returns Copy with reference. NULL if not found.
* @param pDevExt The device extension.
* @param pHdr The VTG header (valid).
* @param cbStrTab The string table size.
* @param fFlags The user module flags.
*/
static PSUPDRVVTGCOPY supdrvVtgFindObjectCopy(PSUPDRVDEVEXT pDevExt, PCVTGOBJHDR pHdr, uint32_t cbStrTab, uint32_t fFlags)
{
PRTLISTANCHOR pHashList = &pDevExt->aTrackerUmodHash[pHdr->Uuid.au8[3] % RT_ELEMENTS(pDevExt->aTrackerUmodHash)];
PSUPDRVVTGCOPY pRet;
int rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
AssertRCReturn(rc, NULL);
pRet = supdrvVtgFindObjectCopyLocked(pHashList, pHdr, cbStrTab, fFlags);
RTSemFastMutexRelease(pDevExt->mtxTracer);
return pRet;
}
/**
* Makes a shared copy of the VTG object.
*
* @returns VBox status code.
* @param pDevExt The device extension.
* @param pVtgHdr The VTG header (valid).
* @param R3PtrVtgHdr The ring-3 VTG header address.
* @param uVtgHdrAddr The address of the VTG header in the context
* where it is actually used.
* @param R3PtrStrTab The ring-3 address of the probe location string
* table. The probe location array have offsets
* into this instead of funciton name pointers.
* @param cbStrTab The size of the probe location string table.
* @param fFlags The user module flags.
* @param pUmod The structure we've allocated to track the
* module. This have a valid kernel mapping of the
* probe location array. Upon successful return,
* the pVtgCopy member will hold the address of our
* copy (with a referenced of course).
*/
static int supdrvVtgCreateObjectCopy(PSUPDRVDEVEXT pDevExt, PCVTGOBJHDR pVtgHdr, RTR3PTR R3PtrVtgHdr, RTUINTPTR uVtgHdrAddr,
RTR3PTR R3PtrStrTab, uint32_t cbStrTab, uint32_t fFlags, PSUPDRVTRACERUMOD pUmod)
{
/*
* Calculate the space required, allocate and copy in the data.
*/
int rc;
size_t const cProbeLocs = pVtgHdr->cbProbeLocs / (pVtgHdr->cBits == 32 ? sizeof(VTGPROBELOC32) : sizeof(VTGPROBELOC64));
size_t const cbProbeLocs = cProbeLocs * sizeof(VTGPROBELOC);
size_t const offProbeLocs = RT_ALIGN(pVtgHdr->cbObj, 8);
size_t const cb = offProbeLocs + cbProbeLocs + cbStrTab + 1;
PSUPDRVVTGCOPY pThis = (PSUPDRVVTGCOPY)RTMemAlloc(RT_OFFSETOF(SUPDRVVTGCOPY, Hdr) + cb);
if (!pThis)
return VERR_NO_MEMORY;
pThis->u32Magic = SUDPRVVTGCOPY_MAGIC;
pThis->cRefs = 1;
pThis->cbStrTab = cbStrTab;
pThis->fFlags = fFlags & SUP_TRACER_UMOD_FLAGS_TYPE_MASK;
RTListInit(&pThis->ListEntry);
rc = RTR0MemUserCopyFrom(&pThis->Hdr, R3PtrVtgHdr, pVtgHdr->cbObj);
if (RT_SUCCESS(rc))
{
char *pchStrTab = (char *)&pThis->Hdr + offProbeLocs + cbProbeLocs;
rc = RTR0MemUserCopyFrom(pchStrTab, R3PtrStrTab, cbStrTab);
if (RT_SUCCESS(rc))
{
PVTGPROBELOC paDst = (PVTGPROBELOC)((char *)&pThis->Hdr + offProbeLocs);
uint32_t i;
/*
* Some paranoia: Overwrite the header with the copy we've already
* validated and zero terminate the string table.
*/
pThis->Hdr = *pVtgHdr;
pchStrTab[cbStrTab] = '\0';
/*
* Set the probe location array related header members since we're
* making our own copy in a different location.
*/
pThis->Hdr.uProbeLocs.u64 = (uintptr_t)paDst;
pThis->Hdr.uProbeLocsEnd.u64 = (uintptr_t)paDst + cbProbeLocs;
pThis->Hdr.offProbeLocs = offProbeLocs;
pThis->Hdr.cbProbeLocs = cbProbeLocs;
pThis->Hdr.cBits = ARCH_BITS;
/*
* Copy, convert and fix up the the probe location table.
*/
if (pVtgHdr->cBits == 32)
{
uintptr_t const offDelta = (uintptr_t)&pThis->Hdr - uVtgHdrAddr;
PCVTGPROBELOC32 paSrc = (PCVTGPROBELOC32)pUmod->pvProbeLocs;
for (i = 0; i < cProbeLocs; i++)
{
paDst[i].uLine = paSrc[i].uLine;
paDst[i].fEnabled = paSrc[i].fEnabled;
paDst[i].idProbe = paSrc[i].idProbe;
if (paSrc[i].pszFunction > cbStrTab)
{
rc = VERR_SUPDRV_TRACER_UMOD_STRTAB_OFF_BAD;
break;
}
paDst[i].pszFunction = pchStrTab + paSrc[i].pszFunction;
paDst[i].pProbe = (PVTGDESCPROBE)(uintptr_t)(paSrc[i].pProbe + offDelta);
}
}
else
{
uint64_t const offDelta = (uintptr_t)&pThis->Hdr - uVtgHdrAddr;
PCVTGPROBELOC64 paSrc = (PCVTGPROBELOC64)pUmod->pvProbeLocs;
for (i = 0; i < cProbeLocs; i++)
{
paDst[i].uLine = paSrc[i].uLine;
paDst[i].fEnabled = paSrc[i].fEnabled;
paDst[i].idProbe = paSrc[i].idProbe;
if (paSrc[i].pszFunction > cbStrTab)
{
rc = VERR_SUPDRV_TRACER_UMOD_STRTAB_OFF_BAD;
break;
}
paDst[i].pszFunction = pchStrTab + (uintptr_t)paSrc[i].pszFunction;
paDst[i].pProbe = (PVTGDESCPROBE)(uintptr_t)(paSrc[i].pProbe + offDelta);
}
}
/*
* Validate it
*
* Note! fUmod is false as this is a kernel copy with all native
* structures.
*/
if (RT_SUCCESS(rc))
rc = supdrvVtgValidate(&pThis->Hdr, (uintptr_t)&pThis->Hdr, (uint8_t *)&pThis->Hdr, cb, false /*fUmod*/);
if (RT_SUCCESS(rc))
{
/*
* Add it to the hash list, making sure nobody raced us.
*/
PRTLISTANCHOR pHashList = &pDevExt->aTrackerUmodHash[ pVtgHdr->Uuid.au8[3]
% RT_ELEMENTS(pDevExt->aTrackerUmodHash)];
rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
if (RT_SUCCESS(rc))
{
pUmod->pVtgCopy = supdrvVtgFindObjectCopyLocked(pHashList, pVtgHdr, cbStrTab, fFlags);
if (!pUmod->pVtgCopy)
{
pUmod->pVtgCopy = pThis;
RTListAppend(pHashList, &pThis->ListEntry);
RTSemFastMutexRelease(pDevExt->mtxTracer);
return rc;
}
/*
* Someone raced us, free our copy and return the existing
* one instead.
*/
RTSemFastMutexRelease(pDevExt->mtxTracer);
}
}
}
}
RTMemFree(pThis);
return rc;
}
/**
* Undoes what supdrvTracerUmodSetProbeIds did.
*
* @param pDevExt The device extension.
* @param pSession The current session.
* @param pUmod The user tracepoint module.
*/
static void supdrvTracerUmodClearProbeIds(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVTRACERUMOD pUmod)
{
uint32_t i;
AssertReturnVoid(pUmod->iLookupTable < RT_ELEMENTS(pSession->apTpLookupTable));
AssertReturnVoid(pSession->apTpLookupTable[pUmod->iLookupTable] == pUmod);
/*
* Clear the probe IDs and disable the probes.
*/
i = pUmod->cProbeLocs;
if (pUmod->cBits == 32)
{
PVTGPROBELOC32 paProbeLocs = (PVTGPROBELOC32)pUmod->pvProbeLocs;
while (i-- > 0)
paProbeLocs[i].idProbe = 0;
}
else
{
PVTGPROBELOC64 paProbeLocs = (PVTGPROBELOC64)pUmod->pvProbeLocs;
while (i-- > 0)
paProbeLocs[i].idProbe = 0;
}
/*
* Free the lookup table entry. We'll have to wait for the table to go
* idle to make sure there are no current users of pUmod.
*/
RTSemFastMutexRequest(pDevExt->mtxTracer);
if (pSession->apTpLookupTable[pUmod->iLookupTable] == pUmod)
{
if (pSession->cTpProbesFiring > 0)
{
i = 0;
while (pSession->cTpProbesFiring > 0)
{
RTSemFastMutexRelease(pDevExt->mtxTracer);
i++;
if (!(i & 0xff))
SUPR0Printf("supdrvTracerUmodClearProbeIds: waiting for lookup table to go idle (i=%u)\n", i);
RTThreadSleep(10);
RTSemFastMutexRequest(pDevExt->mtxTracer);
}
}
ASMAtomicWriteNullPtr(&pSession->apTpLookupTable[pUmod->iLookupTable]);
}
RTSemFastMutexRelease(pDevExt->mtxTracer);
}
/**
* Allocates a lookup table entry for the Umod and sets the
* VTGPROBELOC::idProbe fields in user mode.
*
* @returns VINF_SUCCESS or VERR_SUPDRV_TRACER_TOO_MANY_PROVIDERS.
* @param pDevExt The device extension.
* @param pSession The current session.
* @param pUmod The user tracepoint module.
*/
static int supdrvTracerUmodSetProbeIds(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVTRACERUMOD pUmod)
{
uint32_t iBase;
uint32_t i;
/*
* Allocate a lookup table entry.
*/
RTSemFastMutexRequest(pDevExt->mtxTracer);
for (i = 0; i < RT_ELEMENTS(pSession->apTpLookupTable); i++)
{
if (!pSession->apTpLookupTable[i])
{
pSession->apTpLookupTable[i] = pUmod;
pUmod->iLookupTable = i;
break;
}
}
RTSemFastMutexRelease(pDevExt->mtxTracer);
if (i >= RT_ELEMENTS(pSession->apTpLookupTable))
return VERR_SUPDRV_TRACER_TOO_MANY_PROVIDERS;
/*
* Set probe IDs of the usermode probe location to indicate our lookup
* table entry as well as the probe location array entry.
*/
iBase = (uint32_t)pUmod->iLookupTable << 24;
i = pUmod->cProbeLocs;
if (pUmod->cBits == 32)
{
PVTGPROBELOC32 paProbeLocs = (PVTGPROBELOC32)pUmod->pvProbeLocs;
while (i-- > 0)
paProbeLocs[i].idProbe = iBase | i;
}
else
{
PVTGPROBELOC64 paProbeLocs = (PVTGPROBELOC64)pUmod->pvProbeLocs;
while (i-- > 0)
paProbeLocs[i].idProbe = iBase | i;
}
return VINF_SUCCESS;
}
int VBOXCALL supdrvIOCtl_TracerUmodRegister(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession,
RTR3PTR R3PtrVtgHdr, RTUINTPTR uVtgHdrAddr,
RTR3PTR R3PtrStrTab, uint32_t cbStrTab,
const char *pszModName, uint32_t fFlags)
{
VTGOBJHDR Hdr;
PSUPDRVTRACERUMOD pUmod;
RTR3PTR R3PtrLock;
size_t cbLock;
uint32_t cProbeLocs;
int rc;
/*
* Validate input.
*/
if (pSession->R0Process == NIL_RTR0PROCESS)
return VERR_INVALID_CONTEXT;
if ( fFlags != SUP_TRACER_UMOD_FLAGS_EXE
&& fFlags != SUP_TRACER_UMOD_FLAGS_SHARED)
return VERR_INVALID_PARAMETER;
if (pSession->cTpProviders >= RT_ELEMENTS(pSession->apTpLookupTable))
return VERR_SUPDRV_TRACER_TOO_MANY_PROVIDERS;
if ( cbStrTab < 2
|| cbStrTab > _1M)
return VERR_SUPDRV_TRACER_UMOD_STRTAB_TOO_BIG;
/*
* Read the VTG header into a temporary buffer and perform some simple
* validations to make sure we aren't wasting our time here.
*/
rc = RTR0MemUserCopyFrom(&Hdr, R3PtrVtgHdr, sizeof(Hdr));
if (RT_FAILURE(rc))
return rc;
rc = supdrvVtgValidateHdr(&Hdr, uVtgHdrAddr, NULL, 0, true /*fUmod*/);
if (RT_FAILURE(rc))
return rc;
if (Hdr.cbProviders / sizeof(VTGDESCPROVIDER) > 2)
return VERR_SUPDRV_TRACER_TOO_MANY_PROVIDERS;
/*
* Check how much needs to be locked down and how many probe locations
* there are.
*/
if ( Hdr.offProbeLocs <= 0
|| Hdr.offProbeEnabled > (uint32_t)Hdr.offProbeLocs
|| (uint32_t)Hdr.offProbeLocs - Hdr.offProbeEnabled - Hdr.cbProbeEnabled > 128)
return VERR_SUPDRV_TRACER_UMOD_NOT_ADJACENT;
R3PtrLock = R3PtrVtgHdr + Hdr.offProbeEnabled;
cbLock = Hdr.offProbeLocs + Hdr.cbProbeLocs - Hdr.offProbeEnabled + (R3PtrLock & PAGE_OFFSET_MASK);
R3PtrLock &= ~(RTR3PTR)PAGE_OFFSET_MASK;
if (cbLock > _64K)
return VERR_SUPDRV_TRACER_UMOD_TOO_MANY_PROBES;
cProbeLocs = Hdr.cbProbeLocs / (Hdr.cBits == 32 ? sizeof(VTGPROBELOC32) : sizeof(VTGPROBELOC64));
/*
* Allocate the tracker data we keep in the session.
*/
pUmod = (PSUPDRVTRACERUMOD)RTMemAllocZ( RT_OFFSETOF(SUPDRVTRACERUMOD, aProbeLocs[cProbeLocs])
+ (Hdr.cbProbeEnabled / sizeof(uint32_t) * sizeof(SUPDRVPROBEINFO)) );
if (!pUmod)
return VERR_NO_MEMORY;
pUmod->u32Magic = SUPDRVTRACERUMOD_MAGIC;
RTListInit(&pUmod->ListEntry);
pUmod->R3PtrVtgHdr = R3PtrVtgHdr;
pUmod->pVtgCopy = NULL;
pUmod->hMemObjLock = NIL_RTR0MEMOBJ;
pUmod->hMemObjMap = NIL_RTR0MEMOBJ;
pUmod->R3PtrProbeLocs = (RTR3INTPTR)R3PtrVtgHdr + Hdr.offProbeLocs;
pUmod->iLookupTable = UINT8_MAX;
pUmod->cBits = Hdr.cBits;
pUmod->cbProbeLoc = Hdr.cBits == 32 ? sizeof(VTGPROBELOC32) : sizeof(VTGPROBELOC64);
pUmod->cProbeLocs = cProbeLocs;
/*
* Lock down and map the user-mode structures.
*/
rc = RTR0MemObjLockUser(&pUmod->hMemObjLock, R3PtrLock, cbLock, RTMEM_PROT_READ | RTMEM_PROT_WRITE, NIL_RTR0PROCESS);
if (RT_SUCCESS(rc))
{
rc = RTR0MemObjMapKernel(&pUmod->hMemObjMap, pUmod->hMemObjLock, (void *)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
if (RT_SUCCESS(rc))
{
pUmod->pacProbeEnabled = (uint32_t *)( (uintptr_t)RTR0MemObjAddress(pUmod->hMemObjMap)
+ ((uintptr_t)(R3PtrVtgHdr + Hdr.offProbeEnabled) & PAGE_OFFSET_MASK));
pUmod->pvProbeLocs = (uint8_t *)pUmod->pacProbeEnabled + Hdr.offProbeLocs - Hdr.offProbeEnabled;
/*
* Does some other process use the same module already? If so,
* share the VTG data with it. Otherwise, make a ring-0 copy it.
*/
pUmod->pVtgCopy = supdrvVtgFindObjectCopy(pDevExt, &Hdr, cbStrTab, fFlags);
if (!pUmod->pVtgCopy)
rc = supdrvVtgCreateObjectCopy(pDevExt, &Hdr, R3PtrVtgHdr, uVtgHdrAddr, R3PtrStrTab, cbStrTab, fFlags, pUmod);
if (RT_SUCCESS(rc))
{
AssertPtr(pUmod->pVtgCopy);
/*
* Grabe a place in apTpLookupTable and set the probe IDs
* accordingly.
*/
rc = supdrvTracerUmodSetProbeIds(pDevExt, pSession, pUmod);
if (RT_SUCCESS(rc))
{
/*
* Register the providers.
*/
rc = supdrvTracerRegisterVtgObj(pDevExt, &pUmod->pVtgCopy->Hdr,
NULL /*pImage*/, pSession, pUmod, pszModName);
if (RT_SUCCESS(rc))
{
RTSemFastMutexRequest(pDevExt->mtxTracer);
RTListAppend(&pSession->TpUmods, &pUmod->ListEntry);
RTSemFastMutexRelease(pDevExt->mtxTracer);
return VINF_SUCCESS;
}
/* bail out. */
supdrvTracerUmodClearProbeIds(pDevExt, pSession, pUmod);
}
supdrvVtgReleaseObjectCopy(pDevExt, pUmod->pVtgCopy);
}
RTR0MemObjFree(pUmod->hMemObjMap, false /*fFreeMappings*/);
}
RTR0MemObjFree(pUmod->hMemObjLock, false /*fFreeMappings*/);
}
pUmod->u32Magic = ~SUPDRVTRACERUMOD_MAGIC;
RTMemFree(pUmod);
return rc;
}
int VBOXCALL supdrvIOCtl_TracerUmodDeregister(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, RTR3PTR R3PtrVtgHdr)
{
PSUPDRVTRACERUMOD pUmod = NULL;
uint32_t i;
int rc;
/*
* Validate the request.
*/
RTSemFastMutexRequest(pDevExt->mtxTracer);
for (i = 0; i < RT_ELEMENTS(pSession->apTpLookupTable); i++)
{
pUmod = pSession->apTpLookupTable[i];
if ( pUmod
&& pUmod->u32Magic == SUPDRVTRACERUMOD_MAGIC
&& pUmod->R3PtrVtgHdr == R3PtrVtgHdr)
break;
}
RTSemFastMutexRelease(pDevExt->mtxTracer);
if (pUmod)
{
SUPDRVTPPROVIDER *pProvNext;
SUPDRVTPPROVIDER *pProv;
/*
* Remove ourselves from the lookup table and clean up the ring-3 bits
* we've dirtied. We do this first to make sure no probes are firing
* when we're destroying the providers in the next step.
*/
supdrvTracerUmodClearProbeIds(pDevExt, pSession, pUmod);
/*
* Deregister providers related to the VTG object.
*/
RTSemFastMutexRequest(pDevExt->mtxTracer);
RTListForEachSafe(&pSession->TpProviders, pProv, pProvNext, SUPDRVTPPROVIDER, SessionListEntry)
{
if (pProv->pUmod == pUmod)
supdrvTracerDeregisterVtgObj(pDevExt, pProv);
}
RTSemFastMutexRelease(pDevExt->mtxTracer);
/*
* Destroy the Umod object.
*/
pUmod->u32Magic = ~SUPDRVTRACERUMOD_MAGIC;
supdrvVtgReleaseObjectCopy(pDevExt, pUmod->pVtgCopy);
RTR0MemObjFree(pUmod->hMemObjMap, false /*fFreeMappings*/);
RTR0MemObjFree(pUmod->hMemObjLock, false /*fFreeMappings*/);
RTMemFree(pUmod);
}
else
rc = VERR_NOT_FOUND;
return rc;
}
/**
* Implementation of supdrvIOCtl_TracerUmodProbeFire and
* SUPR0TracerUmodProbeFire.
*
* @param pDevExt The device extension.
* @param pSession The calling session.
* @param pCtx The context record.
*/
static void supdrvTracerUmodProbeFire(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVTRACERUSRCTX pCtx)
{
/*
* We cannot trust user mode to hand us the right bits nor not calling us
* when disabled. So, we have to check for our selves.
*/
PSUPDRVTRACERUMOD pUmod;
uint32_t const iLookupTable = pCtx->idProbe >> 24;
uint32_t const iProbeLoc = pCtx->idProbe & UINT32_C(0x00ffffff);
if (RT_UNLIKELY( !pDevExt->pTracerOps
|| pDevExt->fTracerUnloading))
return;
if (RT_UNLIKELY(iLookupTable >= RT_ELEMENTS(pSession->apTpLookupTable)))
return;
if (RT_UNLIKELY( pCtx->cBits != 32
&& pCtx->cBits != 64))
return;
ASMAtomicIncU32(&pSession->cTpProviders);
pUmod = pSession->apTpLookupTable[iLookupTable];
if (RT_LIKELY(pUmod))
{
if (RT_LIKELY( pUmod->u32Magic == SUPDRVTRACERUMOD_MAGIC
&& iProbeLoc < pUmod->cProbeLocs
&& pCtx->cBits == pUmod->cBits))
{
#if 0 /* This won't work for RC modules. */
RTR3PTR R3PtrProbeLoc = pUmod->R3PtrProbeLocs + iProbeLoc * pUmod->cbProbeLoc;
if (RT_LIKELY( (pCtx->cBits == 32 ? (RTR3PTR)pCtx->u.X86.uVtgProbeLoc : pCtx->u.Amd64.uVtgProbeLoc)
== R3PtrProbeLoc))
#endif
{
if (RT_LIKELY(pUmod->aProbeLocs[iProbeLoc].fEnabled))
{
PSUPDRVVTGCOPY pVtgCopy;
ASMAtomicIncU32(&pDevExt->cTracerCallers);
pVtgCopy = pUmod->pVtgCopy;
if (RT_LIKELY( pDevExt->pTracerOps
&& !pDevExt->fTracerUnloading
&& pVtgCopy))
{
PCVTGPROBELOC pProbeLocRO;
pProbeLocRO = (PCVTGPROBELOC)((uintptr_t)&pVtgCopy->Hdr + pVtgCopy->Hdr.offProbeLocs) + iProbeLoc;
pCtx->idProbe = pUmod->aProbeLocs[iProbeLoc].idProbe;
pDevExt->pTracerOps->pfnProbeFireUser(pDevExt->pTracerOps, pSession, pCtx, &pVtgCopy->Hdr, pProbeLocRO);
}
ASMAtomicDecU32(&pDevExt->cTracerCallers);
}
}
}
}
ASMAtomicDecU32(&pSession->cTpProviders);
}
SUPR0DECL(void) SUPR0TracerUmodProbeFire(PSUPDRVSESSION pSession, PSUPDRVTRACERUSRCTX pCtx)
{
AssertReturnVoid(SUP_IS_SESSION_VALID(pSession));
AssertPtrReturnVoid(pCtx);
supdrvTracerUmodProbeFire(pSession->pDevExt, pSession, pCtx);
}
void VBOXCALL supdrvIOCtl_TracerUmodProbeFire(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVTRACERUSRCTX pCtx)
{
supdrvTracerUmodProbeFire(pDevExt, pSession, pCtx);
}
/**
* Open the tracer.
*
* @returns VBox status code
* @param pDevExt The device extension structure.
* @param pSession The current session.
* @param uCookie The tracer cookie.
* @param uArg The tracer open argument.
*/
int VBOXCALL supdrvIOCtl_TracerOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, uint32_t uCookie, uintptr_t uArg)
{
RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
int rc;
RTSemFastMutexRequest(pDevExt->mtxTracer);
if (!pSession->uTracerData)
{
if (pDevExt->pTracerOps)
{
if (pDevExt->pTracerSession != pSession)
{
if (!pDevExt->fTracerUnloading)
{
if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
{
pDevExt->cTracerOpens++;
pSession->uTracerData = ~(uintptr_t)0;
pSession->hTracerCaller = hNativeSelf;
RTSemFastMutexRelease(pDevExt->mtxTracer);
rc = pDevExt->pTracerOps->pfnTracerOpen(pDevExt->pTracerOps, pSession, uCookie, uArg, &pSession->uTracerData);
RTSemFastMutexRequest(pDevExt->mtxTracer);
if (RT_FAILURE(rc))
{
pDevExt->cTracerOpens--;
pSession->uTracerData = 0;
}
pSession->hTracerCaller = NIL_RTNATIVETHREAD;
}
else
rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
}
else
rc = VERR_SUPDRV_TRACER_UNLOADING;
}
else
rc = VERR_SUPDRV_TRACER_CANNOT_OPEN_SELF;
}
else
rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
}
else
rc = VERR_SUPDRV_TRACER_ALREADY_OPENED;
RTSemFastMutexRelease(pDevExt->mtxTracer);
return rc;
}
/**
* Closes the tracer.
*
* @returns VBox status code.
* @param pDevExt The device extension structure.
* @param pSession The current session.
*/
int VBOXCALL supdrvIOCtl_TracerClose(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
{
RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
int rc;
RTSemFastMutexRequest(pDevExt->mtxTracer);
if (pSession->uTracerData)
{
Assert(pDevExt->cTracerOpens > 0);
if (pDevExt->pTracerOps)
{
if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
{
uintptr_t uTracerData = pSession->uTracerData;
pSession->uTracerData = 0;
pSession->hTracerCaller = hNativeSelf;
RTSemFastMutexRelease(pDevExt->mtxTracer);
pDevExt->pTracerOps->pfnTracerClose(pDevExt->pTracerOps, pSession, uTracerData);
rc = VINF_SUCCESS;
RTSemFastMutexRequest(pDevExt->mtxTracer);
pSession->hTracerCaller = NIL_RTNATIVETHREAD;
Assert(pDevExt->cTracerOpens > 0);
pDevExt->cTracerOpens--;
}
else
rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
}
else
{
rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
pSession->uTracerData = 0;
Assert(pDevExt->cTracerOpens > 0);
pDevExt->cTracerOpens--;
}
}
else
rc = VERR_SUPDRV_TRACER_NOT_OPENED;
RTSemFastMutexRelease(pDevExt->mtxTracer);
return rc;
}
/**
* Performs a tracer I/O control request.
*
* @returns VBox status code.
* @param pDevExt The device extension structure.
* @param pSession The current session.
* @param uCmd The tracer command.
* @param uArg The tracer argument.
* @param piRetVal Where to store the tracer specific return value.
*/
int VBOXCALL supdrvIOCtl_TracerIOCtl(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
{
RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
int rc;
*piRetVal = 0;
RTSemFastMutexRequest(pDevExt->mtxTracer);
if (pSession->uTracerData)
{
Assert(pDevExt->cTracerOpens > 0);
if (pDevExt->pTracerOps)
{
if (!pDevExt->fTracerUnloading)
{
if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
{
uintptr_t uTracerData = pSession->uTracerData;
pDevExt->cTracerOpens++;
pSession->hTracerCaller = hNativeSelf;
RTSemFastMutexRelease(pDevExt->mtxTracer);
rc = pDevExt->pTracerOps->pfnTracerIoCtl(pDevExt->pTracerOps, pSession, uTracerData, uCmd, uArg, piRetVal);
RTSemFastMutexRequest(pDevExt->mtxTracer);
pSession->hTracerCaller = NIL_RTNATIVETHREAD;
Assert(pDevExt->cTracerOpens > 0);
pDevExt->cTracerOpens--;
}
else
rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
}
else
rc = VERR_SUPDRV_TRACER_UNLOADING;
}
else
rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
}
else
rc = VERR_SUPDRV_TRACER_NOT_OPENED;
RTSemFastMutexRelease(pDevExt->mtxTracer);
return rc;
}
/**
* Early module initialization hook.
*
* @returns VBox status code.
* @param pDevExt The device extension structure.
*/
int VBOXCALL supdrvTracerInit(PSUPDRVDEVEXT pDevExt)
{
/*
* Initialize the tracer.
*/
int rc = RTSemFastMutexCreate(&pDevExt->mtxTracer);
if (RT_SUCCESS(rc))
{
uint32_t i;
pDevExt->TracerHlp.uVersion = SUPDRVTRACERHLP_VERSION;
/** @todo */
pDevExt->TracerHlp.uEndVersion = SUPDRVTRACERHLP_VERSION;
RTListInit(&pDevExt->TracerProviderList);
RTListInit(&pDevExt->TracerProviderZombieList);
for (i = 0; i < RT_ELEMENTS(pDevExt->aTrackerUmodHash); i++)
RTListInit(&pDevExt->aTrackerUmodHash[i]);
#ifdef VBOX_WITH_NATIVE_DTRACE
pDevExt->pTracerOps = supdrvDTraceInit();
if (pDevExt->pTracerOps)
g_pfnSupdrvProbeFireKernel = (PFNRT)pDevExt->pTracerOps->pfnProbeFireKernel;
#endif
/*
* Register the provider for this module, if compiled in.
*/
#ifdef VBOX_WITH_DTRACE_R0DRV
rc = supdrvTracerRegisterVtgObj(pDevExt, &g_VTGObjHeader, NULL /*pImage*/, NULL /*pSession*/, NULL /*pUmod*/, "vboxdrv");
if (RT_SUCCESS(rc))
return rc;
SUPR0Printf("supdrvTracerInit: supdrvTracerRegisterVtgObj failed with rc=%d\n", rc);
RTSemFastMutexDestroy(pDevExt->mtxTracer);
#else
return VINF_SUCCESS;
#endif
}
pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
return rc;
}
/**
* Late module termination hook.
*
* @returns VBox status code.
* @param pDevExt The device extension structure.
*/
void VBOXCALL supdrvTracerTerm(PSUPDRVDEVEXT pDevExt)
{
LOG_TRACER(("supdrvTracerTerm\n"));
supdrvTracerRemoveAllProviders(pDevExt);
RTSemFastMutexDestroy(pDevExt->mtxTracer);
pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
LOG_TRACER(("supdrvTracerTerm: Done\n"));
}