/* $Id: ldrkStuff.cpp 52403 2014-08-18 20:35:32Z vboxsync $ */ /** @file * IPRT - Binary Image Loader, kLdr Interface. */ /* * Copyright (C) 2006-2011 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 #include #include #include #include "internal/ldr.h" #define KLDR_ALREADY_INCLUDE_STD_TYPES #define KLDR_NO_KLDR_H_INCLUDES #include #include #include #include #include /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * kLdr file provider. */ typedef struct RTKLDRRDR { /** The core. */ KRDR Core; /** The IPRT bit reader. */ PRTLDRREADER pReader; } RTKLDRRDR, *PRTKLDRRDR; /** * IPRT module. */ typedef struct RTLDRMODKLDR { /** The Core module structure. */ RTLDRMODINTERNAL Core; /** The kLdr module. */ PKLDRMOD pMod; } RTLDRMODKLDR, *PRTLDRMODKLDR; /** * Arguments for a RTLDRMODKLDR callback wrapper. */ typedef struct RTLDRMODKLDRARGS { union { PFNRT pfn; PFNRTLDRENUMDBG pfnEnumDbgInfo; PFNRTLDRENUMSYMS pfnEnumSyms; PFNRTLDRIMPORT pfnGetImport; } u; void *pvUser; const void *pvBits; PRTLDRMODKLDR pMod; int rc; } RTLDRMODKLDRARGS, *PRTLDRMODKLDRARGS; /** * Converts a kLdr error code to an IPRT one. */ static int rtkldrConvertError(int krc) { if (!krc) return VINF_SUCCESS; switch (krc) { case KERR_INVALID_PARAMETER: return VERR_INVALID_PARAMETER; case KERR_INVALID_HANDLE: return VERR_INVALID_HANDLE; case KERR_NO_MEMORY: return VERR_NO_MEMORY; case KLDR_ERR_CPU_ARCH_MISMATCH: return VERR_LDR_ARCH_MISMATCH; case KLDR_ERR_UNKNOWN_FORMAT: case KLDR_ERR_MZ_NOT_SUPPORTED: return VERR_MZ_EXE_NOT_SUPPORTED; case KLDR_ERR_NE_NOT_SUPPORTED: return VERR_NE_EXE_NOT_SUPPORTED; case KLDR_ERR_LX_NOT_SUPPORTED: return VERR_LX_EXE_NOT_SUPPORTED; case KLDR_ERR_LE_NOT_SUPPORTED: return VERR_LE_EXE_NOT_SUPPORTED; case KLDR_ERR_PE_NOT_SUPPORTED: return VERR_PE_EXE_NOT_SUPPORTED; case KLDR_ERR_ELF_NOT_SUPPORTED: return VERR_ELF_EXE_NOT_SUPPORTED; case KLDR_ERR_MACHO_NOT_SUPPORTED: return VERR_INVALID_EXE_SIGNATURE; case KLDR_ERR_AOUT_NOT_SUPPORTED: return VERR_AOUT_EXE_NOT_SUPPORTED; case KLDR_ERR_MODULE_NOT_FOUND: return VERR_MODULE_NOT_FOUND; case KLDR_ERR_PREREQUISITE_MODULE_NOT_FOUND: return VERR_MODULE_NOT_FOUND; case KLDR_ERR_MAIN_STACK_ALLOC_FAILED: return VERR_NO_MEMORY; case KERR_BUFFER_OVERFLOW: return VERR_BUFFER_OVERFLOW; case KLDR_ERR_SYMBOL_NOT_FOUND: return VERR_SYMBOL_NOT_FOUND; case KLDR_ERR_FORWARDER_SYMBOL: return VERR_BAD_EXE_FORMAT; case KLDR_ERR_BAD_FIXUP: AssertMsgFailedReturn(("KLDR_ERR_BAD_FIXUP\n"), VERR_BAD_EXE_FORMAT); case KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS: return VERR_BAD_EXE_FORMAT; case KLDR_ERR_NO_DEBUG_INFO: return VERR_FILE_NOT_FOUND; case KLDR_ERR_ALREADY_MAPPED: return VERR_WRONG_ORDER; case KLDR_ERR_NOT_MAPPED: return VERR_WRONG_ORDER; case KLDR_ERR_ADDRESS_OVERFLOW: return VERR_NUMBER_TOO_BIG; case KLDR_ERR_TODO: return VERR_NOT_IMPLEMENTED; case KLDR_ERR_NOT_LOADED_DYNAMICALLY: case KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE: case KLDR_ERR_TOO_LONG_FORWARDER_CHAIN: case KLDR_ERR_MODULE_TERMINATING: case KLDR_ERR_PREREQUISITE_MODULE_TERMINATING: case KLDR_ERR_MODULE_INIT_FAILED: case KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED: case KLDR_ERR_MODULE_INIT_FAILED_ALREADY: case KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY: case KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY: case KLDR_ERR_THREAD_ATTACH_FAILED: case KRDR_ERR_TOO_MANY_MAPPINGS: case KLDR_ERR_NOT_DLL: case KLDR_ERR_NOT_EXE: AssertMsgFailedReturn(("krc=%d (%#x): %s\n", krc, krc, kErrName(krc)), VERR_LDR_GENERAL_FAILURE); case KLDR_ERR_PE_UNSUPPORTED_MACHINE: case KLDR_ERR_PE_BAD_FILE_HEADER: case KLDR_ERR_PE_BAD_OPTIONAL_HEADER: case KLDR_ERR_PE_BAD_SECTION_HEADER: case KLDR_ERR_PE_BAD_FORWARDER: case KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND: case KLDR_ERR_PE_BAD_FIXUP: case KLDR_ERR_PE_BAD_IMPORT: AssertMsgFailedReturn(("krc=%d (%#x): %s\n", krc, krc, kErrName(krc)), VERR_LDR_GENERAL_FAILURE); case KLDR_ERR_LX_BAD_HEADER: case KLDR_ERR_LX_BAD_LOADER_SECTION: case KLDR_ERR_LX_BAD_FIXUP_SECTION: case KLDR_ERR_LX_BAD_OBJECT_TABLE: case KLDR_ERR_LX_BAD_PAGE_MAP: case KLDR_ERR_LX_BAD_ITERDATA: case KLDR_ERR_LX_BAD_ITERDATA2: case KLDR_ERR_LX_BAD_BUNDLE: case KLDR_ERR_LX_NO_SONAME: case KLDR_ERR_LX_BAD_SONAME: case KLDR_ERR_LX_BAD_FORWARDER: case KLDR_ERR_LX_NRICHAIN_NOT_SUPPORTED: AssertMsgFailedReturn(("krc=%d (%#x): %s\n", krc, krc, kErrName(krc)), VERR_LDR_GENERAL_FAILURE); case KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE: return VERR_LDR_GENERAL_FAILURE; case KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED: case KLDR_ERR_MACHO_BAD_HEADER: case KLDR_ERR_MACHO_UNSUPPORTED_MACHINE: case KLDR_ERR_MACHO_BAD_LOAD_COMMAND: case KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND: case KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND: case KLDR_ERR_MACHO_BAD_SECTION: case KLDR_ERR_MACHO_UNSUPPORTED_SECTION: #ifdef KLDR_ERR_MACHO_UNSUPPORTED_INIT_SECTION case KLDR_ERR_MACHO_UNSUPPORTED_INIT_SECTION: case KLDR_ERR_MACHO_UNSUPPORTED_TERM_SECTION: #endif case KLDR_ERR_MACHO_UNKNOWN_SECTION: case KLDR_ERR_MACHO_BAD_SECTION_ORDER: case KLDR_ERR_MACHO_BIT_MIX: case KLDR_ERR_MACHO_BAD_OBJECT_FILE: case KLDR_ERR_MACHO_BAD_SYMBOL: case KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE: AssertMsgFailedReturn(("krc=%d (%#x): %s\n", krc, krc, kErrName(krc)), VERR_LDR_GENERAL_FAILURE); default: if (RT_FAILURE(krc)) return krc; AssertMsgFailedReturn(("krc=%d (%#x): %s\n", krc, krc, kErrName(krc)), VERR_NO_TRANSLATION); } } /** * Converts a IPRT error code to an kLdr one. */ static int rtkldrConvertErrorFromIPRT(int rc) { if (RT_SUCCESS(rc)) return 0; switch (rc) { case VERR_NO_MEMORY: return KERR_NO_MEMORY; case VERR_INVALID_PARAMETER: return KERR_INVALID_PARAMETER; case VERR_INVALID_HANDLE: return KERR_INVALID_HANDLE; case VERR_BUFFER_OVERFLOW: return KERR_BUFFER_OVERFLOW; default: return rc; } } /** @copydoc KLDRRDROPS::pfnCreate * @remark This is a dummy which isn't used. */ static int rtkldrRdr_Create( PPKRDR ppRdr, const char *pszFilename) { NOREF(ppRdr); NOREF(pszFilename); AssertReleaseFailed(); return -1; } /** @copydoc KLDRRDROPS::pfnDestroy */ static int rtkldrRdr_Destroy( PKRDR pRdr) { PRTKLDRRDR pThis = (PRTKLDRRDR)pRdr; pThis->pReader = NULL; RTMemFree(pThis); return 0; } /** @copydoc KLDRRDROPS::pfnRead */ static int rtkldrRdr_Read( PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off) { PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader; int rc = pReader->pfnRead(pReader, pvBuf, cb, off); return rtkldrConvertErrorFromIPRT(rc); } /** @copydoc KLDRRDROPS::pfnAllMap */ static int rtkldrRdr_AllMap( PKRDR pRdr, const void **ppvBits) { PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader; int rc = pReader->pfnMap(pReader, ppvBits); return rtkldrConvertErrorFromIPRT(rc); } /** @copydoc KLDRRDROPS::pfnAllUnmap */ static int rtkldrRdr_AllUnmap(PKRDR pRdr, const void *pvBits) { PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader; int rc = pReader->pfnUnmap(pReader, pvBits); return rtkldrConvertErrorFromIPRT(rc); } /** @copydoc KLDRRDROPS::pfnSize */ static KFOFF rtkldrRdr_Size( PKRDR pRdr) { PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader; return (KFOFF)pReader->pfnSize(pReader); } /** @copydoc KLDRRDROPS::pfnTell */ static KFOFF rtkldrRdr_Tell( PKRDR pRdr) { PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader; return (KFOFF)pReader->pfnTell(pReader); } /** @copydoc KLDRRDROPS::pfnName */ static const char * rtkldrRdr_Name(PKRDR pRdr) { PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader; return pReader->pfnLogName(pReader); } /** @copydoc KLDRRDROPS::pfnNativeFH */ static KIPTR rtkldrRdr_NativeFH(PKRDR pRdr) { NOREF(pRdr); AssertFailed(); return -1; } /** @copydoc KLDRRDROPS::pfnPageSize */ static KSIZE rtkldrRdr_PageSize(PKRDR pRdr) { NOREF(pRdr); return PAGE_SIZE; } /** @copydoc KLDRRDROPS::pfnMap */ static int rtkldrRdr_Map( PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed) { //PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader; NOREF(pRdr); NOREF(ppvBase); NOREF(cSegments); NOREF(paSegments); NOREF(fFixed); AssertFailed(); return -1; } /** @copydoc KLDRRDROPS::pfnRefresh */ static int rtkldrRdr_Refresh( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { //PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader; NOREF(pRdr); NOREF(pvBase); NOREF(cSegments); NOREF(paSegments); AssertFailed(); return -1; } /** @copydoc KLDRRDROPS::pfnProtect */ static int rtkldrRdr_Protect( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect) { //PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader; NOREF(pRdr); NOREF(pvBase); NOREF(cSegments); NOREF(paSegments); NOREF(fUnprotectOrProtect); AssertFailed(); return -1; } /** @copydoc KLDRRDROPS::pfnUnmap */ static int rtkldrRdr_Unmap( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { //PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader; NOREF(pRdr); NOREF(pvBase); NOREF(cSegments); NOREF(paSegments); AssertFailed(); return -1; } /** @copydoc KLDRRDROPS::pfnDone */ static void rtkldrRdr_Done( PKRDR pRdr) { NOREF(pRdr); //PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader; } /** * The file reader operations. * We provide our own based on IPRT instead of using the kLdr ones. */ extern "C" const KRDROPS g_kLdrRdrFileOps; extern "C" const KRDROPS g_kLdrRdrFileOps = { /* .pszName = */ "IPRT", /* .pNext = */ NULL, /* .pfnCreate = */ rtkldrRdr_Create, /* .pfnDestroy = */ rtkldrRdr_Destroy, /* .pfnRead = */ rtkldrRdr_Read, /* .pfnAllMap = */ rtkldrRdr_AllMap, /* .pfnAllUnmap = */ rtkldrRdr_AllUnmap, /* .pfnSize = */ rtkldrRdr_Size, /* .pfnTell = */ rtkldrRdr_Tell, /* .pfnName = */ rtkldrRdr_Name, /* .pfnNativeFH = */ rtkldrRdr_NativeFH, /* .pfnPageSize = */ rtkldrRdr_PageSize, /* .pfnMap = */ rtkldrRdr_Map, /* .pfnRefresh = */ rtkldrRdr_Refresh, /* .pfnProtect = */ rtkldrRdr_Protect, /* .pfnUnmap = */ rtkldrRdr_Unmap, /* .pfnDone = */ rtkldrRdr_Done, /* .u32Dummy = */ 42 }; /** @copydoc RTLDROPS::pfnClose */ static DECLCALLBACK(int) rtkldr_Close(PRTLDRMODINTERNAL pMod) { PKLDRMOD pModkLdr = ((PRTLDRMODKLDR)pMod)->pMod; int rc = kLdrModClose(pModkLdr); return rtkldrConvertError(rc); } /** @copydoc RTLDROPS::pfnDone */ static DECLCALLBACK(int) rtkldr_Done(PRTLDRMODINTERNAL pMod) { PKLDRMOD pModkLdr = ((PRTLDRMODKLDR)pMod)->pMod; int rc = kLdrModMostlyDone(pModkLdr); return rtkldrConvertError(rc); } /** @copydoc FNKLDRMODENUMSYMS */ static int rtkldrEnumSymbolsWrapper(PKLDRMOD pMod, uint32_t iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, KLDRADDR uValue, uint32_t fKind, void *pvUser) { PRTLDRMODKLDRARGS pArgs = (PRTLDRMODKLDRARGS)pvUser; NOREF(pMod); NOREF(pszVersion); NOREF(fKind); /* If not zero terminated we'll have to use a temporary buffer. */ const char *pszSymbol = pchSymbol; if (pchSymbol && pchSymbol[cchSymbol]) { char *psz = (char *)alloca(cchSymbol + 1); memcpy(psz, pchSymbol, cchSymbol); psz[cchSymbol] = '\0'; pszSymbol = psz; } #if defined(RT_OS_OS2) || defined(RT_OS_DARWIN) /* skip the underscore prefix. */ if (*pszSymbol == '_') pszSymbol++; #endif int rc = pArgs->u.pfnEnumSyms(&pArgs->pMod->Core, pszSymbol, iSymbol, uValue, pArgs->pvUser); if (RT_FAILURE(rc)) return rc; /* don't bother converting. */ return 0; } /** @copydoc RTLDROPS::pfnEnumSymbols */ static DECLCALLBACK(int) rtkldr_EnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFlags, const void *pvBits, RTUINTPTR BaseAddress, PFNRTLDRENUMSYMS pfnCallback, void *pvUser) { PKLDRMOD pModkLdr = ((PRTLDRMODKLDR)pMod)->pMod; RTLDRMODKLDRARGS Args; Args.pvUser = pvUser; Args.u.pfnEnumSyms = pfnCallback; Args.pMod = (PRTLDRMODKLDR)pMod; Args.pvBits = pvBits; Args.rc = VINF_SUCCESS; int rc = kLdrModEnumSymbols(pModkLdr, pvBits, BaseAddress, fFlags & RTLDR_ENUM_SYMBOL_FLAGS_ALL ? KLDRMOD_ENUM_SYMS_FLAGS_ALL : 0, rtkldrEnumSymbolsWrapper, &Args); if (Args.rc != VINF_SUCCESS) rc = Args.rc; else rc = rtkldrConvertError(rc); return rc; } /** @copydoc RTLDROPS::pfnGetImageSize */ static DECLCALLBACK(size_t) rtkldr_GetImageSize(PRTLDRMODINTERNAL pMod) { PKLDRMOD pModkLdr = ((PRTLDRMODKLDR)pMod)->pMod; return kLdrModSize(pModkLdr); } /** @copydoc FNKLDRMODGETIMPORT */ static int rtkldrGetImportWrapper(PKLDRMOD pMod, uint32_t iImport, uint32_t iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PKLDRADDR puValue, uint32_t *pfKind, void *pvUser) { PRTLDRMODKLDRARGS pArgs = (PRTLDRMODKLDRARGS)pvUser; NOREF(pMod); NOREF(pszVersion); NOREF(pfKind); /* If not zero terminated we'll have to use a temporary buffer. */ const char *pszSymbol = pchSymbol; if (pchSymbol && pchSymbol[cchSymbol]) { char *psz = (char *)alloca(cchSymbol + 1); memcpy(psz, pchSymbol, cchSymbol); psz[cchSymbol] = '\0'; pszSymbol = psz; } #if defined(RT_OS_OS2) || defined(RT_OS_DARWIN) /* skip the underscore prefix. */ if (*pszSymbol == '_') pszSymbol++; #endif /* get the import module name - TODO: cache this */ const char *pszModule = NULL; if (iImport != NIL_KLDRMOD_IMPORT) { char *pszBuf = (char *)alloca(64); int rc = kLdrModGetImport(pMod, pArgs->pvBits, iImport, pszBuf, 64); if (rc) return rc; pszModule = pszBuf; } /* do the query */ RTUINTPTR Value; int rc = pArgs->u.pfnGetImport(&pArgs->pMod->Core, pszModule, pszSymbol, pszSymbol ? ~0 : iSymbol, &Value, pArgs->pvUser); if (RT_SUCCESS(rc)) { *puValue = Value; return 0; } return rtkldrConvertErrorFromIPRT(rc); } /** @copydoc RTLDROPS::pfnGetBits */ static DECLCALLBACK(int) rtkldr_GetBits(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser) { PKLDRMOD pModkLdr = ((PRTLDRMODKLDR)pMod)->pMod; RTLDRMODKLDRARGS Args; Args.pvUser = pvUser; Args.u.pfnGetImport = pfnGetImport; Args.pMod = (PRTLDRMODKLDR)pMod; Args.pvBits = pvBits; Args.rc = VINF_SUCCESS; int rc = kLdrModGetBits(pModkLdr, pvBits, BaseAddress, rtkldrGetImportWrapper, &Args); if (Args.rc != VINF_SUCCESS) rc = Args.rc; else rc = rtkldrConvertError(rc); return rc; } /** @copydoc RTLDROPS::pfnRelocate */ static DECLCALLBACK(int) rtkldr_Relocate(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress, RTUINTPTR OldBaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser) { PKLDRMOD pModkLdr = ((PRTLDRMODKLDR)pMod)->pMod; RTLDRMODKLDRARGS Args; Args.pvUser = pvUser; Args.u.pfnGetImport = pfnGetImport; Args.pMod = (PRTLDRMODKLDR)pMod; Args.pvBits = pvBits; Args.rc = VINF_SUCCESS; int rc = kLdrModRelocateBits(pModkLdr, pvBits, NewBaseAddress, OldBaseAddress, rtkldrGetImportWrapper, &Args); if (Args.rc != VINF_SUCCESS) rc = Args.rc; else rc = rtkldrConvertError(rc); return rc; } /** @copydoc RTLDROPS::pfnGetSymbolEx */ static DECLCALLBACK(int) rtkldr_GetSymbolEx(PRTLDRMODINTERNAL pMod, const void *pvBits, RTUINTPTR BaseAddress, uint32_t iOrdinal, const char *pszSymbol, RTUINTPTR *pValue) { PKLDRMOD pModkLdr = ((PRTLDRMODKLDR)pMod)->pMod; KLDRADDR uValue; #if defined(RT_OS_OS2) || defined(RT_OS_DARWIN) /* * Add underscore prefix. */ if (pszSymbol) { size_t cch = strlen(pszSymbol); char *psz = (char *)alloca(cch + 2); memcpy(psz + 1, pszSymbol, cch + 1); *psz = '_'; pszSymbol = psz; } #endif int rc = kLdrModQuerySymbol(pModkLdr, pvBits, BaseAddress, iOrdinal == UINT32_MAX ? NIL_KLDRMOD_SYM_ORDINAL : iOrdinal, pszSymbol, strlen(pszSymbol), NULL, NULL, NULL, &uValue, NULL); if (!rc) { *pValue = uValue; return VINF_SUCCESS; } return rtkldrConvertError(rc); } /** @copydoc FNKLDRENUMDBG */ static int rtkldrEnumDbgInfoWrapper(PKLDRMOD pMod, KU32 iDbgInfo, KLDRDBGINFOTYPE enmType, KI16 iMajorVer, KI16 iMinorVer, const char *pszPartNm, KLDRFOFF offFile, KLDRADDR LinkAddress, KLDRSIZE cb, const char *pszExtFile, void *pvUser) { PRTLDRMODKLDRARGS pArgs = (PRTLDRMODKLDRARGS)pvUser; NOREF(pMod); RTLDRDBGINFO DbgInfo; RT_ZERO(DbgInfo.u); DbgInfo.iDbgInfo = iDbgInfo; DbgInfo.offFile = offFile; DbgInfo.LinkAddress = LinkAddress; DbgInfo.cb = cb; DbgInfo.pszExtFile = pszExtFile; switch (enmType) { case KLDRDBGINFOTYPE_UNKNOWN: DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN; break; case KLDRDBGINFOTYPE_STABS: DbgInfo.enmType = RTLDRDBGINFOTYPE_STABS; break; case KLDRDBGINFOTYPE_DWARF: DbgInfo.enmType = RTLDRDBGINFOTYPE_DWARF; if (!pszExtFile) DbgInfo.u.Dwarf.pszSection = pszPartNm; else { DbgInfo.enmType = RTLDRDBGINFOTYPE_DWARF_DWO; DbgInfo.u.Dwo.uCrc32 = 0; } break; case KLDRDBGINFOTYPE_CODEVIEW: DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW; /* Should make some more effort here... Assume the IPRT loader will kick in before we get here! */ break; case KLDRDBGINFOTYPE_WATCOM: DbgInfo.enmType = RTLDRDBGINFOTYPE_WATCOM; break; case KLDRDBGINFOTYPE_HLL: DbgInfo.enmType = RTLDRDBGINFOTYPE_HLL; break; default: AssertFailed(); DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN; break; } int rc = pArgs->u.pfnEnumDbgInfo(&pArgs->pMod->Core, &DbgInfo, pArgs->pvUser); if (RT_FAILURE(rc)) return rc; /* don't bother converting. */ return 0; } /** @copydoc RTLDROPS::pfnEnumDbgInfo */ static DECLCALLBACK(int) rtkldr_EnumDbgInfo(PRTLDRMODINTERNAL pMod, const void *pvBits, PFNRTLDRENUMDBG pfnCallback, void *pvUser) { PRTLDRMODKLDR pThis = (PRTLDRMODKLDR)pMod; RTLDRMODKLDRARGS Args; Args.pvUser = pvUser; Args.u.pfnEnumDbgInfo = pfnCallback; Args.pvBits = pvBits; Args.pMod = pThis; Args.rc = VINF_SUCCESS; int rc = kLdrModEnumDbgInfo(pThis->pMod, pvBits, rtkldrEnumDbgInfoWrapper, &Args); if (Args.rc != VINF_SUCCESS) rc = Args.rc; return rc; } /** @copydoc RTLDROPS::pfnEnumSegments. */ static DECLCALLBACK(int) rtkldr_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser) { PRTLDRMODKLDR pThis = (PRTLDRMODKLDR)pMod; uint32_t const cSegments = pThis->pMod->cSegments; PCKLDRSEG paSegments = &pThis->pMod->aSegments[0]; char szName[128]; for (uint32_t iSeg = 0; iSeg < cSegments; iSeg++) { RTLDRSEG Seg; if (!paSegments[iSeg].cchName) { Seg.pszName = szName; Seg.cchName = (uint32_t)RTStrPrintf(szName, sizeof(szName), "Seg%02u", iSeg); } else if (paSegments[iSeg].pchName[paSegments[iSeg].cchName]) { AssertReturn(paSegments[iSeg].cchName < sizeof(szName), VERR_INTERNAL_ERROR_3); RTStrCopyEx(szName, sizeof(szName), paSegments[iSeg].pchName, paSegments[iSeg].cchName); Seg.pszName = szName; Seg.cchName = paSegments[iSeg].cchName; } else { Seg.pszName = paSegments[iSeg].pchName; Seg.cchName = paSegments[iSeg].cchName; } Seg.SelFlat = paSegments[iSeg].SelFlat; Seg.Sel16bit = paSegments[iSeg].Sel16bit; Seg.fFlags = paSegments[iSeg].fFlags; AssertCompile(KLDRSEG_FLAG_16BIT == RTLDRSEG_FLAG_16BIT ); AssertCompile(KLDRSEG_FLAG_OS2_ALIAS16 == RTLDRSEG_FLAG_OS2_ALIAS16); AssertCompile(KLDRSEG_FLAG_OS2_CONFORM == RTLDRSEG_FLAG_OS2_CONFORM); AssertCompile(KLDRSEG_FLAG_OS2_IOPL == RTLDRSEG_FLAG_OS2_IOPL ); switch (paSegments[iSeg].enmProt) { default: AssertMsgFailed(("%d\n", paSegments[iSeg].enmProt)); case KPROT_NOACCESS: Seg.fProt = 0; break; case KPROT_READONLY: Seg.fProt = RTMEM_PROT_READ; break; case KPROT_READWRITE: Seg.fProt = RTMEM_PROT_READ | RTMEM_PROT_WRITE; break; case KPROT_WRITECOPY: Seg.fProt = RTMEM_PROT_WRITE; break; case KPROT_EXECUTE: Seg.fProt = RTMEM_PROT_EXEC; break; case KPROT_EXECUTE_READ: Seg.fProt = RTMEM_PROT_EXEC | RTMEM_PROT_READ; break; case KPROT_EXECUTE_READWRITE: Seg.fProt = RTMEM_PROT_EXEC | RTMEM_PROT_READ | RTMEM_PROT_WRITE; break; case KPROT_EXECUTE_WRITECOPY: Seg.fProt = RTMEM_PROT_EXEC | RTMEM_PROT_WRITE; break; } Seg.cb = paSegments[iSeg].cb; Seg.Alignment = paSegments[iSeg].Alignment; Seg.LinkAddress = paSegments[iSeg].LinkAddress; Seg.offFile = paSegments[iSeg].offFile; Seg.cbFile = paSegments[iSeg].cbFile; Seg.RVA = paSegments[iSeg].RVA; Seg.cbMapped = paSegments[iSeg].cbMapped; int rc = pfnCallback(pMod, &Seg, pvUser); if (rc != VINF_SUCCESS) return rc; } return VINF_SUCCESS; } /** @copydoc RTLDROPS::pfnLinkAddressToSegOffset. */ static DECLCALLBACK(int) rtkldr_LinkAddressToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress, uint32_t *piSeg, PRTLDRADDR poffSeg) { PRTLDRMODKLDR pThis = (PRTLDRMODKLDR)pMod; uint32_t const cSegments = pThis->pMod->cSegments; PCKLDRSEG paSegments = &pThis->pMod->aSegments[0]; for (uint32_t iSeg = 0; iSeg < cSegments; iSeg++) { KLDRADDR offSeg = LinkAddress - paSegments[iSeg].LinkAddress; if ( offSeg < paSegments[iSeg].cbMapped || offSeg < paSegments[iSeg].cb) { *piSeg = iSeg; *poffSeg = offSeg; return VINF_SUCCESS; } } return VERR_LDR_INVALID_LINK_ADDRESS; } /** @copydoc RTLDROPS::pfnLinkAddressToRva. */ static DECLCALLBACK(int) rtkldr_LinkAddressToRva(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva) { PRTLDRMODKLDR pThis = (PRTLDRMODKLDR)pMod; uint32_t const cSegments = pThis->pMod->cSegments; PCKLDRSEG paSegments = &pThis->pMod->aSegments[0]; for (uint32_t iSeg = 0; iSeg < cSegments; iSeg++) { KLDRADDR offSeg = LinkAddress - paSegments[iSeg].LinkAddress; if ( offSeg < paSegments[iSeg].cbMapped || offSeg < paSegments[iSeg].cb) { *pRva = paSegments[iSeg].RVA + offSeg; return VINF_SUCCESS; } } return VERR_LDR_INVALID_RVA; } /** @copydoc RTLDROPS::pfnSegOffsetToRva. */ static DECLCALLBACK(int) rtkldr_SegOffsetToRva(PRTLDRMODINTERNAL pMod, uint32_t iSeg, RTLDRADDR offSeg, PRTLDRADDR pRva) { PRTLDRMODKLDR pThis = (PRTLDRMODKLDR)pMod; if (iSeg >= pThis->pMod->cSegments) return VERR_LDR_INVALID_SEG_OFFSET; PCKLDRSEG const pSegment = &pThis->pMod->aSegments[iSeg]; if ( offSeg > pSegment->cbMapped && offSeg > pSegment->cb && ( pSegment->cbFile < 0 || offSeg > (uint64_t)pSegment->cbFile)) return VERR_LDR_INVALID_SEG_OFFSET; *pRva = pSegment->RVA + offSeg; return VINF_SUCCESS; } /** @copydoc RTLDROPS::pfnRvaToSegOffset. */ static DECLCALLBACK(int) rtkldr_RvaToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR Rva, uint32_t *piSeg, PRTLDRADDR poffSeg) { PRTLDRMODKLDR pThis = (PRTLDRMODKLDR)pMod; uint32_t const cSegments = pThis->pMod->cSegments; PCKLDRSEG paSegments = &pThis->pMod->aSegments[0]; for (uint32_t iSeg = 0; iSeg < cSegments; iSeg++) { KLDRADDR offSeg = Rva - paSegments[iSeg].RVA; if ( offSeg < paSegments[iSeg].cbMapped || offSeg < paSegments[iSeg].cb) { *piSeg = iSeg; *poffSeg = offSeg; return VINF_SUCCESS; } } return VERR_LDR_INVALID_RVA; } /** @copydoc RTLDROPS::pfnReadDbgInfo. */ static DECLCALLBACK(int) rtkldr_ReadDbgInfo(PRTLDRMODINTERNAL pMod, uint32_t iDbgInfo, RTFOFF off, size_t cb, void *pvBuf) { PRTLDRMODKLDR pThis = (PRTLDRMODKLDR)pMod; /** @todo May have to apply fixups here. */ return pThis->Core.pReader->pfnRead(pThis->Core.pReader, pvBuf, cb, off); } /** @interface_method_impl{RTLDROPS,pfnQueryProp} */ static DECLCALLBACK(int) rtkldr_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void const *pvBits, void *pvBuf, size_t cbBuf, size_t *pcbRet) { PRTLDRMODKLDR pThis = (PRTLDRMODKLDR)pMod; int rc; switch (enmProp) { case RTLDRPROP_UUID: rc = kLdrModQueryImageUuid(pThis->pMod, /*pvBits*/ NULL, (uint8_t *)pvBuf, cbBuf); if (rc == KLDR_ERR_NO_IMAGE_UUID) return VERR_NOT_FOUND; AssertReturn(rc == 0, VERR_INVALID_PARAMETER); break; default: return VERR_NOT_FOUND; } return VINF_SUCCESS; } /** * Operations for a kLdr module. */ static const RTLDROPS g_rtkldrOps = { "kLdr", rtkldr_Close, NULL, rtkldr_Done, rtkldr_EnumSymbols, /* ext */ rtkldr_GetImageSize, rtkldr_GetBits, rtkldr_Relocate, rtkldr_GetSymbolEx, NULL /*pfnQueryForwarderInfo*/, rtkldr_EnumDbgInfo, rtkldr_EnumSegments, rtkldr_LinkAddressToSegOffset, rtkldr_LinkAddressToRva, rtkldr_SegOffsetToRva, rtkldr_RvaToSegOffset, rtkldr_ReadDbgInfo, rtkldr_QueryProp, NULL, NULL, 42 }; /** * Open a image using kLdr. * * @returns iprt status code. * @param pReader The loader reader instance which will provide the raw image bits. * @param fFlags Reserved, MBZ. * @param enmArch CPU architecture specifier for the image to be loaded. * @param phLdrMod Where to store the handle. * @param pErrInfo Where to return extended error information. Optional. */ int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo) { /* Convert enmArch to k-speak. */ KCPUARCH enmCpuArch; switch (enmArch) { case RTLDRARCH_WHATEVER: enmCpuArch = KCPUARCH_UNKNOWN; break; case RTLDRARCH_X86_32: enmCpuArch = KCPUARCH_X86_32; break; case RTLDRARCH_AMD64: enmCpuArch = KCPUARCH_AMD64; break; default: return VERR_INVALID_PARAMETER; } KU32 fKFlags = 0; if (fFlags & RTLDR_O_FOR_DEBUG) fKFlags |= KLDRMOD_OPEN_FLAGS_FOR_INFO; /* Create a rtkldrRdr_ instance. */ PRTKLDRRDR pRdr = (PRTKLDRRDR)RTMemAllocZ(sizeof(*pRdr)); if (!pRdr) return VERR_NO_MEMORY; pRdr->Core.u32Magic = KRDR_MAGIC; pRdr->Core.pOps = &g_kLdrRdrFileOps; pRdr->pReader = pReader; /* Try open it. */ PKLDRMOD pMod; int krc = kLdrModOpenFromRdr(&pRdr->Core, fKFlags, enmCpuArch, &pMod); if (!krc) { /* Create a module wrapper for it. */ PRTLDRMODKLDR pNewMod = (PRTLDRMODKLDR)RTMemAllocZ(sizeof(*pNewMod)); if (pNewMod) { pNewMod->Core.u32Magic = RTLDRMOD_MAGIC; pNewMod->Core.eState = LDR_STATE_OPENED; pNewMod->Core.pOps = &g_rtkldrOps; pNewMod->Core.pReader = pReader; switch (pMod->enmFmt) { case KLDRFMT_NATIVE: pNewMod->Core.enmFormat = RTLDRFMT_NATIVE; break; case KLDRFMT_AOUT: pNewMod->Core.enmFormat = RTLDRFMT_AOUT; break; case KLDRFMT_ELF: pNewMod->Core.enmFormat = RTLDRFMT_ELF; break; case KLDRFMT_LX: pNewMod->Core.enmFormat = RTLDRFMT_LX; break; case KLDRFMT_MACHO: pNewMod->Core.enmFormat = RTLDRFMT_MACHO; break; case KLDRFMT_PE: pNewMod->Core.enmFormat = RTLDRFMT_PE; break; default: AssertMsgFailed(("%d\n", pMod->enmFmt)); pNewMod->Core.enmFormat = RTLDRFMT_NATIVE; break; } switch (pMod->enmType) { case KLDRTYPE_OBJECT: pNewMod->Core.enmType = RTLDRTYPE_OBJECT; break; case KLDRTYPE_EXECUTABLE_FIXED: pNewMod->Core.enmType = RTLDRTYPE_EXECUTABLE_FIXED; break; case KLDRTYPE_EXECUTABLE_RELOCATABLE: pNewMod->Core.enmType = RTLDRTYPE_EXECUTABLE_RELOCATABLE; break; case KLDRTYPE_EXECUTABLE_PIC: pNewMod->Core.enmType = RTLDRTYPE_EXECUTABLE_PIC; break; case KLDRTYPE_SHARED_LIBRARY_FIXED: pNewMod->Core.enmType = RTLDRTYPE_SHARED_LIBRARY_FIXED; break; case KLDRTYPE_SHARED_LIBRARY_RELOCATABLE: pNewMod->Core.enmType = RTLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break; case KLDRTYPE_SHARED_LIBRARY_PIC: pNewMod->Core.enmType = RTLDRTYPE_SHARED_LIBRARY_PIC; break; case KLDRTYPE_FORWARDER_DLL: pNewMod->Core.enmType = RTLDRTYPE_FORWARDER_DLL; break; case KLDRTYPE_CORE: pNewMod->Core.enmType = RTLDRTYPE_CORE; break; case KLDRTYPE_DEBUG_INFO: pNewMod->Core.enmType = RTLDRTYPE_DEBUG_INFO; break; default: AssertMsgFailed(("%d\n", pMod->enmType)); pNewMod->Core.enmType = RTLDRTYPE_OBJECT; break; } switch (pMod->enmEndian) { case KLDRENDIAN_LITTLE: pNewMod->Core.enmEndian = RTLDRENDIAN_LITTLE; break; case KLDRENDIAN_BIG: pNewMod->Core.enmEndian = RTLDRENDIAN_BIG; break; case KLDRENDIAN_NA: pNewMod->Core.enmEndian = RTLDRENDIAN_NA; break; default: AssertMsgFailed(("%d\n", pMod->enmEndian)); pNewMod->Core.enmEndian = RTLDRENDIAN_NA; break; } switch (pMod->enmArch) { case KCPUARCH_X86_32: pNewMod->Core.enmArch = RTLDRARCH_X86_32; break; case KCPUARCH_AMD64: pNewMod->Core.enmArch = RTLDRARCH_AMD64; break; default: AssertMsgFailed(("%d\n", pMod->enmArch)); pNewMod->Core.enmArch = RTLDRARCH_WHATEVER; break; } pNewMod->pMod = pMod; *phLdrMod = &pNewMod->Core; #ifdef LOG_ENABLED Log(("rtldrkLdrOpen: '%s' (%s) %u segments\n", pMod->pszName, pMod->pszFilename, pMod->cSegments)); for (unsigned iSeg = 0; iSeg < pMod->cSegments; iSeg++) { Log(("Segment #%-2u: RVA=%08llx cb=%08llx '%.*s'\n", iSeg, pMod->aSegments[iSeg].RVA, pMod->aSegments[iSeg].cb, pMod->aSegments[iSeg].cchName, pMod->aSegments[iSeg].pchName)); } #endif return VINF_SUCCESS; } /* bail out */ kLdrModClose(pMod); krc = KERR_NO_MEMORY; } else RTMemFree(pRdr); return rtkldrConvertError(krc); }