PDMLdr.cpp revision d14b45df33b70c47b6eab2507de958c04711f38c
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * PDM - Pluggable Device Manager, module loader.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Copyright (C) 2006-2007 innotek GmbH
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * This file is part of VirtualBox Open Source Edition (OSE), as
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * available from http://www.virtualbox.org. This file is free software;
0662ed52e814f8f08ef0e09956413a792584eddffuankg * you can redistribute it and/or modify it under the terms of the GNU
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * General Public License as published by the Free Software Foundation,
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * distribution. VirtualBox OSE is distributed in the hope that it will
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * be useful, but WITHOUT ANY WARRANTY of any kind.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes//#define PDMLDR_FAKE_MODE
70953fb44a7140fe206c3a5f011e24209c8c5c6abnicholes/*******************************************************************************
44f575c8cb19a7a5cd61664a7848be6bc197df02fuankg* Header Files *
b387b9d37fc71c534f4718777454a8f5a1169017fuankg*******************************************************************************/
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes/*******************************************************************************
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes* Structures and Typedefs *
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes*******************************************************************************/
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Structure which the user argument of the RTLdrGetBits() callback points to.
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg/*******************************************************************************
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes* Internal Functions *
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes*******************************************************************************/
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholesstatic DECLCALLBACK(int) pdmr3GetImportGC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholesstatic int pdmR3LoadR0(PVM pVM, const char *pszFilename, const char *pszName);
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholesstatic char * pdmR3File(const char *pszFile, const char *pszDefaultExt, bool fShared);
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholesstatic DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser);
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Loads the VMMR0.r0 module before the VM is created.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * The opqaue VMMR0 module pointer is passed on to PDMR3Init later in
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * the init process or PDMR3LdrUnloadVMMR0 in case of some init failure before PDMR3Init.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * @returns VBox status code.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * @param ppvOpaque Where to return the opaque VMMR0.r0 module handle one success.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * @remarks Yes, this is a kind of hacky and should go away. See @todo in VMR3Create.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Resolve the filename and allocate the module list node.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes char *pszFilename = pdmR3FileR0(VMMR0_MAIN_MODULE_NAME);
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Ask the support library to load it.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes int rc = SUPLoadModule(pModule->szFilename, pModule->szName, &pvImageBase);
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes Log(("PDMR3LdrLoadVMMR0: Loaded %s at %VGvx (%s)\n", pModule->szName, (RTGCPTR)pModule->ImageBase, pModule->szFilename));
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes LogRel(("PDMR3LdrLoadVMMR0: rc=%Vrc szName=%s szFilename=%s\n", rc, pModule->szName, pModule->szFilename));
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Register the VMMR0.r0 module with the created VM or unload it if
0662ed52e814f8f08ef0e09956413a792584eddffuankg * we failed to create the VM (pVM == NULL).
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * @param pVM The VM pointer. NULL if we failed to create the VM and
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * the module should be unloaded and freed.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * @param pvOpaque The value returned by PDMR3LDrLoadVMMR0().
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * @remarks Yes, this is a kind of hacky and should go away. See @todo in VMR3Create.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholesPDMR3DECL(void) PDMR3LdrLoadVMMR0Part2(PVM pVM, void *pvOpaque)
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Register the R0 module loaded by PDMR3LdrLoadVMMR0
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Failed, unload the module.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes int rc2 = SUPFreeModule((void *)(uintptr_t)pModule->ImageBase);
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Init the module loader part of PDM.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * This routine will load the Host Context Ring-0 and Guest
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Context VMM modules.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * @returns VBox stutus code.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * @param pVM VM handle.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * @param pvVMMR0Mod The opqaue returned by PDMR3LdrLoadVMMR0.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Load the mandatory GC module, the VMMR0.r0 is loaded before VM creation.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes return PDMR3LoadGC(pVM, NULL, VMMGC_MAIN_MODULE_NAME);
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Terminate the module loader part of PDM.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * This will unload and free all modules.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * @param pVM The VM handle.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Free the modules.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes /* free loader item. */
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes /* free bits. */
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes int rc2 = SUPFreeModule((void *)(uintptr_t)pModule->ImageBase);
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes /* MM will free this memory for us - it's alloc only memory. :-) */
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * Applies relocations to GC modules.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * This must be done very early in the relocation
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * process so that components can resolve GC symbols during relocation.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * @param pVM VM handle.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes * @param offDelta Relocation delta relative to old location.
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholesPDMR3DECL(void) PDMR3LdrRelocate(PVM pVM, RTGCINTPTR offDelta)
3c937b528ca923d5b51e63def9f888af4a77bb40bnicholes LogFlow(("PDMR3LdrRelocate: offDelta=%VGv\n", offDelta));
return VERR_INVALID_PARAMETER;
return VINF_PDM_ALREADY_LOADED;
return VERR_PDM_MODULE_NAME_CLASH;
if (!pModule)
return VERR_NO_MEMORY;
return rc;
static DECLCALLBACK(int) pdmr3GetImportGC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
AssertMsg(!pszModule, ("Unknown builtin symbol '%s' for module '%s'!\n", pszSymbol, pModule->szName)); NOREF(pModule);
return rc;
while (pCur)
&& ( !pszModule
return rc;
if (pszModule)
return VERR_SYMBOL_NOT_FOUND;
return VERR_SYMBOL_NOT_FOUND;
while (pCur)
return VERR_PDM_MODULE_NAME_CLASH;
if (!pszFilename)
if (!pModule)
return VERR_NO_MEMORY;
("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
return VINF_SUCCESS;
/* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
return rc;
while (pCur)
return VERR_PDM_MODULE_NAME_CLASH;
if (!pszFilename)
if (!pModule)
return VERR_NO_MEMORY;
("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
void *pvImageBase;
return VINF_SUCCESS;
/* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
return rc;
PDMR3DECL(int) PDMR3GetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue)
int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
return rc;
return VERR_SYMBOL_NOT_FOUND;
PDMR3DECL(int) PDMR3GetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
#ifdef PDMLDR_FAKE_MODE
return VINF_SUCCESS;
if (!pszModule)
return rc;
return VERR_SYMBOL_NOT_FOUND;
PDMR3DECL(int) PDMR3GetSymbolR0Lazy(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
#ifdef PDMLDR_FAKE_MODE
return VINF_SUCCESS;
if (pszModule)
AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
if (!pModule)
PDMR3DECL(int) PDMR3GetSymbolGC(PVM pVM, const char *pszModule, const char *pszSymbol, PRTGCPTR pGCPtrValue)
#ifdef PDMLDR_FAKE_MODE
return VINF_SUCCESS;
if (!pszModule)
int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
return rc;
return VERR_SYMBOL_NOT_FOUND;
PDMR3DECL(int) PDMR3GetSymbolGCLazy(PVM pVM, const char *pszModule, const char *pszSymbol, PRTGCPTR pGCPtrValue)
#ifdef PDMLDR_FAKE_MODE
return VINF_SUCCESS;
if (pszModule)
AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
if (!pModule)
static char * pdmR3FileConstruct(const char *pszDir, const char *pszFile, const char *pszDefaultExt)
unsigned cchDefaultExt;
cchDefaultExt = 0;
return NULL;
if (!pszRet)
return NULL;
if (cchDefaultExt)
return pszRet;
* search in the private directory (/usr/lib/virtualbox on Unix).
int rc;
return NULL;
typedef struct QMFEIPARG
char *pszNearSym1;
unsigned cchNearSym1;
char *pszNearSym2;
unsigned cchNearSym2;
if (pMod)
return rc;
static DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
if (pszSymbol)
if (pszSymbol)
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;