diff options
Diffstat (limited to 'src/VBox/VMM/VMMR0/DBGFR0Tracer.cpp')
-rw-r--r-- | src/VBox/VMM/VMMR0/DBGFR0Tracer.cpp | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/src/VBox/VMM/VMMR0/DBGFR0Tracer.cpp b/src/VBox/VMM/VMMR0/DBGFR0Tracer.cpp new file mode 100644 index 00000000..5efecbdc --- /dev/null +++ b/src/VBox/VMM/VMMR0/DBGFR0Tracer.cpp @@ -0,0 +1,220 @@ +/* $Id: DBGFR0Tracer.cpp $ */ +/** @file + * DBGF - Debugger Facility, R0 tracing part. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_DBGF +#include "DBGFInternal.h" +#include <VBox/vmm/gvm.h> +#include <VBox/vmm/gvmm.h> +#include <VBox/vmm/vmm.h> + +#include <VBox/log.h> +#include <VBox/sup.h> +#include <iprt/asm.h> +#include <iprt/assert.h> +#include <iprt/errcore.h> +#include <iprt/ctype.h> +#include <iprt/mem.h> +#include <iprt/memobj.h> +#include <iprt/process.h> +#include <iprt/string.h> + +#include "dtrace/VBoxVMM.h" + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ + + +/** + * Used by DBGFR0CleanupVM to destroy a tracer instance. + * + * This is done during VM cleanup so that we're sure there are no active threads + * using the tracer code. + * + * @param pGVM The global (ring-0) VM structure. + * @param pTracer The device instance. + */ +DECLHIDDEN(void) dbgfR0TracerDestroy(PGVM pGVM, PDBGFTRACERINSR0 pTracer) +{ + RT_NOREF(pGVM); + + /* + * Free the ring-3 mapping and instance memory. + */ + RTR0MEMOBJ hMemObj = pTracer->hMapObj; + pTracer->hMapObj = NIL_RTR0MEMOBJ; + RTR0MemObjFree(hMemObj, true); + + hMemObj = pTracer->hMemObj; + pTracer->hMemObj = NIL_RTR0MEMOBJ; + RTR0MemObjFree(hMemObj, true); +} + + +/** + * Worker for DBGFR0TracerCreate that does the actual instantiation. + * + * Allocates a memory object and divides it up as follows: + * @verbatim + -------------------------------------- + ring-0 tracerins + -------------------------------------- + page alignment padding + -------------------------------------- + ring-3 tracerins + -------------------------------------- + [page alignment padding ] -+ + [--------------------------------------] |- Optional, only when raw-mode is enabled. + [raw-mode tracerins ] -+ + [--------------------------------------] + shared tracer data + -------------------------------------- + @endverbatim + * + * @returns VBox status code. + * @param pGVM The global (ring-0) VM structure. + * @param cbRingBuf Size of the ring buffer in bytes. + * @param RCPtrMapping The raw-mode context mapping address, NIL_RTGCPTR if + * not to include raw-mode. + * @param ppTracerInsR3 Where to return the ring-3 tracer instance address. + * @thread EMT(0) + */ +static int dbgfR0TracerCreateWorker(PGVM pGVM, uint32_t cbRingBuf, RTRGPTR RCPtrMapping, PDBGFTRACERINSR3 *ppTracerInsR3) +{ + /* + * Figure out how much memory we need and allocate it. + */ + uint32_t const cbRing0 = RT_ALIGN_32(sizeof(DBGFTRACERINSR0), HOST_PAGE_SIZE); + uint32_t const cbRing3 = RT_ALIGN_32(sizeof(DBGFTRACERINSR3), RCPtrMapping != NIL_RTRGPTR ? HOST_PAGE_SIZE : 64); + uint32_t const cbRC = RCPtrMapping != NIL_RTRGPTR ? 0 + : RT_ALIGN_32(sizeof(DBGFTRACERINSRC), 64); + uint32_t const cbShared = RT_ALIGN_32(sizeof(DBGFTRACERSHARED) + cbRingBuf, 64); + uint32_t const offShared = cbRing0 + cbRing3 + cbRC; + uint32_t const cbTotal = RT_ALIGN_32(cbRing0 + cbRing3 + cbRC + cbShared, HOST_PAGE_SIZE); + AssertLogRelMsgReturn(cbTotal <= DBGF_MAX_TRACER_INSTANCE_SIZE, + ("Instance of tracer is too big: cbTotal=%u, max %u\n", cbTotal, DBGF_MAX_TRACER_INSTANCE_SIZE), + VERR_OUT_OF_RANGE); + + RTR0MEMOBJ hMemObj; + int rc = RTR0MemObjAllocPage(&hMemObj, cbTotal, false /*fExecutable*/); + if (RT_FAILURE(rc)) + return rc; + RT_BZERO(RTR0MemObjAddress(hMemObj), cbTotal); + + /* Map it. */ + RTR0MEMOBJ hMapObj; + rc = RTR0MemObjMapUserEx(&hMapObj, hMemObj, (RTR3PTR)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE, RTR0ProcHandleSelf(), + cbRing0, cbTotal - cbRing0); + if (RT_SUCCESS(rc)) + { + PDBGFTRACERINSR0 pTracerIns = (PDBGFTRACERINSR0)RTR0MemObjAddress(hMemObj); + struct DBGFTRACERINSR3 *pTracerInsR3 = (struct DBGFTRACERINSR3 *)((uint8_t *)pTracerIns + cbRing0); + + /* + * Initialize the ring-0 instance. + */ + pTracerIns->pGVM = pGVM; + pTracerIns->hMemObj = hMemObj; + pTracerIns->hMapObj = hMapObj; + pTracerIns->pSharedR0 = (PDBGFTRACERSHARED)((uint8_t *)pTracerIns + offShared); + pTracerIns->cbRingBuf = cbRingBuf; + pTracerIns->pbRingBufR0 = (uint8_t *)(pTracerIns->pSharedR0 + 1); + + /* + * Initialize the ring-3 instance data as much as we can. + * Note! DBGFR3Tracer.cpp does this job for ring-3 only tracers. Keep in sync. + */ + pTracerInsR3->pVMR3 = pGVM->pVMR3; + pTracerInsR3->fR0Enabled = true; + pTracerInsR3->pSharedR3 = RTR0MemObjAddressR3(hMapObj) + cbRing3 + cbRC; + pTracerInsR3->pbRingBufR3 = RTR0MemObjAddressR3(hMapObj) + cbRing3 + cbRC + sizeof(DBGFTRACERSHARED); + + pTracerIns->pSharedR0->idEvt = 0; + pTracerIns->pSharedR0->cbRingBuf = cbRingBuf; + pTracerIns->pSharedR0->fEvtsWaiting = false; + pTracerIns->pSharedR0->fFlushThrdActive = false; + + /* + * Initialize the raw-mode instance data as much as possible. + */ + if (RCPtrMapping != NIL_RTRCPTR) + { + struct DBGFTRACERINSRC *pTracerInsRC = RCPtrMapping == NIL_RTRCPTR ? NULL + : (struct DBGFTRACERINSRC *)((uint8_t *)pTracerIns + cbRing0 + cbRing3); + + pTracerInsRC->pVMRC = pGVM->pVMRC; + } + + pGVM->dbgfr0.s.pTracerR0 = pTracerIns; + + /* + * We're done. + */ + *ppTracerInsR3 = RTR0MemObjAddressR3(hMapObj); + return rc; + } + + RTR0MemObjFree(hMemObj, true); + return rc; +} + + +/** + * Used by ring-3 DBGF to create a tracer instance that operates both in ring-3 + * and ring-0. + * + * Creates an instance of a tracer (for both ring-3 and ring-0, and optionally + * raw-mode context). + * + * @returns VBox status code. + * @param pGVM The global (ring-0) VM structure. + * @param pReq Pointer to the request buffer. + * @thread EMT(0) + */ +VMMR0_INT_DECL(int) DBGFR0TracerCreateReqHandler(PGVM pGVM, PDBGFTRACERCREATEREQ pReq) +{ + LogFlow(("DBGFR0TracerCreateReqHandler:\n")); + + /* + * Validate the request. + */ + AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER); + pReq->pTracerInsR3 = NIL_RTR3PTR; + + int rc = GVMMR0ValidateGVMandEMT(pGVM, 0); + AssertRCReturn(rc, rc); + + AssertReturn(pReq->cbRingBuf <= DBGF_MAX_TRACER_INSTANCE_SIZE, VERR_OUT_OF_RANGE); + + return dbgfR0TracerCreateWorker(pGVM, pReq->cbRingBuf, NIL_RTRCPTR /** @todo new raw-mode */, &pReq->pTracerInsR3); +} + |