/* $Id: ldrMemory.cpp 46087 2013-05-15 09:30:56Z vboxsync $ */ /** @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 #include "internal/iprt.h" #include #include #include #include #include #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=%#zu 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);