diff options
Diffstat (limited to 'src/VBox/Runtime/common/ldr/ldrMemory.cpp')
-rw-r--r-- | src/VBox/Runtime/common/ldr/ldrMemory.cpp | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/ldr/ldrMemory.cpp b/src/VBox/Runtime/common/ldr/ldrMemory.cpp new file mode 100644 index 00000000..7e82c90b --- /dev/null +++ b/src/VBox/Runtime/common/ldr/ldrMemory.cpp @@ -0,0 +1,324 @@ + +/* $Id: ldrMemory.cpp $ */ +/** @file + * IPRT - Binary Image Loader, The Memory/Debugger Oriented Parts. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define LOG_GROUP RTLOGGROUP_LDR +#include <iprt/ldr.h> +#include "internal/iprt.h" + +#include <iprt/alloc.h> +#include <iprt/assert.h> +#include <iprt/log.h> +#include <iprt/err.h> +#include <iprt/string.h> +#include "internal/ldr.h" + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Memory reader (for debuggers) instance. + */ +typedef struct RTLDRRDRMEM +{ + /** The core. */ + RTLDRREADER Core; + /** The size of the image. */ + size_t cbImage; + /** The current offset. */ + size_t offCur; + + /** User parameter for the reader and destructor functions.*/ + void *pvUser; + /** Read function. */ + PFNRTLDRRDRMEMREAD pfnRead; + /** Destructor callback. */ + PFNRTLDRRDRMEMDTOR pfnDtor; + + /** Mapping of the file. */ + void *pvMapping; + /** Mapping usage counter. */ + uint32_t cMappings; + + /** The fake filename (variable size). */ + char szName[1]; +} RTLDRRDRMEM; +/** Memory based loader reader instance data. */ +typedef RTLDRRDRMEM *PRTLDRRDRMEM; + + +/** @callback_method_impl{FNRTLDRRDRMEMDTOR, + * Default destructor - pvUser points to the image memory block.} + */ +static DECLCALLBACK(void) rtldrRdrMemDefaultDtor(void *pvUser) +{ + RTMemFree(pvUser); +} + + +/** @callback_method_impl{FNRTLDRRDRMEMREAD, + * Default memory reader - pvUser points to the image memory block.} + */ +static DECLCALLBACK(int) rtldrRdrMemDefaultReader(void *pvBuf, size_t cb, size_t off, void *pvUser) +{ + memcpy(pvBuf, (uint8_t *)pvUser + off, cb); + return VINF_SUCCESS; +} + + +/** @copydoc RTLDRREADER::pfnRead */ +static DECLCALLBACK(int) rtldrRdrMem_Read(PRTLDRREADER pReader, void *pvBuf, size_t cb, RTFOFF off) +{ + PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader; + + AssertReturn(off >= 0, VERR_INVALID_PARAMETER); + if ( cb > pThis->cbImage + || off > (RTFOFF)pThis->cbImage + || off + (RTFOFF)cb > (RTFOFF)pThis->cbImage) + { + pThis->offCur = pThis->cbImage; + return VERR_EOF; + } + + int rc = pThis->pfnRead(pvBuf, cb, (size_t)off, pThis->pvUser); + if (RT_SUCCESS(rc)) + pThis->offCur = (size_t)off + cb; + else + pThis->offCur = ~(size_t)0; + return rc; +} + + +/** @copydoc RTLDRREADER::pfnTell */ +static DECLCALLBACK(RTFOFF) rtldrRdrMem_Tell(PRTLDRREADER pReader) +{ + PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader; + return pThis->offCur; +} + + +/** @copydoc RTLDRREADER::pfnSize */ +static DECLCALLBACK(RTFOFF) rtldrRdrMem_Size(PRTLDRREADER pReader) +{ + PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader; + return pThis->cbImage; +} + + +/** @copydoc RTLDRREADER::pfnLogName */ +static DECLCALLBACK(const char *) rtldrRdrMem_LogName(PRTLDRREADER pReader) +{ + PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader; + return pThis->szName; +} + + +/** @copydoc RTLDRREADER::pfnMap */ +static DECLCALLBACK(int) rtldrRdrMem_Map(PRTLDRREADER pReader, const void **ppvBits) +{ + PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader; + + /* + * Already mapped? + */ + if (pThis->pvMapping) + { + pThis->cMappings++; + *ppvBits = pThis->pvMapping; + return VINF_SUCCESS; + } + + /* + * Allocate memory. + */ + pThis->pvMapping = RTMemAlloc(pThis->cbImage); + if (!pThis->pvMapping) + return VERR_NO_MEMORY; + int rc = rtldrRdrMem_Read(pReader, pThis->pvMapping, pThis->cbImage, 0); + if (RT_SUCCESS(rc)) + { + pThis->cMappings = 1; + *ppvBits = pThis->pvMapping; + } + else + { + RTMemFree(pThis->pvMapping); + pThis->pvMapping = NULL; + } + + return rc; +} + + +/** @copydoc RTLDRREADER::pfnUnmap */ +static DECLCALLBACK(int) rtldrRdrMem_Unmap(PRTLDRREADER pReader, const void *pvBits) +{ + PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader; + AssertReturn(pThis->cMappings > 0, VERR_INVALID_PARAMETER); + + if (!--pThis->cMappings) + { + RTMemFree(pThis->pvMapping); + pThis->pvMapping = NULL; + } + + NOREF(pvBits); + return VINF_SUCCESS; +} + + +/** @copydoc RTLDRREADER::pfnDestroy */ +static DECLCALLBACK(int) rtldrRdrMem_Destroy(PRTLDRREADER pReader) +{ + PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader; + pThis->pfnDtor(pThis->pvUser); + RTMemFree(pThis); + return VINF_SUCCESS; +} + + +/** + * Opens a memory based loader reader. + * + * @returns iprt status code. + * @param ppReader Where to store the reader instance on success. + * @param pszName The name to give the image. + * @param cbImage The image size. + * @param pfnRead The reader function. If NULL, a default reader is + * used that assumes pvUser points to a memory buffer + * of at least @a cbImage size. + * @param pfnDtor The destructor. If NULL, a default destructore is + * used that will call RTMemFree on @a pvUser. + * @param pvUser User argument. If either @a pfnRead or @a pfnDtor + * is NULL, this must be a pointer to readable memory + * (see above). + */ +static int rtldrRdrMem_Create(PRTLDRREADER *ppReader, const char *pszName, size_t cbImage, + PFNRTLDRRDRMEMREAD pfnRead, PFNRTLDRRDRMEMDTOR pfnDtor, void *pvUser) +{ +#if ARCH_BITS > 32 /* 'ing gcc. */ + AssertReturn(cbImage < RTFOFF_MAX, VERR_INVALID_PARAMETER); +#endif + AssertReturn((RTFOFF)cbImage > 0, VERR_INVALID_PARAMETER); + + size_t cchName = strlen(pszName); + int rc = VERR_NO_MEMORY; + PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)RTMemAlloc(sizeof(*pThis) + cchName); + if (pThis) + { + memcpy(pThis->szName, pszName, cchName + 1); + pThis->cbImage = cbImage; + pThis->pvUser = pvUser; + pThis->offCur = 0; + pThis->pvUser = pvUser; + pThis->pfnRead = pfnRead ? pfnRead : rtldrRdrMemDefaultReader; + pThis->pfnDtor = pfnDtor ? pfnDtor : rtldrRdrMemDefaultDtor; + pThis->pvMapping = NULL; + pThis->cMappings = 0; + pThis->Core.pszName = "rdrmem"; + pThis->Core.pfnRead = rtldrRdrMem_Read; + pThis->Core.pfnTell = rtldrRdrMem_Tell; + pThis->Core.pfnSize = rtldrRdrMem_Size; + pThis->Core.pfnLogName = rtldrRdrMem_LogName; + pThis->Core.pfnMap = rtldrRdrMem_Map; + pThis->Core.pfnUnmap = rtldrRdrMem_Unmap; + pThis->Core.pfnDestroy = rtldrRdrMem_Destroy; + *ppReader = &pThis->Core; + return VINF_SUCCESS; + } + + *ppReader = NULL; + return rc; +} + + +RTDECL(int) RTLdrOpenInMemory(const char *pszName, uint32_t fFlags, RTLDRARCH enmArch, size_t cbImage, + PFNRTLDRRDRMEMREAD pfnRead, PFNRTLDRRDRMEMDTOR pfnDtor, void *pvUser, + PRTLDRMOD phLdrMod) +{ + LogFlow(("RTLdrOpenInMemory: pszName=%p:{%s} fFlags=%#x enmArch=%d cbImage=%#zx pfnRead=%p pfnDtor=%p pvUser=%p phLdrMod=%p\n", + pszName, pszName, fFlags, enmArch, cbImage, pfnRead, pfnDtor, pvUser, phLdrMod)); + + if (!pfnRead || !pfnDtor) + AssertPtrReturn(pvUser, VERR_INVALID_POINTER); + if (!pfnDtor) + pfnDtor = rtldrRdrMemDefaultDtor; + else + AssertPtrReturn(pfnRead, VERR_INVALID_POINTER); + + /* The rest of the validations will call the destructor. */ + AssertMsgReturnStmt(!(fFlags & ~RTLDR_O_VALID_MASK), ("%#x\n", fFlags), + pfnDtor(pvUser), VERR_INVALID_PARAMETER); + AssertMsgReturnStmt(enmArch > RTLDRARCH_INVALID && enmArch < RTLDRARCH_END, ("%d\n", enmArch), + pfnDtor(pvUser), VERR_INVALID_PARAMETER); + if (!pfnRead) + pfnRead = rtldrRdrMemDefaultReader; + else + AssertReturnStmt(RT_VALID_PTR(pfnRead), pfnDtor(pvUser), VERR_INVALID_POINTER); + AssertReturnStmt(cbImage > 0, pfnDtor(pvUser), VERR_INVALID_PARAMETER); + + /* + * Resolve RTLDRARCH_HOST. + */ + if (enmArch == RTLDRARCH_HOST) +#if defined(RT_ARCH_AMD64) + enmArch = RTLDRARCH_AMD64; +#elif defined(RT_ARCH_X86) + enmArch = RTLDRARCH_X86_32; +#else + enmArch = RTLDRARCH_WHATEVER; +#endif + + /* + * Create file reader & invoke worker which identifies and calls the image interpreter. + */ + PRTLDRREADER pReader = NULL; /* gcc may be wrong */ + int rc = rtldrRdrMem_Create(&pReader, pszName, cbImage, pfnRead, pfnDtor, pvUser); + if (RT_SUCCESS(rc)) + { + rc = rtldrOpenWithReader(pReader, fFlags, enmArch, phLdrMod); + if (RT_SUCCESS(rc)) + { + LogFlow(("RTLdrOpen: return %Rrc *phLdrMod\n", rc, *phLdrMod)); + return rc; + } + + pReader->pfnDestroy(pReader); + } + else + pfnDtor(pvUser), + *phLdrMod = NIL_RTLDRMOD; + + LogFlow(("RTLdrOpen: return %Rrc\n", rc)); + return rc; +} +RT_EXPORT_SYMBOL(RTLdrOpenInMemory); + |