PDMLdr.cpp revision 0d1eca640ef561d1d5eaa30414c6b330ba5e17c3
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/* $Id$ */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/** @file
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * PDM - Pluggable Device Manager, module loader.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/*
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * available from http://www.virtualbox.org. This file is free software;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * General Public License (GPL) as published by the Free Software
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * additional information or have any questions.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync//#define PDMLDR_FAKE_MODE
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/*******************************************************************************
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync* Header Files *
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync*******************************************************************************/
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#define LOG_GROUP LOG_GROUP_PDM_LDR
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#include "PDMInternal.h"
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#include <VBox/pdm.h>
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#include <VBox/mm.h>
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#include <VBox/vmm.h>
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#include <VBox/vm.h>
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#include <VBox/uvm.h>
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#include <VBox/sup.h>
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync#include <VBox/param.h>
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync#include <VBox/err.h>
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#include <VBox/hwaccm.h>
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#include <VBox/log.h>
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync#include <iprt/assert.h>
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync#include <iprt/alloc.h>
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync#include <iprt/ldr.h>
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync#include <iprt/path.h>
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#include <iprt/string.h>
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#include <limits.h>
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/*******************************************************************************
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync* Structures and Typedefs *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync*******************************************************************************/
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/**
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Structure which the user argument of the RTLdrGetBits() callback points to.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @internal
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsynctypedef struct PDMGETIMPORTARGS
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync{
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync PVM pVM;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync PPDMMOD pModule;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync} PDMGETIMPORTARGS, *PPDMGETIMPORTARGS;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/*******************************************************************************
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync* Internal Functions *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync*******************************************************************************/
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsyncstatic DECLCALLBACK(int) pdmR3GetImportGC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsyncstatic int pdmR3LoadR0U(PUVM pUVM, const char *pszFilename, const char *pszName);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsyncstatic char * pdmR3FileGC(const char *pszFile);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsyncstatic char * pdmR3FileR0(const char *pszFile);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsyncstatic char * pdmR3File(const char *pszFile, const char *pszDefaultExt, bool fShared);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsyncstatic DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/**
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Loads the VMMR0.r0 module early in the init process.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @returns VBox status code.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * @param pUVM Pointer to the user mode VM structure.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync */
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsyncPDMR3DECL(int) PDMR3LdrLoadVMMR0U(PUVM pUVM)
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync{
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync return pdmR3LoadR0U(pUVM, NULL, VMMR0_MAIN_MODULE_NAME);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync}
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/**
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Init the module loader part of PDM.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * This routine will load the Host Context Ring-0 and Guest
b3109af8dcc2a3da7f424aa05a4e84a64bf1c43fvboxsync * Context VMM modules.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @returns VBox stutus code.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @param pUVM Pointer to the user mode VM structure.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @param pvVMMR0Mod The opqaue returned by PDMR3LdrLoadVMMR0.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsyncint pdmR3LdrInitU(PUVM pUVM)
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync{
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#ifdef PDMLDR_FAKE_MODE
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync return VINF_SUCCESS;
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync#else
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync /*
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync * Load the mandatory GC module, the VMMR0.r0 is loaded before VM creation.
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync return PDMR3LoadGC(pUVM->pVM, NULL, VMMGC_MAIN_MODULE_NAME);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#endif
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync}
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync/**
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * Terminate the module loader part of PDM.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * This will unload and free all modules.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @param pVM The VM handle.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @remarks This is normally called twice during termination.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsyncvoid pdmR3LdrTermU(PUVM pUVM)
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync{
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync /*
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Free the modules.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync PPDMMOD pModule = pUVM->pdm.s.pModules;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pUVM->pdm.s.pModules = NULL;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync while (pModule)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync /* free loader item. */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (pModule->hLdrMod != NIL_RTLDRMOD)
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync int rc2 = RTLdrClose(pModule->hLdrMod);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync AssertRC(rc2);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pModule->hLdrMod = NIL_RTLDRMOD;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync /* free bits. */
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync switch (pModule->eType)
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync {
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync case PDMMOD_TYPE_R0:
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync {
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync Assert(pModule->ImageBase);
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync int rc2 = SUPFreeModule((void *)(uintptr_t)pModule->ImageBase);
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync AssertRC(rc2);
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync pModule->ImageBase = 0;
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync break;
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync }
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync case PDMMOD_TYPE_GC:
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync case PDMMOD_TYPE_R3:
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync /* MM will free this memory for us - it's alloc only memory. :-) */
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync break;
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync default:
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync AssertMsgFailed(("eType=%d\n", pModule->eType));
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync break;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pModule->pvBits = NULL;
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync void *pvFree = pModule;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pModule = pModule->pNext;
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync RTMemFree(pvFree);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync}
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/**
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Applies relocations to GC modules.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * This must be done very early in the relocation
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * process so that components can resolve GC symbols during relocation.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @param pUVM Pointer to the user mode VM structure.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @param offDelta Relocation delta relative to old location.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsyncPDMR3DECL(void) PDMR3LdrRelocateU(PUVM pUVM, RTGCINTPTR offDelta)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync{
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync LogFlow(("PDMR3LdrRelocate: offDelta=%VGv\n", offDelta));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync /*
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * GC Modules.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (pUVM->pdm.s.pModules)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync /*
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync * The relocation have to be done in two passes so imports
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync * can be correctely resolved. The first pass will update
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * the ImageBase saving the current value in OldImageBase.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * The second pass will do the actual relocation.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync /* pass 1 */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync PPDMMOD pCur;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync for (pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (pCur->eType == PDMMOD_TYPE_GC)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pCur->OldImageBase = pCur->ImageBase;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync pCur->ImageBase = MMHyperHC2GC(pUVM->pVM, pCur->pvBits);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync /* pass 2 */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync for (pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
2c44f485771ff1ffffd3d9e614f8406e33a90701vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (pCur->eType == PDMMOD_TYPE_GC)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync PDMGETIMPORTARGS Args;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync Args.pVM = pUVM->pVM;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync Args.pModule = pCur;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync int rc = RTLdrRelocate(pCur->hLdrMod, pCur->pvBits, pCur->ImageBase, pCur->OldImageBase,
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pdmR3GetImportGC, &Args);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync AssertFatalMsgRC(rc, ("RTLdrRelocate failed, rc=%d\n", rc));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync DBGFR3ModuleRelocate(pUVM->pVM, pCur->OldImageBase, pCur->ImageBase, RTLdrSize(pCur->hLdrMod),
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pCur->szFilename, pCur->szName);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync }
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync}
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/**
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Loads a module into the host context ring-3.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync * This is used by the driver and device init functions to load modules
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * containing the drivers and devices. The function can be extended to
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * load modules which are not native to the environment we're running in,
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * but at the moment this is not required.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * No reference counting is kept, since we don't implement any facilities
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * for unloading the module. But the module will naturally be released
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * when the VM terminates.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync *
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * @returns VBox status code.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * @param pUVM Pointer to the user mode VM structure.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @param pszFilename Filename of the module binary.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @param pszName Module name. Case sensitive and the length is limited!
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsyncint pdmR3LoadR3U(PUVM pUVM, const char *pszFilename, const char *pszName)
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync{
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync /*
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Validate input.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync AssertMsg(pUVM->pVM->pdm.s.offVM, ("bad init order!\n"));
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync Assert(pszFilename);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync size_t cchFilename = strlen(pszFilename);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync Assert(pszName);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync size_t cchName = strlen(pszName);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync PPDMMOD pCur;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync if (cchName >= sizeof(pCur->szName))
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync AssertMsgFailed(("Name is too long, cchName=%d pszName='%s'\n", cchName, pszName));
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync return VERR_INVALID_PARAMETER;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync /*
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * Try lookup the name and see if the module exists.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync for (pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (!strcmp(pCur->szName, pszName))
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (pCur->eType == PDMMOD_TYPE_R3)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync return VINF_PDM_ALREADY_LOADED;
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync return VERR_PDM_MODULE_NAME_CLASH;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync /*
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Allocate the module list node and initialize it.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync const char *pszSuff = RTLdrGetSuff();
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync size_t cchSuff = strlen(pszSuff);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + cchFilename + cchSuff);
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync if (!pModule)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync return VERR_NO_MEMORY;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pModule->eType = PDMMOD_TYPE_R3;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync memcpy(pModule->szName, pszName, cchName); /* memory is zero'ed, no need to copy terminator :-) */
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync memcpy(pModule->szFilename, pszFilename, cchFilename);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync memcpy(&pModule->szFilename[cchFilename], pszSuff, cchSuff);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync /*
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Load the loader item.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync int rc = SUPR3HardenedVerifyFile(pModule->szFilename, "pdmR3LoadR3U", NULL);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (RT_SUCCESS(rc))
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync rc = RTLdrLoad(pModule->szFilename, &pModule->hLdrMod);
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync if (VBOX_SUCCESS(rc))
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pModule->pNext = pUVM->pdm.s.pModules;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pUVM->pdm.s.pModules = pModule;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync return rc;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync /* Something went wrong, most likely module not found. Don't consider other unlikely errors */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync RTMemFree(pModule);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync return VMSetError(pUVM->pVM, rc, RT_SRC_POS, N_("Unable to load R3 module %s"), pszFilename);
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync}
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync/**
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Resolve an external symbol during RTLdrGetBits() of a GC module.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @returns VBox status code.
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync * @param hLdrMod The loader module handle.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * @param pszModule Module name.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * @param pszSymbol Symbol name, NULL if uSymbol should be used.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @param pValue Where to store the symbol value (address).
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @param pvUser User argument.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsyncstatic DECLCALLBACK(int) pdmR3GetImportGC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync{
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync PVM pVM = ((PPDMGETIMPORTARGS)pvUser)->pVM;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync PPDMMOD pModule = ((PPDMGETIMPORTARGS)pvUser)->pModule;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync /*
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Adjust input.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (pszModule && !*pszModule)
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync pszModule = NULL;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync /*
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * Builtin module.
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (!pszModule || !strcmp(pszModule, "VMMGCBuiltin.gc"))
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync int rc = VINF_SUCCESS;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (!strcmp(pszSymbol, "g_VM"))
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *pValue = pVM->pVMGC;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync else if (!strcmp(pszSymbol, "g_CPUM"))
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync *pValue = VM_GUEST_ADDR(pVM, &pVM->cpum);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync else if (!strcmp(pszSymbol, "g_TRPM"))
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync *pValue = VM_GUEST_ADDR(pVM, &pVM->trpm);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync else if ( !strncmp(pszSymbol, "VMM", 3)
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync || !strcmp(pszSymbol, "g_Logger")
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync || !strcmp(pszSymbol, "g_RelLogger"))
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync RTGCPTR GCPtr = 0;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync rc = VMMR3GetImportGC(pVM, pszSymbol, &GCPtr);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (VBOX_SUCCESS(rc))
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync *pValue = GCPtr;
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync else if ( !strncmp(pszSymbol, "TM", 2)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync || !strcmp(pszSymbol, "g_pSUPGlobalInfoPage"))
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync RTGCPTR GCPtr = 0;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync rc = TMR3GetImportGC(pVM, pszSymbol, &GCPtr);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync if (VBOX_SUCCESS(rc))
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync *pValue = GCPtr;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync else
2805b95732a8d26015a397626b96049a6e6573e7vboxsync {
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync AssertMsg(!pszModule, ("Unknown builtin symbol '%s' for module '%s'!\n", pszSymbol, pModule->szName)); NOREF(pModule);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync rc = VERR_SYMBOL_NOT_FOUND;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync if (VBOX_SUCCESS(rc) || pszModule)
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync return rc;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync /*
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * Search for module.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync */
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync PPDMMOD pCur = pVM->pUVM->pdm.s.pModules;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync while (pCur)
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if ( pCur->eType == PDMMOD_TYPE_GC
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync && ( !pszModule
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync || !strcmp(pCur->szName, pszModule))
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync )
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync {
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync /* Search for the symbol. */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync int rc = RTLdrGetSymbolEx(pCur->hLdrMod, pCur->pvBits, pCur->ImageBase, pszSymbol, pValue);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (VBOX_SUCCESS(rc))
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync AssertMsg(*pValue - pCur->ImageBase < RTLdrSize(pCur->hLdrMod),
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync ("%VGv-%VGv %s %VGv\n", (RTGCPTR)pCur->ImageBase,
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync (RTGCPTR)(pCur->ImageBase + RTLdrSize(pCur->hLdrMod) - 1),
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pszSymbol, (RTGCPTR)*pValue));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync return rc;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (pszModule)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync AssertMsgFailed(("Couldn't find symbol '%s' in module '%s'!\n", pszSymbol, pszModule));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync LogRel(("PDMLdr: Couldn't find symbol '%s' in module '%s'!\n", pszSymbol, pszModule));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync return VERR_SYMBOL_NOT_FOUND;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync /* next */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pCur = pCur->pNext;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync }
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync AssertMsgFailed(("Couldn't find module '%s' for resolving symbol '%s'!\n", pszModule, pszSymbol));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync return VERR_SYMBOL_NOT_FOUND;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync}
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/**
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Loads a module into the guest context (i.e. into the Hypervisor memory region).
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * The external (to PDM) use of this interface is to load VMMGC.gc.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @returns VBox status code.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @param pVM The VM to load it into.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @param pszFilename Filename of the module binary.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * @param pszName Module name. Case sensitive and the length is limited!
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsyncPDMR3DECL(int) PDMR3LoadGC(PVM pVM, const char *pszFilename, const char *pszName)
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync{
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync /*
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Validate input.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync PPDMMOD pCur = pVM->pUVM->pdm.s.pModules;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync while (pCur)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync if (!strcmp(pCur->szName, pszName))
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync return VERR_PDM_MODULE_NAME_CLASH;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync /* next */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pCur = pCur->pNext;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync }
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync /*
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * Find the file if not specified.
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync char *pszFile = NULL;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (!pszFilename)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pszFilename = pszFile = pdmR3FileGC(pszName);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync /*
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * Allocate the module list node.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync */
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
75a0540cb8c3cca698de583260c62e496041a3a5vboxsync if (!pModule)
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync {
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync RTMemTmpFree(pszFile);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync return VERR_NO_MEMORY;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync AssertMsg(strlen(pszName) + 1 < sizeof(pModule->szName),
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync ("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync strcpy(pModule->szName, pszName);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync pModule->eType = PDMMOD_TYPE_GC;
2805b95732a8d26015a397626b96049a6e6573e7vboxsync strcpy(pModule->szFilename, pszFilename);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync /*
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * Open the loader item.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync */
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync int rc = SUPR3HardenedVerifyFile(pszFilename, "PDMR3LoadGC", NULL);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync if (RT_SUCCESS(rc))
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync rc = RTLdrOpen(pszFilename, &pModule->hLdrMod);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync if (VBOX_SUCCESS(rc))
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync {
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync /*
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * Allocate space in the hypervisor.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync size_t cb = RTLdrSize(pModule->hLdrMod);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync cb = RT_ALIGN_Z(cb, PAGE_SIZE);
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync rc = SUPPageAlloc(cb >> PAGE_SHIFT, &pModule->pvBits);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync if (VBOX_SUCCESS(rc))
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync {
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync RTGCPTR GCPtr;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync rc = MMR3HyperMapHCRam(pVM, pModule->pvBits, cb, true, pModule->szName, &GCPtr);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (VBOX_SUCCESS(rc))
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync /*
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Get relocated image bits.
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync Assert(MMHyperHC2GC(pVM, pModule->pvBits) == GCPtr);
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync pModule->ImageBase = GCPtr;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync PDMGETIMPORTARGS Args;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync Args.pVM = pVM;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync Args.pModule = pModule;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync rc = RTLdrGetBits(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pdmR3GetImportGC, &Args);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync if (VBOX_SUCCESS(rc))
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync {
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync /*
a734bb626f889ee3334bfc381be194b4ec56aae6vboxsync * Insert the module.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync PUVM pUVM = pVM->pUVM;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync if (pUVM->pdm.s.pModules)
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync {
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync /* we don't expect this list to be very long, so rather save the tail pointer. */
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync PPDMMOD pCur = pUVM->pdm.s.pModules;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync while (pCur->pNext)
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync pCur = pCur->pNext;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync pCur->pNext = pModule;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync else
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync pUVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync Log(("PDM: GC Module at %VGvx %s (%s)\n", (RTGCPTR)pModule->ImageBase, pszName, pszFilename));
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync RTMemTmpFree(pszFile);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync return VINF_SUCCESS;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync else
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync {
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync AssertRC(rc);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync SUPPageFree(pModule->pvBits, cb >> PAGE_SHIFT);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync else
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync AssertMsgFailed(("SUPPageAlloc(%d,) -> %Vrc\n", cb >> PAGE_SHIFT, rc));
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync int rc2 = RTLdrClose(pModule->hLdrMod);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync AssertRC(rc2);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync }
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync RTMemFree(pModule);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync RTMemTmpFree(pszFile);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync /* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync if (VBOX_FAILURE(rc))
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync return VMSetError(pVM, rc, RT_SRC_POS, N_("Cannot load GC module %s"), pszFilename);
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync return rc;
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync}
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync/**
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * Loads a module into the ring-0 context.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync *
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * @returns VBox status code.
0fcf82b2591711fa8980e8f5d9cad1b8f222d6d7vboxsync * @param pUVM Pointer to the user mode VM structure.
* @param pszFilename Filename of the module binary.
* @param pszName Module name. Case sensitive and the length is limited!
*/
static int pdmR3LoadR0U(PUVM pUVM, const char *pszFilename, const char *pszName)
{
/*
* Validate input.
*/
PPDMMOD pCur = pUVM->pdm.s.pModules;
while (pCur)
{
if (!strcmp(pCur->szName, pszName))
{
AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
return VERR_PDM_MODULE_NAME_CLASH;
}
/* next */
pCur = pCur->pNext;
}
/*
* Find the file if not specified.
*/
char *pszFile = NULL;
if (!pszFilename)
pszFilename = pszFile = pdmR3FileR0(pszName);
/*
* Allocate the module list node.
*/
PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
if (!pModule)
{
RTMemTmpFree(pszFile);
return VERR_NO_MEMORY;
}
AssertMsg(strlen(pszName) + 1 < sizeof(pModule->szName),
("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
strcpy(pModule->szName, pszName);
pModule->eType = PDMMOD_TYPE_R0;
strcpy(pModule->szFilename, pszFilename);
/*
* Ask the support library to load it.
*/
void *pvImageBase;
int rc = SUPLoadModule(pszFilename, pszName, &pvImageBase);
if (VBOX_SUCCESS(rc))
{
pModule->hLdrMod = NIL_RTLDRMOD;
pModule->ImageBase = (uintptr_t)pvImageBase;
/*
* Insert the module.
*/
if (pUVM->pdm.s.pModules)
{
/* we don't expect this list to be very long, so rather save the tail pointer. */
PPDMMOD pCur = pUVM->pdm.s.pModules;
while (pCur->pNext)
pCur = pCur->pNext;
pCur->pNext = pModule;
}
else
pUVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
Log(("PDM: GC Module at %VGvx %s (%s)\n", (RTGCPTR)pModule->ImageBase, pszName, pszFilename));
RTMemTmpFree(pszFile);
return VINF_SUCCESS;
}
RTMemFree(pModule);
RTMemTmpFree(pszFile);
LogRel(("pdmR3LoadR0U: pszName=\"%s\" rc=%Vrc\n", pszName, rc));
/* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
if (VBOX_FAILURE(rc) && pUVM->pVM) /** @todo VMR3SetErrorU. */
return VMSetError(pUVM->pVM, rc, RT_SRC_POS, N_("Cannot load R0 module %s"), pszFilename);
return rc;
}
/**
* Get the address of a symbol in a given HC ring 3 module.
*
* @returns VBox status code.
* @param pVM VM handle.
* @param pszModule Module name.
* @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
* ordinal value rather than a string pointer.
* @param ppvValue Where to store the symbol value.
*/
PDMR3DECL(int) PDMR3GetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue)
{
/*
* Validate input.
*/
AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
/*
* Find the module.
*/
for (PPDMMOD pModule = pVM->pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
{
if ( pModule->eType == PDMMOD_TYPE_R3
&& !strcmp(pModule->szName, pszModule))
{
RTUINTPTR Value = 0;
int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
if (VBOX_SUCCESS(rc))
{
*ppvValue = (void *)(uintptr_t)Value;
Assert((uintptr_t)*ppvValue == Value);
}
else
{
if (pszSymbol < (const char*)(void*)0x10000)
AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
else
AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
}
return rc;
}
}
AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
return VERR_SYMBOL_NOT_FOUND;
}
/**
* Get the address of a symbol in a given HC ring 0 module.
*
* @returns VBox status code.
* @param pVM VM handle.
* @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumes.
* @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
* ordinal value rather than a string pointer.
* @param ppvValue Where to store the symbol value.
*/
PDMR3DECL(int) PDMR3GetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
{
#ifdef PDMLDR_FAKE_MODE
*ppvValue = 0xdeadbeef;
return VINF_SUCCESS;
#else
/*
* Validate input.
*/
AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
if (!pszModule)
pszModule = "VMMR0.r0";
/*
* Find the module.
*/
for (PPDMMOD pModule = pVM->pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
{
if ( pModule->eType == PDMMOD_TYPE_R0
&& !strcmp(pModule->szName, pszModule))
{
int rc = SUPGetSymbolR0((void *)(uintptr_t)pModule->ImageBase, pszSymbol, (void **)ppvValue);
if (VBOX_FAILURE(rc))
{
AssertMsgRC(rc, ("Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
LogRel(("PDMGetSymbol: Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
}
return rc;
}
}
AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
return VERR_SYMBOL_NOT_FOUND;
#endif
}
/**
* Same as PDMR3GetSymbolR0 except that the module will be attempted loaded if not found.
*
* @returns VBox status code.
* @param pVM VM handle.
* @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumed.
* @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
* ordinal value rather than a string pointer.
* @param ppvValue Where to store the symbol value.
*/
PDMR3DECL(int) PDMR3GetSymbolR0Lazy(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
{
#ifdef PDMLDR_FAKE_MODE
*ppvValue = 0xdeadbeef;
return VINF_SUCCESS;
#else
/*
* Since we're lazy, we'll only check if the module is present
* and hand it over to PDMR3GetSymbolR0 when that's done.
*/
AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
if (pszModule)
{
AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
PPDMMOD pModule;
for (pModule = pVM->pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
if ( pModule->eType == PDMMOD_TYPE_R0
&& !strcmp(pModule->szName, pszModule))
break;
if (!pModule)
{
int rc = pdmR3LoadR0U(pVM->pUVM, NULL, pszModule);
AssertMsgRCReturn(rc, ("pszModule=%s rc=%Vrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
}
}
return PDMR3GetSymbolR0(pVM, pszModule, pszSymbol, ppvValue);
#endif
}
/**
* Get the address of a symbol in a given GC module.
*
* @returns VBox status code.
* @param pVM VM handle.
* @param pszModule Module name. If NULL the main R0 module (VMMGC.gc) is assumes.
* @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
* ordinal value rather than a string pointer.
* @param pGCPtrValue Where to store the symbol value.
*/
PDMR3DECL(int) PDMR3GetSymbolGC(PVM pVM, const char *pszModule, const char *pszSymbol, PRTGCPTR32 pGCPtrValue)
{
#ifdef PDMLDR_FAKE_MODE
*pGCPtrValue = 0xfeedf00d;
return VINF_SUCCESS;
#else
/*
* Validate input.
*/
AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
if (!pszModule)
pszModule = "VMMGC.gc";
/*
* Find the module.
*/
for (PPDMMOD pModule = pVM->pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
{
if ( pModule->eType == PDMMOD_TYPE_GC
&& !strcmp(pModule->szName, pszModule))
{
RTUINTPTR Value;
int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
if (VBOX_SUCCESS(rc))
{
*pGCPtrValue = (RTGCPTR)Value;
Assert(*pGCPtrValue == Value);
}
else
{
if (pszSymbol < (const char*)(void*)0x10000)
AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
else
AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
}
return rc;
}
}
AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
return VERR_SYMBOL_NOT_FOUND;
#endif
}
/**
* Same as PDMR3GetSymbolGC except that the module will be attempted loaded if not found.
*
* @returns VBox status code.
* @param pVM VM handle.
* @param pszModule Module name. If NULL the main R0 module (VMMGC.gc) is assumes.
* @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
* ordinal value rather than a string pointer.
* @param pGCPtrValue Where to store the symbol value.
*/
PDMR3DECL(int) PDMR3GetSymbolGCLazy(PVM pVM, const char *pszModule, const char *pszSymbol, PRTGCPTR32 pGCPtrValue)
{
#ifdef PDMLDR_FAKE_MODE
*pGCPtrValue = 0xfeedf00d;
return VINF_SUCCESS;
#else
/*
* Since we're lazy, we'll only check if the module is present
* and hand it over to PDMR3GetSymbolGC when that's done.
*/
AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
if (pszModule)
{
AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
PPDMMOD pModule;
for (pModule = pVM->pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
if ( pModule->eType == PDMMOD_TYPE_GC
&& !strcmp(pModule->szName, pszModule))
break;
if (!pModule)
{
char *pszFilename = pdmR3FileGC(pszModule);
AssertMsgReturn(pszFilename, ("pszModule=%s\n", pszModule), VERR_MODULE_NOT_FOUND);
int rc = PDMR3LoadGC(pVM, pszFilename, pszModule);
RTMemTmpFree(pszFilename);
AssertMsgRCReturn(rc, ("pszModule=%s rc=%Vrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
}
}
return PDMR3GetSymbolGC(pVM, pszModule, pszSymbol, pGCPtrValue);
#endif
}
/**
* Constructs the full filename for a R3 image file.
*
* @returns Pointer to temporary memory containing the filename.
* Caller must free this using RTMemTmpFree().
* @returns NULL on failure.
* @param pszFile File name (no path).
* @todo We'll have this elsewhere than in the root later!
*/
char *pdmR3FileR3(const char *pszFile, bool fShared)
{
return pdmR3File(pszFile, NULL, fShared);
}
/**
* Constructs the full filename for a R0 image file.
*
* @returns Pointer to temporary memory containing the filename.
* Caller must free this using RTMemTmpFree().
* @returns NULL on failure.
* @param pszFile File name (no path).
* @todo We'll have this elsewhere than in the root later!
*/
char * pdmR3FileR0(const char *pszFile)
{
return pdmR3File(pszFile, NULL, /*fShared=*/false);
}
/**
* Constructs the full filename for a GC image file.
*
* @returns Pointer to temporary memory containing the filename.
* Caller must free this using RTMemTmpFree().
* @returns NULL on failure.
* @param pszFile File name (no path).
* @todo We'll have this elsewhere than in the root later!
*/
char * pdmR3FileGC(const char *pszFile)
{
return pdmR3File(pszFile, NULL, /*fShared=*/false);
}
/**
* Worker for pdmR3File().
*
* @returns Pointer to temporary memory containing the filename.
* Caller must free this using RTMemTmpFree().
* @returns NULL on failure.
* @param pszDir Directory part
* @param pszFile File name part
* @param pszDefaultExt Extension part
*/
static char * pdmR3FileConstruct(const char *pszDir, const char *pszFile, const char *pszDefaultExt)
{
/*
* Allocate temp memory for return buffer.
*/
unsigned cchDir = strlen(pszDir);
unsigned cchFile = strlen(pszFile);
unsigned cchDefaultExt;
/*
* Default extention?
*/
if (!pszDefaultExt || strchr(pszFile, '.'))
cchDefaultExt = 0;
else
cchDefaultExt = strlen(pszDefaultExt);
unsigned cchPath = cchDir + 1 + cchFile + cchDefaultExt + 1;
if (cchPath > RTPATH_MAX)
{
AssertMsgFailed(("Path too long!\n"));
return NULL;
}
char *pszRet = (char *)RTMemTmpAlloc(cchDir + 1 + cchFile + cchDefaultExt + 1);
if (!pszRet)
{
AssertMsgFailed(("Out of temporary memory!\n"));
return NULL;
}
/*
* Construct the filename.
*/
memcpy(pszRet, pszDir, cchDir);
pszRet[cchDir++] = '/'; /* this works everywhere */
memcpy(pszRet + cchDir, pszFile, cchFile + 1);
if (cchDefaultExt)
memcpy(pszRet + cchDir + cchFile, pszDefaultExt, cchDefaultExt + 1);
return pszRet;
}
/**
* Worker for pdmR3FileGC(), pdmR3FileR0() and pdmR3FileR3().
*
* @returns Pointer to temporary memory containing the filename.
* Caller must free this using RTMemTmpFree().
* @returns NULL on failure.
* @param pszFile File name (no path).
* @param pszDefaultExt The default extention, NULL if none.
* @param fShared If true, search in the shared directory (/usr/lib on Unix), else
* search in the private directory (/usr/lib/virtualbox on Unix).
* Ignored if VBOX_PATH_SHARED_LIBS is not defined.
* @todo We'll have this elsewhere than in the root later!
* @todo Remove the fShared hack again once we don't need to link against VBoxDD anymore!
*/
static char * pdmR3File(const char *pszFile, const char *pszDefaultExt, bool fShared)
{
char szPath[RTPATH_MAX];
int rc;
rc = fShared ? RTPathSharedLibs(szPath, sizeof(szPath))
: RTPathAppPrivateArch(szPath, sizeof(szPath));
if (!VBOX_SUCCESS(rc))
{
AssertMsgFailed(("RTPathProgram(,%d) failed rc=%d!\n", sizeof(szPath), rc));
return NULL;
}
return pdmR3FileConstruct(szPath, pszFile, pszDefaultExt);
}
/** @internal */
typedef struct QMFEIPARG
{
uint32_t uEIP;
char *pszNearSym1;
unsigned cchNearSym1;
RTINTPTR offNearSym1;
char *pszNearSym2;
unsigned cchNearSym2;
RTINTPTR offNearSym2;
} QMFEIPARG, *PQMFEIPARG;
/**
* Queries module information from an EIP.
*
* This is typically used to locate a crash address.
*
* @returns VBox status code.
* @param pVM VM handle
* @param uEIP EIP to locate.
* @param pszModName Where to store the module name.
* @param cchModName Size of the module name buffer.
* @param pMod Base address of the module.
* @param pszNearSym1 Name of the closes symbol from below.
* @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
* @param pNearSym1 The address of pszNearSym1.
* @param pszNearSym2 Name of the closes symbol from below.
* @param cchNearSym2 Size of the buffer pointed to by pszNearSym2.
* @param pNearSym2 The address of pszNearSym2.
*/
PDMR3DECL(int) PDMR3QueryModFromEIP(PVM pVM, uint32_t uEIP,
char *pszModName, unsigned cchModName, RTGCPTR *pMod,
char *pszNearSym1, unsigned cchNearSym1, RTGCPTR *pNearSym1,
char *pszNearSym2, unsigned cchNearSym2, RTGCPTR *pNearSym2)
{
int rc = VERR_MODULE_NOT_FOUND;
PPDMMOD pCur;
for (pCur = pVM->pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
{
/* Skip anything which isn't in GC. */
if (pCur->eType != PDMMOD_TYPE_GC)
continue;
if ((RTUINTPTR)uEIP - pCur->ImageBase < RTLdrSize(pCur->hLdrMod))
{
if (pMod)
*pMod = pCur->ImageBase;
if (pszModName && cchModName)
{
*pszModName = '\0';
strncat(pszModName, pCur->szName, cchModName);
}
if (pNearSym1) *pNearSym1 = 0;
if (pNearSym2) *pNearSym2 = 0;
if (pszNearSym1) *pszNearSym1 = '\0';
if (pszNearSym2) *pszNearSym2 = '\0';
/*
* Locate the nearest symbols.
*/
QMFEIPARG Args;
Args.uEIP = uEIP;
Args.pszNearSym1 = pszNearSym1;
Args.cchNearSym1 = cchNearSym1;
Args.offNearSym1 = INT_MIN; /** @todo fix INT_MIN/MAX! */
Args.pszNearSym2 = pszNearSym2;
Args.cchNearSym2 = cchNearSym2;
Args.offNearSym2 = INT_MAX;
rc = RTLdrEnumSymbols(pCur->hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, pCur->pvBits, pCur->ImageBase,
pdmR3QueryModFromEIPEnumSymbols, &Args);
if (pNearSym1 && Args.offNearSym1 != INT_MIN)
*pNearSym1 = Args.offNearSym1 + uEIP;
if (pNearSym2 && Args.offNearSym2 != INT_MAX)
*pNearSym2 = Args.offNearSym2 + uEIP;
rc = VINF_SUCCESS;
if (pCur->eType == PDMMOD_TYPE_GC)
break;
}
}
return rc;
}
/**
* Enumeration callback function used by RTLdrEnumSymbols().
*
* @returns VBox status code. Failure will stop the enumeration.
* @param hLdrMod The loader module handle.
* @param pszSymbol Symbol name. NULL if ordinal only.
* @param uSymbol Symbol ordinal, ~0 if not used.
* @param Value Symbol value.
* @param pvUser The user argument specified to RTLdrEnumSymbols().
*/
static DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
{
PQMFEIPARG pArgs = (PQMFEIPARG)pvUser;
RTINTPTR off = Value - pArgs->uEIP;
if (off <= 0) /* near1 is before or at same location. */
{
if (off > pArgs->offNearSym1)
{
pArgs->offNearSym1 = off;
if (pArgs->pszNearSym1 && pArgs->cchNearSym1)
{
*pArgs->pszNearSym1 = '\0';
if (pszSymbol)
strncat(pArgs->pszNearSym1, pszSymbol, pArgs->cchNearSym1);
else
{
char szOrd[32];
RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
strncat(pArgs->pszNearSym1, szOrd, pArgs->cchNearSym1);
}
}
}
}
else /* near2 is after */
{
if (off < pArgs->offNearSym2)
{
pArgs->offNearSym2 = off;
if (pArgs->pszNearSym2 && pArgs->cchNearSym2)
{
*pArgs->pszNearSym2 = '\0';
if (pszSymbol)
strncat(pArgs->pszNearSym2, pszSymbol, pArgs->cchNearSym2);
else
{
char szOrd[32];
RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
strncat(pArgs->pszNearSym2, szOrd, pArgs->cchNearSym2);
}
}
}
}
return VINF_SUCCESS;
}
/**
* Enumerate all PDM modules.
*
* @returns VBox status.
* @param pVM VM Handle.
* @param pfnCallback Function to call back for each of the modules.
* @param pvArg User argument.
*/
PDMR3DECL(int) PDMR3EnumModules(PVM pVM, PFNPDMR3ENUM pfnCallback, void *pvArg)
{
PPDMMOD pCur;
for (pCur = pVM->pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
{
int rc = pfnCallback(pVM,
pCur->szFilename,
pCur->szName,
pCur->ImageBase,
pCur->eType == PDMMOD_TYPE_GC ? RTLdrSize(pCur->hLdrMod) : 0,
pCur->eType == PDMMOD_TYPE_GC);
if (VBOX_FAILURE(rc))
return rc;
}
return VINF_SUCCESS;
}