ldrkStuff.cpp revision c58f1213e628a545081c70e26c6b67a841cff880
/* $Id$ */
/** @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;
* 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
#define KLDR_ALREADY_INCLUDE_STD_TYPES
#define KLDR_NO_KLDR_H_INCLUDES
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* kLdr file provider.
*/
typedef struct RTKLDRRDR
{
/** The core. */
/** The IPRT bit reader. */
} RTKLDRRDR, *PRTKLDRRDR;
/**
* IPRT module.
*/
typedef struct RTLDRMODKLDR
{
/** The Core module structure. */
/** The kLdr module. */
/**
* Arguments for a RTLDRMODKLDR callback wrapper.
*/
typedef struct RTLDRMODKLDRARGS
{
union
{
} u;
void *pvUser;
const void *pvBits;
int rc;
/**
* 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_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_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_DLL:
case KLDR_ERR_NOT_EXE:
case KLDR_ERR_PE_BAD_FIXUP:
case KLDR_ERR_PE_BAD_IMPORT:
case KLDR_ERR_LX_BAD_HEADER:
case KLDR_ERR_LX_BAD_PAGE_MAP:
case KLDR_ERR_LX_BAD_ITERDATA:
case KLDR_ERR_LX_BAD_BUNDLE:
case KLDR_ERR_LX_NO_SONAME:
case KLDR_ERR_LX_BAD_SONAME:
#endif
case KLDR_ERR_MACHO_BIT_MIX:
default:
if (RT_FAILURE(krc))
return krc;
}
}
/**
* 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. */
{
return -1;
}
/** @copydoc KLDRRDROPS::pfnDestroy */
{
return rtkldrConvertErrorFromIPRT(rc);
}
/** @copydoc KLDRRDROPS::pfnRead */
{
return rtkldrConvertErrorFromIPRT(rc);
}
/** @copydoc KLDRRDROPS::pfnAllMap */
{
return rtkldrConvertErrorFromIPRT(rc);
}
/** @copydoc KLDRRDROPS::pfnAllUnmap */
{
return rtkldrConvertErrorFromIPRT(rc);
}
/** @copydoc KLDRRDROPS::pfnSize */
{
}
/** @copydoc KLDRRDROPS::pfnTell */
{
}
/** @copydoc KLDRRDROPS::pfnName */
{
}
/** @copydoc KLDRRDROPS::pfnNativeFH */
{
AssertFailed();
return -1;
}
/** @copydoc KLDRRDROPS::pfnPageSize */
{
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;
AssertFailed();
return -1;
}
/** @copydoc KLDRRDROPS::pfnRefresh */
{
//PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader;
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;
AssertFailed();
return -1;
}
/** @copydoc KLDRRDROPS::pfnUnmap */
{
//PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader;
AssertFailed();
return -1;
}
/** @copydoc KLDRRDROPS::pfnDone */
{
//PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader;
}
/**
* The file reader operations.
* We provide our own based on IPRT instead of using the kLdr ones.
*/
{
/* .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 */
{
return rtkldrConvertError(rc);
}
/** @copydoc RTLDROPS::pfnDone */
{
return rtkldrConvertError(rc);
}
/** @copydoc FNKLDRMODENUMSYMS */
{
/* If not zero terminated we'll have to use a temporary buffer. */
{
}
#if defined(RT_OS_OS2) || defined(RT_OS_DARWIN)
/* skip the underscore prefix. */
if (*pszSymbol == '_')
pszSymbol++;
#endif
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,
{
else
return rc;
}
/** @copydoc RTLDROPS::pfnGetImageSize */
{
return kLdrModSize(pModkLdr);
}
/** @copydoc FNKLDRMODGETIMPORT */
static int rtkldrGetImportWrapper(PKLDRMOD pMod, uint32_t iImport, uint32_t iSymbol, const char *pchSymbol, KSIZE cchSymbol,
{
/* If not zero terminated we'll have to use a temporary buffer. */
{
}
#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 */
if (iImport != NIL_KLDRMOD_IMPORT)
{
if (rc)
return rc;
}
/* do the query */
int rc = pArgs->u.pfnGetImport(&pArgs->pMod->Core, pszModule, pszSymbol, pszSymbol ? ~0 : iSymbol, &Value, pArgs->pvUser);
if (RT_SUCCESS(rc))
{
return 0;
}
return rtkldrConvertErrorFromIPRT(rc);
}
/** @copydoc RTLDROPS::pfnGetBits */
static DECLCALLBACK(int) rtkldr_GetBits(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR BaseAddress,
{
else
return rc;
}
/** @copydoc RTLDROPS::pfnRelocate */
static DECLCALLBACK(int) rtkldr_Relocate(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress,
{
int rc = kLdrModRelocateBits(pModkLdr, pvBits, NewBaseAddress, OldBaseAddress, rtkldrGetImportWrapper, &Args);
else
return rc;
}
/** @copydoc RTLDROPS::pfnGetSymbolEx */
static DECLCALLBACK(int) rtkldr_GetSymbolEx(PRTLDRMODINTERNAL pMod, const void *pvBits, RTUINTPTR BaseAddress,
{
#if defined(RT_OS_OS2) || defined(RT_OS_DARWIN)
/*
* Add underscore prefix.
*/
if (pszSymbol)
{
*psz = '_';
}
#endif
if (!rc)
{
return VINF_SUCCESS;
}
return rtkldrConvertError(rc);
}
/** @copydoc FNKLDRENUMDBG */
static int rtkldrEnumDbgInfoWrapper(PKLDRMOD pMod, KU32 iDbgInfo, KLDRDBGINFOTYPE enmType, KI16 iMajorVer, KI16 iMinorVer,
const char *pszExtFile, void *pvUser)
{
switch (enmType)
{
default:
AssertFailed();
break;
}
int rc = pArgs->u.pfnEnumDbgInfo(&pArgs->pMod->Core, iDbgInfo, enmMyType, iMajorVer, iMinorVer, pszPartNm,
if (RT_FAILURE(rc))
return rc; /* don't bother converting. */
return 0;
}
/** @copydoc RTLDROPS::pfnEnumDbgInfo */
{
return rc;
}
/** @copydoc RTLDROPS::pfnEnumSegments. */
static DECLCALLBACK(int) rtkldr_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser)
{
{
{
default:
case KPROT_NOACCESS:
break;
case KPROT_EXECUTE_READWRITE: Seg.fProt = RTMEM_PROT_EXEC | RTMEM_PROT_READ | RTMEM_PROT_WRITE; break;
}
if (rc != VINF_SUCCESS)
return rc;
}
return VINF_SUCCESS;
}
/** @copydoc RTLDROPS::pfnLinkAddressToSegOffset. */
static DECLCALLBACK(int) rtkldr_LinkAddressToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress,
{
{
{
return VINF_SUCCESS;
}
}
return VERR_LDR_INVALID_LINK_ADDRESS;
}
/** @copydoc RTLDROPS::pfnLinkAddressToRva. */
static DECLCALLBACK(int) rtkldr_LinkAddressToRva(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva)
{
{
{
return VINF_SUCCESS;
}
}
return VERR_LDR_INVALID_RVA;
}
/** @copydoc RTLDROPS::pfnSegOffsetToRva. */
static DECLCALLBACK(int) rtkldr_SegOffsetToRva(PRTLDRMODINTERNAL pMod, uint32_t iSeg, RTLDRADDR offSeg,
{
return VERR_LDR_INVALID_SEG_OFFSET;
return VERR_LDR_INVALID_SEG_OFFSET;
return VINF_SUCCESS;
}
/** @copydoc RTLDROPS::pfnRvaToSegOffset. */
{
{
{
return VINF_SUCCESS;
}
}
return VERR_LDR_INVALID_RVA;
}
/**
* Operations for a kLdr module.
*/
static const RTLDROPS g_rtkldrOps =
{
"kLdr",
NULL,
/* ext */
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.
*/
{
/* Convert enmArch to k-speak. */
switch (enmArch)
{
case RTLDRARCH_WHATEVER:
break;
case RTLDRARCH_X86_32:
break;
case RTLDRARCH_AMD64:
break;
default:
return VERR_INVALID_PARAMETER;
}
/* Create a rtkldrRdr_ instance. */
if (!pRdr)
return VERR_NO_MEMORY;
/* Try open it. */
if (!krc)
{
/* Create a module wrapper for it. */
if (pNewMod)
{
#ifdef LOG_ENABLED
Log(("rtldrkLdrOpen: '%s' (%s) %u segments\n",
{
}
#endif
return VINF_SUCCESS;
}
}
return rtkldrConvertError(krc);
}