summaryrefslogtreecommitdiff
path: root/src/VBox/Runtime/common/ldr
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-03-26 19:21:20 +0000
committer <>2014-05-08 15:03:54 +0000
commitfb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch)
treec2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Runtime/common/ldr
parent58ed4748338f9466599adfc8a9171280ed99e23f (diff)
downloadVirtualBox-master.tar.gz
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Runtime/common/ldr')
-rw-r--r--src/VBox/Runtime/common/ldr/ldr.cpp81
-rw-r--r--src/VBox/Runtime/common/ldr/ldrELF.cpp6
-rw-r--r--src/VBox/Runtime/common/ldr/ldrELFRelocatable.cpp.h837
-rw-r--r--src/VBox/Runtime/common/ldr/ldrEx.cpp42
-rw-r--r--src/VBox/Runtime/common/ldr/ldrFile.cpp5
-rw-r--r--src/VBox/Runtime/common/ldr/ldrMemory.cpp324
-rw-r--r--src/VBox/Runtime/common/ldr/ldrNative.cpp88
-rw-r--r--src/VBox/Runtime/common/ldr/ldrPE.cpp806
-rw-r--r--src/VBox/Runtime/common/ldr/ldrkStuff.cpp151
9 files changed, 2140 insertions, 200 deletions
diff --git a/src/VBox/Runtime/common/ldr/ldr.cpp b/src/VBox/Runtime/common/ldr/ldr.cpp
index fda1e437..218b4105 100644
--- a/src/VBox/Runtime/common/ldr/ldr.cpp
+++ b/src/VBox/Runtime/common/ldr/ldr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * 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;
@@ -40,14 +40,6 @@
#include "internal/ldr.h"
-/**
- * Checks if a library is loadable or not.
- *
- * This may attempt load and unload the library.
- *
- * @returns true/false accordingly.
- * @param pszFilename Image filename.
- */
RTDECL(bool) RTLdrIsLoadable(const char *pszFilename)
{
/*
@@ -65,15 +57,6 @@ RTDECL(bool) RTLdrIsLoadable(const char *pszFilename)
RT_EXPORT_SYMBOL(RTLdrIsLoadable);
-/**
- * Gets the address of a named exported symbol.
- *
- * @returns iprt status code.
- * @param hLdrMod The loader module handle.
- * @param pszSymbol Symbol name.
- * @param ppvValue Where to store the symbol value. Note that this is restricted to the
- * pointer size used on the host!
- */
RTDECL(int) RTLdrGetSymbol(RTLDRMOD hLdrMod, const char *pszSymbol, void **ppvValue)
{
LogFlow(("RTLdrGetSymbol: hLdrMod=%RTldrm pszSymbol=%p:{%s} ppvValue=%p\n",
@@ -110,15 +93,53 @@ RTDECL(int) RTLdrGetSymbol(RTLDRMOD hLdrMod, const char *pszSymbol, void **ppvVa
RT_EXPORT_SYMBOL(RTLdrGetSymbol);
-/**
- * Closes a loader module handle.
- *
- * The handle can be obtained using any of the RTLdrLoad(), RTLdrOpen()
- * and RTLdrOpenBits() functions.
- *
- * @returns iprt status code.
- * @param hLdrMod The loader module handle.
- */
+RTDECL(PFNRT) RTLdrGetFunction(RTLDRMOD hLdrMod, const char *pszSymbol)
+{
+ PFNRT pfn;
+ int rc = RTLdrGetSymbol(hLdrMod, pszSymbol, (void **)&pfn);
+ if (RT_SUCCESS(rc))
+ return pfn;
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTLdrGetFunction);
+
+
+RTDECL(RTLDRFMT) RTLdrGetFormat(RTLDRMOD hLdrMod)
+{
+ AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRFMT_INVALID);
+ PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
+ return pMod->enmFormat;
+}
+RT_EXPORT_SYMBOL(RTLdrGetFormat);
+
+
+RTDECL(RTLDRTYPE) RTLdrGetType(RTLDRMOD hLdrMod)
+{
+ AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRTYPE_INVALID);
+ PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
+ return pMod->enmType;
+}
+RT_EXPORT_SYMBOL(RTLdrGetType);
+
+
+RTDECL(RTLDRENDIAN) RTLdrGetEndian(RTLDRMOD hLdrMod)
+{
+ AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRENDIAN_INVALID);
+ PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
+ return pMod->enmEndian;
+}
+RT_EXPORT_SYMBOL(RTLdrGetEndian);
+
+
+RTDECL(RTLDRARCH) RTLdrGetArch(RTLDRMOD hLdrMod)
+{
+ AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRARCH_INVALID);
+ PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
+ return pMod->enmArch;
+}
+RT_EXPORT_SYMBOL(RTLdrGetArch);
+
+
RTDECL(int) RTLdrClose(RTLDRMOD hLdrMod)
{
LogFlow(("RTLdrClose: hLdrMod=%RTldrm\n", hLdrMod));
@@ -137,6 +158,12 @@ RTDECL(int) RTLdrClose(RTLDRMOD hLdrMod)
AssertRC(rc);
pMod->eState = LDR_STATE_INVALID;
pMod->u32Magic++;
+ if (pMod->pReader)
+ {
+ rc = pMod->pReader->pfnDestroy(pMod->pReader);
+ AssertRC(rc);
+ pMod->pReader = NULL;
+ }
RTMemFree(pMod);
LogFlow(("RTLdrClose: returns VINF_SUCCESS\n"));
diff --git a/src/VBox/Runtime/common/ldr/ldrELF.cpp b/src/VBox/Runtime/common/ldr/ldrELF.cpp
index 47b45f61..ce08533b 100644
--- a/src/VBox/Runtime/common/ldr/ldrELF.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrELF.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -48,8 +48,10 @@
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
-/** Finds an ELF string. */
+/** Finds an ELF symbol table string. */
#define ELF_STR(pHdrs, iStr) ((pHdrs)->pStr + (iStr))
+/** Finds an ELF section header string. */
+#define ELF_SH_STR(pHdrs, iStr) ((pHdrs)->pShStr + (iStr))
diff --git a/src/VBox/Runtime/common/ldr/ldrELFRelocatable.cpp.h b/src/VBox/Runtime/common/ldr/ldrELFRelocatable.cpp.h
index 20d11b35..bd7760b4 100644
--- a/src/VBox/Runtime/common/ldr/ldrELFRelocatable.cpp.h
+++ b/src/VBox/Runtime/common/ldr/ldrELFRelocatable.cpp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -92,21 +92,25 @@ typedef struct RTLDRMODELF
{
/** Core module structure. */
RTLDRMODINTERNAL Core;
- /** Pointer to the reader instance. */
- PRTLDRREADER pReader;
/** Pointer to readonly mapping of the image bits.
* This mapping is provided by the pReader. */
const void *pvBits;
/** The ELF header. */
Elf_Ehdr Ehdr;
- /** Pointer to our copy of the section headers.
+ /** Pointer to our copy of the section headers with sh_addr as RVAs.
* The virtual addresses in this array is the 0 based assignments we've given the image.
* Not valid if the image is DONE. */
Elf_Shdr *paShdrs;
+ /** Unmodified section headers (allocated after paShdrs, so no need to free).
+ * Not valid if the image is DONE. */
+ Elf_Shdr const *paOrgShdrs;
/** The size of the loaded image. */
size_t cbImage;
+ /** The image base address if it's an EXEC or DYN image. */
+ Elf_Addr LinkAddress;
+
/** The symbol section index. */
unsigned iSymSh;
/** Number of symbols in the table. */
@@ -120,6 +124,11 @@ typedef struct RTLDRMODELF
unsigned cbStr;
/** Pointer to string table within RTLDRMODELF::pvBits. */
const char *pStr;
+
+ /** Size of the section header string table. */
+ unsigned cbShStr;
+ /** Pointer to section header string table within RTLDRMODELF::pvBits. */
+ const char *pShStr;
} RTLDRMODELF, *PRTLDRMODELF;
@@ -136,7 +145,7 @@ static int RTLDRELF_NAME(MapBits)(PRTLDRMODELF pModElf, bool fNeedsBits)
NOREF(fNeedsBits);
if (pModElf->pvBits)
return VINF_SUCCESS;
- int rc = pModElf->pReader->pfnMap(pModElf->pReader, &pModElf->pvBits);
+ int rc = pModElf->Core.pReader->pfnMap(pModElf->Core.pReader, &pModElf->pvBits);
if (RT_SUCCESS(rc))
{
const uint8_t *pu8 = (const uint8_t *)pModElf->pvBits;
@@ -144,11 +153,244 @@ static int RTLDRELF_NAME(MapBits)(PRTLDRMODELF pModElf, bool fNeedsBits)
pModElf->paSyms = (const Elf_Sym *)(pu8 + pModElf->paShdrs[pModElf->iSymSh].sh_offset);
if (pModElf->iStrSh != ~0U)
pModElf->pStr = (const char *)(pu8 + pModElf->paShdrs[pModElf->iStrSh].sh_offset);
+ pModElf->pShStr = (const char *)(pu8 + pModElf->paShdrs[pModElf->Ehdr.e_shstrndx].sh_offset);
}
return rc;
}
+/*
+ *
+ * EXEC & DYN.
+ * EXEC & DYN.
+ * EXEC & DYN.
+ * EXEC & DYN.
+ * EXEC & DYN.
+ *
+ */
+
+
+/**
+ * Applies the fixups for a section in an executable image.
+ *
+ * @returns iprt status code.
+ * @param pModElf The ELF loader module instance data.
+ * @param BaseAddr The base address which the module is being fixedup to.
+ * @param pfnGetImport The callback function to use to resolve imports (aka unresolved externals).
+ * @param pvUser User argument to pass to the callback.
+ * @param SecAddr The section address. This is the address the relocations are relative to.
+ * @param cbSec The section size. The relocations must be inside this.
+ * @param pu8SecBaseR Where we read section bits from.
+ * @param pu8SecBaseW Where we write section bits to.
+ * @param pvRelocs Pointer to where we read the relocations from.
+ * @param cbRelocs Size of the relocations.
+ */
+static int RTLDRELF_NAME(RelocateSectionExecDyn)(PRTLDRMODELF pModElf, Elf_Addr BaseAddr,
+ PFNRTLDRIMPORT pfnGetImport, void *pvUser,
+ const Elf_Addr SecAddr, Elf_Size cbSec,
+ const uint8_t *pu8SecBaseR, uint8_t *pu8SecBaseW,
+ const void *pvRelocs, Elf_Size cbRelocs)
+{
+#if ELF_MODE != 32
+ NOREF(pu8SecBaseR);
+#endif
+
+ /*
+ * Iterate the relocations.
+ * The relocations are stored in an array of Elf32_Rel records and covers the entire relocation section.
+ */
+ const Elf_Addr offDelta = BaseAddr - pModElf->LinkAddress;
+ const Elf_Reloc *paRels = (const Elf_Reloc *)pvRelocs;
+ const unsigned iRelMax = (unsigned)(cbRelocs / sizeof(paRels[0]));
+ AssertMsgReturn(iRelMax == cbRelocs / sizeof(paRels[0]), (FMT_ELF_SIZE "\n", cbRelocs / sizeof(paRels[0])),
+ VERR_IMAGE_TOO_BIG);
+ for (unsigned iRel = 0; iRel < iRelMax; iRel++)
+ {
+ /*
+ * Skip R_XXX_NONE entries early to avoid confusion in the symbol
+ * getter code.
+ */
+#if ELF_MODE == 32
+ if (ELF_R_TYPE(paRels[iRel].r_info) == R_386_NONE)
+ continue;
+#elif ELF_MODE == 64
+ if (ELF_R_TYPE(paRels[iRel].r_info) == R_X86_64_NONE)
+ continue;
+#endif
+
+ /*
+ * Validate and find the symbol, resolve undefined ones.
+ */
+ Elf_Size iSym = ELF_R_SYM(paRels[iRel].r_info);
+ if (iSym >= pModElf->cSyms)
+ {
+ AssertMsgFailed(("iSym=%d is an invalid symbol index!\n", iSym));
+ return VERR_LDRELF_INVALID_SYMBOL_INDEX;
+ }
+ const Elf_Sym *pSym = &pModElf->paSyms[iSym];
+ if (pSym->st_name >= pModElf->cbStr)
+ {
+ AssertMsgFailed(("iSym=%d st_name=%d str sh_size=%d\n", iSym, pSym->st_name, pModElf->cbStr));
+ return VERR_LDRELF_INVALID_SYMBOL_NAME_OFFSET;
+ }
+
+ Elf_Addr SymValue = 0;
+ if (pSym->st_shndx == SHN_UNDEF)
+ {
+ /* Try to resolve the symbol. */
+ const char *pszName = ELF_STR(pModElf, pSym->st_name);
+ RTUINTPTR ExtValue;
+ int rc = pfnGetImport(&pModElf->Core, "", pszName, ~0, &ExtValue, pvUser);
+ AssertMsgRCReturn(rc, ("Failed to resolve '%s' rc=%Rrc\n", pszName, rc), rc);
+ SymValue = (Elf_Addr)ExtValue;
+ AssertMsgReturn((RTUINTPTR)SymValue == ExtValue, ("Symbol value overflowed! '%s'\n", pszName),
+ VERR_SYMBOL_VALUE_TOO_BIG);
+ Log2(("rtldrELF: #%-3d - UNDEF " FMT_ELF_ADDR " '%s'\n", iSym, SymValue, pszName));
+ }
+ else
+ {
+ AssertReturn(pSym->st_shndx < pModElf->cSyms || pSym->st_shndx == SHN_ABS, ("%#x\n", pSym->st_shndx));
+#if ELF_MODE == 64
+ SymValue = pSym->st_value;
+#endif
+ }
+
+#if ELF_MODE == 64
+ /* Calc the value. */
+ Elf_Addr Value;
+ if (pSym->st_shndx < pModElf->cSyms)
+ Value = SymValue + offDelta;
+ else
+ Value = SymValue + paRels[iRel].r_addend;
+#endif
+
+ /*
+ * Apply the fixup.
+ */
+ AssertMsgReturn(paRels[iRel].r_offset < cbSec, (FMT_ELF_ADDR " " FMT_ELF_SIZE "\n", paRels[iRel].r_offset, cbSec), VERR_LDRELF_INVALID_RELOCATION_OFFSET);
+#if ELF_MODE == 32
+ const Elf_Addr *pAddrR = (const Elf_Addr *)(pu8SecBaseR + paRels[iRel].r_offset); /* Where to read the addend. */
+#endif
+ Elf_Addr *pAddrW = (Elf_Addr *)(pu8SecBaseW + paRels[iRel].r_offset); /* Where to write the fixup. */
+ switch (ELF_R_TYPE(paRels[iRel].r_info))
+ {
+#if ELF_MODE == 32
+ /*
+ * Absolute addressing.
+ */
+ case R_386_32:
+ {
+ Elf_Addr Value;
+ if (pSym->st_shndx < pModElf->Ehdr.e_shnum)
+ Value = *pAddrR + offDelta; /* Simplified. */
+ else if (pSym->st_shndx == SHN_ABS)
+ continue; /* Internal fixup, no need to apply it. */
+ else if (pSym->st_shndx == SHN_UNDEF)
+ Value = SymValue + *pAddrR;
+ else
+ AssertFailedReturn(VERR_LDR_GENERAL_FAILURE); /** @todo SHN_COMMON */
+ *(uint32_t *)pAddrW = Value;
+ Log4((FMT_ELF_ADDR": R_386_32 Value=" FMT_ELF_ADDR "\n", SecAddr + paRels[iRel].r_offset + BaseAddr, Value));
+ break;
+ }
+
+ /*
+ * PC relative addressing.
+ */
+ case R_386_PC32:
+ {
+ Elf_Addr Value;
+ if (pSym->st_shndx < pModElf->Ehdr.e_shnum)
+ continue; /* Internal fixup, no need to apply it. */
+ else if (pSym->st_shndx == SHN_ABS)
+ Value = *pAddrR + offDelta; /* Simplified. */
+ else if (pSym->st_shndx == SHN_UNDEF)
+ {
+ const Elf_Addr SourceAddr = SecAddr + paRels[iRel].r_offset + BaseAddr; /* Where the source really is. */
+ Value = SymValue + *(uint32_t *)pAddrR - SourceAddr;
+ *(uint32_t *)pAddrW = Value;
+ }
+ else
+ AssertFailedReturn(VERR_LDR_GENERAL_FAILURE); /** @todo SHN_COMMON */
+ Log4((FMT_ELF_ADDR": R_386_PC32 Value=" FMT_ELF_ADDR "\n", SecAddr + paRels[iRel].r_offset + BaseAddr, Value));
+ break;
+ }
+
+#elif ELF_MODE == 64
+
+ /*
+ * Absolute addressing
+ */
+ case R_X86_64_64:
+ {
+ *(uint64_t *)pAddrW = Value;
+ Log4((FMT_ELF_ADDR": R_X86_64_64 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
+ SecAddr + paRels[iRel].r_offset + BaseAddr, Value, SymValue));
+ break;
+ }
+
+ /*
+ * Truncated 32-bit value (zero-extendedable to the 64-bit value).
+ */
+ case R_X86_64_32:
+ {
+ *(uint32_t *)pAddrW = (uint32_t)Value;
+ Log4((FMT_ELF_ADDR": R_X86_64_32 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
+ SecAddr + paRels[iRel].r_offset + BaseAddr, Value, SymValue));
+ AssertMsgReturn((Elf_Addr)*(uint32_t *)pAddrW == SymValue, ("Value=" FMT_ELF_ADDR "\n", SymValue),
+ VERR_SYMBOL_VALUE_TOO_BIG);
+ break;
+ }
+
+ /*
+ * Truncated 32-bit value (sign-extendedable to the 64-bit value).
+ */
+ case R_X86_64_32S:
+ {
+ *(int32_t *)pAddrW = (int32_t)Value;
+ Log4((FMT_ELF_ADDR": R_X86_64_32S Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
+ SecAddr + paRels[iRel].r_offset + BaseAddr, Value, SymValue));
+ AssertMsgReturn((Elf_Addr)*(int32_t *)pAddrW == Value, ("Value=" FMT_ELF_ADDR "\n", Value), VERR_SYMBOL_VALUE_TOO_BIG); /** @todo check the sign-extending here. */
+ break;
+ }
+
+ /*
+ * PC relative addressing.
+ */
+ case R_X86_64_PC32:
+ {
+ const Elf_Addr SourceAddr = SecAddr + paRels[iRel].r_offset + BaseAddr; /* Where the source really is. */
+ Value -= SourceAddr;
+ *(int32_t *)pAddrW = (int32_t)Value;
+ Log4((FMT_ELF_ADDR": R_X86_64_PC32 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
+ SourceAddr, Value, SymValue));
+ AssertMsgReturn((Elf_Addr)*(int32_t *)pAddrW == Value, ("Value=" FMT_ELF_ADDR "\n", Value), VERR_SYMBOL_VALUE_TOO_BIG); /** @todo check the sign-extending here. */
+ break;
+ }
+#endif
+
+ default:
+ AssertMsgFailed(("Unknown relocation type: %d (iRel=%d iRelMax=%d)\n",
+ ELF_R_TYPE(paRels[iRel].r_info), iRel, iRelMax));
+ return VERR_LDRELF_RELOCATION_NOT_SUPPORTED;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+
+/*
+ *
+ * REL
+ * REL
+ * REL
+ * REL
+ * REL
+ *
+ */
+
/**
* Get the symbol and symbol value.
*
@@ -279,9 +521,22 @@ static int RTLDRELF_NAME(RelocateSection)(PRTLDRMODELF pModElf, Elf_Addr BaseAdd
for (unsigned iRel = 0; iRel < iRelMax; iRel++)
{
/*
+ * Skip R_XXX_NONE entries early to avoid confusion in the symbol
+ * getter code.
+ */
+#if ELF_MODE == 32
+ if (ELF_R_TYPE(paRels[iRel].r_info) == R_386_NONE)
+ continue;
+#elif ELF_MODE == 64
+ if (ELF_R_TYPE(paRels[iRel].r_info) == R_X86_64_NONE)
+ continue;
+#endif
+
+
+ /*
* Get the symbol.
*/
- const Elf_Sym *pSym;
+ const Elf_Sym *pSym = NULL; /* shut up gcc */
Elf_Addr SymValue = 0; /* shut up gcc-4 */
int rc = RTLDRELF_NAME(Symbol)(pModElf, BaseAddr, pfnGetImport, pvUser, ELF_R_SYM(paRels[iRel].r_info), &pSym, &SymValue);
if (RT_FAILURE(rc))
@@ -413,12 +668,6 @@ static DECLCALLBACK(int) RTLDRELF_NAME(Close)(PRTLDRMODINTERNAL pMod)
pModElf->paShdrs = NULL;
}
- if (pModElf->pReader)
- {
- pModElf->pReader->pfnDestroy(pModElf->pReader);
- pModElf->pReader = NULL;
- }
-
pModElf->pvBits = NULL;
return VINF_SUCCESS;
@@ -474,8 +723,13 @@ static DECLCALLBACK(int) RTLDRELF_NAME(EnumSymbols)(PRTLDRMODINTERNAL pMod, unsi
/* absolute symbols are not subject to any relocation. */
Value = paSyms[iSym].st_value;
else if (paSyms[iSym].st_shndx < pModElf->Ehdr.e_shnum)
- /* relative to the section. */
- Value = BaseAddr + paSyms[iSym].st_value + pModElf->paShdrs[paSyms[iSym].st_shndx].sh_addr;
+ {
+ if (pModElf->Ehdr.e_type == ET_REL)
+ /* relative to the section. */
+ Value = BaseAddr + paSyms[iSym].st_value + pModElf->paShdrs[paSyms[iSym].st_shndx].sh_addr;
+ else /* Fixed up for link address. */
+ Value = BaseAddr + paSyms[iSym].st_value - pModElf->LinkAddress;
+ }
else
{
AssertMsgFailed(("Arg! paSyms[%u].st_shndx=" FMT_ELF_HALF "\n", iSym, paSyms[iSym].st_shndx));
@@ -524,10 +778,10 @@ static DECLCALLBACK(int) RTLDRELF_NAME(GetBits)(PRTLDRMODINTERNAL pMod, void *pv
case ET_REL:
break;
case ET_EXEC:
- Log(("RTLdrELF: %s: Executable images are not supported yet!\n", pModElf->pReader->pfnLogName(pModElf->pReader)));
+ Log(("RTLdrELF: %s: Executable images are not supported yet!\n", pModElf->Core.pReader->pfnLogName(pModElf->Core.pReader)));
return VERR_LDRELF_EXEC;
case ET_DYN:
- Log(("RTLdrELF: %s: Dynamic images are not supported yet!\n", pModElf->pReader->pfnLogName(pModElf->pReader)));
+ Log(("RTLdrELF: %s: Dynamic images are not supported yet!\n", pModElf->Core.pReader->pfnLogName(pModElf->Core.pReader)));
return VERR_LDRELF_DYN;
default: AssertFailedReturn(VERR_BAD_EXE_FORMAT);
}
@@ -550,12 +804,12 @@ static DECLCALLBACK(int) RTLDRELF_NAME(GetBits)(PRTLDRMODINTERNAL pMod, void *pv
case SHT_PROGBITS:
default:
{
- int rc = pModElf->pReader->pfnRead(pModElf->pReader, (uint8_t *)pvBits + paShdrs[iShdr].sh_addr,
- (size_t)paShdrs[iShdr].sh_size, paShdrs[iShdr].sh_offset);
+ int rc = pModElf->Core.pReader->pfnRead(pModElf->Core.pReader, (uint8_t *)pvBits + paShdrs[iShdr].sh_addr,
+ (size_t)paShdrs[iShdr].sh_size, paShdrs[iShdr].sh_offset);
if (RT_FAILURE(rc))
{
Log(("RTLdrELF: %s: Read error when reading " FMT_ELF_SIZE " bytes at " FMT_ELF_OFF ", iShdr=%d\n",
- pModElf->pReader->pfnLogName(pModElf->pReader),
+ pModElf->Core.pReader->pfnLogName(pModElf->Core.pReader),
paShdrs[iShdr].sh_size, paShdrs[iShdr].sh_offset, iShdr));
return rc;
}
@@ -577,7 +831,7 @@ static DECLCALLBACK(int) RTLDRELF_NAME(Relocate)(PRTLDRMODINTERNAL pMod, void *p
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
#ifdef LOG_ENABLED
- const char *pszLogName = pModElf->pReader->pfnLogName(pModElf->pReader);
+ const char *pszLogName = pModElf->Core.pReader->pfnLogName(pModElf->Core.pReader);
#endif
NOREF(OldBaseAddress);
@@ -640,17 +894,26 @@ static DECLCALLBACK(int) RTLDRELF_NAME(Relocate)(PRTLDRMODINTERNAL pMod, void *p
* Relocate the section.
*/
Log2(("rtldrELF: %s: Relocation records for #%d [%s] (sh_info=%d sh_link=%d) found in #%d [%s] (sh_info=%d sh_link=%d)\n",
- pszLogName, (int)pShdrRel->sh_info, ELF_STR(pModElf, pShdr->sh_name), (int)pShdr->sh_info, (int)pShdr->sh_link,
- iShdr, ELF_STR(pModElf, pShdrRel->sh_name), (int)pShdrRel->sh_info, (int)pShdrRel->sh_link));
+ pszLogName, (int)pShdrRel->sh_info, ELF_SH_STR(pModElf, pShdr->sh_name), (int)pShdr->sh_info, (int)pShdr->sh_link,
+ iShdr, ELF_SH_STR(pModElf, pShdrRel->sh_name), (int)pShdrRel->sh_info, (int)pShdrRel->sh_link));
/** @todo Make RelocateSection a function pointer so we can select the one corresponding to the machine when opening the image. */
- rc = RTLDRELF_NAME(RelocateSection)(pModElf, BaseAddr, pfnGetImport, pvUser,
- pShdr->sh_addr,
- pShdr->sh_size,
- (const uint8_t *)pModElf->pvBits + pShdr->sh_offset,
- (uint8_t *)pvBits + pShdr->sh_addr,
- (const uint8_t *)pModElf->pvBits + pShdrRel->sh_offset,
- pShdrRel->sh_size);
+ if (pModElf->Ehdr.e_type == ET_REL)
+ rc = RTLDRELF_NAME(RelocateSection)(pModElf, BaseAddr, pfnGetImport, pvUser,
+ pShdr->sh_addr,
+ pShdr->sh_size,
+ (const uint8_t *)pModElf->pvBits + pShdr->sh_offset,
+ (uint8_t *)pvBits + pShdr->sh_addr,
+ (const uint8_t *)pModElf->pvBits + pShdrRel->sh_offset,
+ pShdrRel->sh_size);
+ else
+ rc = RTLDRELF_NAME(RelocateSectionExecDyn)(pModElf, BaseAddr, pfnGetImport, pvUser,
+ pShdr->sh_addr,
+ pShdr->sh_size,
+ (const uint8_t *)pModElf->pvBits + pShdr->sh_offset,
+ (uint8_t *)pvBits + pShdr->sh_addr,
+ (const uint8_t *)pModElf->pvBits + pShdrRel->sh_offset,
+ pShdrRel->sh_size);
if (RT_FAILURE(rc))
return rc;
}
@@ -701,8 +964,13 @@ static DECLCALLBACK(int) RTLDRELF_NAME(GetSymbolEx)(PRTLDRMODINTERNAL pMod, cons
/* absolute symbols are not subject to any relocation. */
Value = paSyms[iSym].st_value;
else if (paSyms[iSym].st_shndx < pModElf->Ehdr.e_shnum)
- /* relative to the section. */
- Value = BaseAddr + paSyms[iSym].st_value + pModElf->paShdrs[paSyms[iSym].st_shndx].sh_addr;
+ {
+ if (pModElf->Ehdr.e_type == ET_REL)
+ /* relative to the section. */
+ Value = BaseAddr + paSyms[iSym].st_value + pModElf->paShdrs[paSyms[iSym].st_shndx].sh_addr;
+ else /* Fixed up for link address. */
+ Value = BaseAddr + paSyms[iSym].st_value - pModElf->LinkAddress;
+ }
else
{
AssertMsgFailed(("Arg. paSyms[iSym].st_shndx=%d\n", paSyms[iSym].st_shndx));
@@ -730,18 +998,163 @@ static DECLCALLBACK(int) RTLDRELF_NAME(EnumDbgInfo)(PRTLDRMODINTERNAL pMod, cons
PFNRTLDRENUMDBG pfnCallback, void *pvUser)
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
- NOREF(pvBits);
- return VERR_NOT_IMPLEMENTED; NOREF(pModElf); NOREF(pfnCallback); NOREF(pvUser);
+ /*
+ * Map the image bits if not already done and setup pointer into it.
+ */
+ int rc = RTLDRELF_NAME(MapBits)(pModElf, true);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Do the enumeration.
+ */
+ const Elf_Shdr *paShdrs = pModElf->paOrgShdrs;
+ for (unsigned iShdr = 0; iShdr < pModElf->Ehdr.e_shnum; iShdr++)
+ {
+ /* Debug sections are expected to be PROGBITS and not allocated. */
+ if (paShdrs[iShdr].sh_type != SHT_PROGBITS)
+ continue;
+ if (paShdrs[iShdr].sh_flags & SHF_ALLOC)
+ continue;
+
+ RTLDRDBGINFO DbgInfo;
+ const char *pszSectName = ELF_SH_STR(pModElf, paShdrs[iShdr].sh_name);
+ if ( !strncmp(pszSectName, RT_STR_TUPLE(".debug_"))
+ || !strcmp(pszSectName, ".WATCOM_references") )
+ {
+ RT_ZERO(DbgInfo.u);
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_DWARF;
+ DbgInfo.pszExtFile = NULL;
+ DbgInfo.offFile = paShdrs[iShdr].sh_offset;
+ DbgInfo.cb = paShdrs[iShdr].sh_size;
+ DbgInfo.u.Dwarf.pszSection = pszSectName;
+ }
+ else if (!strcmp(pszSectName, ".gnu_debuglink"))
+ {
+ if ((paShdrs[iShdr].sh_size & 3) || paShdrs[iShdr].sh_size < 8)
+ return VERR_BAD_EXE_FORMAT;
+
+ RT_ZERO(DbgInfo.u);
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_DWARF_DWO;
+ DbgInfo.pszExtFile = (const char *)((uintptr_t)pModElf->pvBits + (uintptr_t)paShdrs[iShdr].sh_offset);
+ if (!RTStrEnd(DbgInfo.pszExtFile, paShdrs[iShdr].sh_size))
+ return VERR_BAD_EXE_FORMAT;
+ DbgInfo.u.Dwo.uCrc32 = *(uint32_t *)((uintptr_t)DbgInfo.pszExtFile + (uintptr_t)paShdrs[iShdr].sh_size
+ - sizeof(uint32_t));
+ DbgInfo.offFile = -1;
+ DbgInfo.cb = 0;
+ }
+ else
+ continue;
+
+ DbgInfo.LinkAddress = NIL_RTLDRADDR;
+ DbgInfo.iDbgInfo = iShdr - 1;
+
+ rc = pfnCallback(pMod, &DbgInfo, pvUser);
+ if (rc != VINF_SUCCESS)
+ return rc;
+
+ }
+
+ return VINF_SUCCESS;
}
+/**
+ * Helper that locates the first allocated section.
+ *
+ * @returns Pointer to the section header if found, NULL if none.
+ * @param pShdr The section header to start searching at.
+ * @param cLeft The number of section headers left to search. Can be 0.
+ */
+static const Elf_Shdr *RTLDRELF_NAME(GetFirstAllocatedSection)(const Elf_Shdr *pShdr, unsigned cLeft)
+{
+ while (cLeft-- > 0)
+ {
+ if (pShdr->sh_flags & SHF_ALLOC)
+ return pShdr;
+ pShdr++;
+ }
+ return NULL;
+}
+
/** @copydoc RTLDROPS::pfnEnumSegments. */
static DECLCALLBACK(int) RTLDRELF_NAME(EnumSegments)(PRTLDRMODINTERNAL pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser)
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
- return VERR_NOT_IMPLEMENTED; NOREF(pModElf); NOREF(pfnCallback); NOREF(pvUser);
+ /*
+ * Map the image bits if not already done and setup pointer into it.
+ */
+ int rc = RTLDRELF_NAME(MapBits)(pModElf, true);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Do the enumeration.
+ */
+ char szName[32];
+ Elf_Addr uPrevMappedRva = 0;
+ const Elf_Shdr *paShdrs = pModElf->paShdrs;
+ const Elf_Shdr *paOrgShdrs = pModElf->paOrgShdrs;
+ for (unsigned iShdr = 1; iShdr < pModElf->Ehdr.e_shnum; iShdr++)
+ {
+ RTLDRSEG Seg;
+ Seg.pszName = ELF_SH_STR(pModElf, paShdrs[iShdr].sh_name);
+ Seg.cchName = (uint32_t)strlen(Seg.pszName);
+ if (Seg.cchName == 0)
+ {
+ Seg.pszName = szName;
+ Seg.cchName = (uint32_t)RTStrPrintf(szName, sizeof(szName), "UnamedSect%02u", iShdr);
+ }
+ Seg.SelFlat = 0;
+ Seg.Sel16bit = 0;
+ Seg.fFlags = 0;
+ Seg.fProt = RTMEM_PROT_READ;
+ if (paShdrs[iShdr].sh_flags & SHF_WRITE)
+ Seg.fProt |= RTMEM_PROT_WRITE;
+ if (paShdrs[iShdr].sh_flags & SHF_EXECINSTR)
+ Seg.fProt |= RTMEM_PROT_EXEC;
+ Seg.cb = paShdrs[iShdr].sh_size;
+ Seg.Alignment = paShdrs[iShdr].sh_addralign;
+ if (paShdrs[iShdr].sh_flags & SHF_ALLOC)
+ {
+ Seg.LinkAddress = paOrgShdrs[iShdr].sh_addr;
+ Seg.RVA = paShdrs[iShdr].sh_addr;
+ const Elf_Shdr *pShdr2 = RTLDRELF_NAME(GetFirstAllocatedSection)(&paShdrs[iShdr + 1],
+ pModElf->Ehdr.e_shnum - iShdr - 1);
+ if ( pShdr2
+ && pShdr2->sh_addr >= paShdrs[iShdr].sh_addr
+ && Seg.RVA >= uPrevMappedRva)
+ Seg.cbMapped = pShdr2->sh_addr - paShdrs[iShdr].sh_addr;
+ else
+ Seg.cbMapped = RT_MAX(paShdrs[iShdr].sh_size, paShdrs[iShdr].sh_addralign);
+ uPrevMappedRva = Seg.RVA;
+ }
+ else
+ {
+ Seg.LinkAddress = NIL_RTLDRADDR;
+ Seg.RVA = NIL_RTLDRADDR;
+ Seg.cbMapped = NIL_RTLDRADDR;
+ }
+ if (paShdrs[iShdr].sh_type != SHT_NOBITS)
+ {
+ Seg.offFile = paShdrs[iShdr].sh_offset;
+ Seg.cbFile = paShdrs[iShdr].sh_size;
+ }
+ else
+ {
+ Seg.offFile = -1;
+ Seg.cbFile = 0;
+ }
+
+ rc = pfnCallback(pMod, &Seg, pvUser);
+ if (rc != VINF_SUCCESS)
+ return rc;
+ }
+
+ return VINF_SUCCESS;
}
@@ -751,7 +1164,34 @@ static DECLCALLBACK(int) RTLDRELF_NAME(LinkAddressToSegOffset)(PRTLDRMODINTERNAL
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
- return VERR_NOT_IMPLEMENTED; NOREF(pModElf); NOREF(LinkAddress); NOREF(piSeg); NOREF(poffSeg);
+ const Elf_Shdr *pShdrEnd = NULL;
+ unsigned cLeft = pModElf->Ehdr.e_shnum - 1;
+ const Elf_Shdr *pShdr = &pModElf->paOrgShdrs[cLeft];
+ while (cLeft-- > 0)
+ {
+ if (pShdr->sh_flags & SHF_ALLOC)
+ {
+ RTLDRADDR offSeg = LinkAddress - pShdr->sh_addr;
+ if (offSeg < pShdr->sh_size)
+ {
+ *poffSeg = offSeg;
+ *piSeg = cLeft;
+ return VINF_SUCCESS;
+ }
+ if (offSeg == pShdr->sh_size)
+ pShdrEnd = pShdr;
+ }
+ pShdr--;
+ }
+
+ if (pShdrEnd)
+ {
+ *poffSeg = pShdrEnd->sh_size;
+ *piSeg = pShdrEnd - pModElf->paOrgShdrs - 1;
+ return VINF_SUCCESS;
+ }
+
+ return VERR_LDR_INVALID_LINK_ADDRESS;
}
@@ -759,8 +1199,12 @@ static DECLCALLBACK(int) RTLDRELF_NAME(LinkAddressToSegOffset)(PRTLDRMODINTERNAL
static DECLCALLBACK(int) RTLDRELF_NAME(LinkAddressToRva)(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva)
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
-
- return VERR_NOT_IMPLEMENTED; NOREF(pModElf); NOREF(LinkAddress); NOREF(pRva);
+ uint32_t iSeg;
+ RTLDRADDR offSeg;
+ int rc = RTLDRELF_NAME(LinkAddressToSegOffset)(pMod, LinkAddress, &iSeg, &offSeg);
+ if (RT_SUCCESS(rc))
+ *pRva = pModElf->paShdrs[iSeg + 1].sh_addr + offSeg;
+ return rc;
}
@@ -769,8 +1213,24 @@ static DECLCALLBACK(int) RTLDRELF_NAME(SegOffsetToRva)(PRTLDRMODINTERNAL pMod, u
PRTLDRADDR pRva)
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
+ if (iSeg >= pModElf->Ehdr.e_shnum - 1U)
+ return VERR_LDR_INVALID_SEG_OFFSET;
+
+ iSeg++; /* skip section 0 */
+ if (offSeg > pModElf->paShdrs[iSeg].sh_size)
+ {
+ const Elf_Shdr *pShdr2 = RTLDRELF_NAME(GetFirstAllocatedSection)(&pModElf->paShdrs[iSeg + 1],
+ pModElf->Ehdr.e_shnum - iSeg - 1);
+ if ( !pShdr2
+ || offSeg > (pShdr2->sh_addr - pModElf->paShdrs[iSeg].sh_addr))
+ return VERR_LDR_INVALID_SEG_OFFSET;
+ }
+
+ if (!(pModElf->paShdrs[iSeg].sh_flags & SHF_ALLOC))
+ return VERR_LDR_INVALID_SEG_OFFSET;
- return VERR_NOT_IMPLEMENTED; NOREF(pModElf); NOREF(iSeg); NOREF(offSeg); NOREF(pRva);
+ *pRva = pModElf->paShdrs[iSeg].sh_addr;
+ return VINF_SUCCESS;
}
@@ -780,7 +1240,136 @@ static DECLCALLBACK(int) RTLDRELF_NAME(RvaToSegOffset)(PRTLDRMODINTERNAL pMod, R
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
- return VERR_NOT_IMPLEMENTED; NOREF(pModElf); NOREF(Rva); NOREF(piSeg); NOREF(poffSeg);
+ Elf_Addr PrevAddr = 0;
+ unsigned cLeft = pModElf->Ehdr.e_shnum - 1;
+ const Elf_Shdr *pShdr = &pModElf->paShdrs[cLeft];
+ while (cLeft-- > 0)
+ {
+ if (pShdr->sh_flags & SHF_ALLOC)
+ {
+ Elf_Addr cbSeg = PrevAddr ? PrevAddr - pShdr->sh_addr : pShdr->sh_size;
+ RTLDRADDR offSeg = Rva - pShdr->sh_addr;
+ if (offSeg <= cbSeg)
+ {
+ *poffSeg = offSeg;
+ *piSeg = cLeft;
+ return VINF_SUCCESS;
+ }
+ PrevAddr = pShdr->sh_addr;
+ }
+ pShdr--;
+ }
+
+ return VERR_LDR_INVALID_RVA;
+}
+
+
+/** @callback_method_impl{FNRTLDRIMPORT, Stub used by ReadDbgInfo.} */
+static DECLCALLBACK(int) RTLDRELF_NAME(GetImportStubCallback)(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol,
+ unsigned uSymbol, PRTLDRADDR pValue, void *pvUser)
+{
+ return VERR_SYMBOL_NOT_FOUND;
+}
+
+
+/** @copydoc RTLDROPS::pfnRvaToSegOffset. */
+static DECLCALLBACK(int) RTLDRELF_NAME(ReadDbgInfo)(PRTLDRMODINTERNAL pMod, uint32_t iDbgInfo, RTFOFF off,
+ size_t cb, void *pvBuf)
+{
+ PRTLDRMODELF pThis = (PRTLDRMODELF)pMod;
+ LogFlow(("%s: iDbgInfo=%#x off=%RTfoff cb=%#zu\n", __FUNCTION__, iDbgInfo, off, cb));
+
+ /*
+ * Input validation.
+ */
+ AssertReturn(iDbgInfo < pThis->Ehdr.e_shnum && iDbgInfo + 1 < pThis->Ehdr.e_shnum, VERR_INVALID_PARAMETER);
+ iDbgInfo++;
+ AssertReturn(!(pThis->paShdrs[iDbgInfo].sh_flags & SHF_ALLOC), VERR_INVALID_PARAMETER);
+ AssertReturn(pThis->paShdrs[iDbgInfo].sh_type == SHT_PROGBITS, VERR_INVALID_PARAMETER);
+ AssertReturn(pThis->paShdrs[iDbgInfo].sh_offset == (uint64_t)off, VERR_INVALID_PARAMETER);
+ AssertReturn(pThis->paShdrs[iDbgInfo].sh_size == cb, VERR_INVALID_PARAMETER);
+ RTFOFF cbRawImage = pThis->Core.pReader->pfnSize(pThis->Core.pReader);
+ AssertReturn(cbRawImage >= 0, VERR_INVALID_PARAMETER);
+ AssertReturn(off >= 0 && cb <= (uint64_t)cbRawImage && (uint64_t)off + cb <= (uint64_t)cbRawImage, VERR_INVALID_PARAMETER);
+
+ /*
+ * Read it from the file and look for fixup sections.
+ */
+ int rc;
+ if (pThis->pvBits)
+ memcpy(pvBuf, (const uint8_t *)pThis->pvBits + (size_t)off, cb);
+ else
+ {
+ rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pvBuf, cb, off);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+
+ uint32_t iRelocs = iDbgInfo + 1;
+ if ( iRelocs >= pThis->Ehdr.e_shnum
+ || pThis->paShdrs[iRelocs].sh_info != iDbgInfo
+ || ( pThis->paShdrs[iRelocs].sh_type != SHT_REL
+ && pThis->paShdrs[iRelocs].sh_type != SHT_RELA) )
+ {
+ iRelocs = 0;
+ while ( iRelocs < pThis->Ehdr.e_shnum
+ && ( pThis->paShdrs[iRelocs].sh_info != iDbgInfo
+ || ( pThis->paShdrs[iRelocs].sh_type != SHT_REL
+ && pThis->paShdrs[iRelocs].sh_type != SHT_RELA)) )
+ iRelocs++;
+ }
+ if ( iRelocs < pThis->Ehdr.e_shnum
+ && pThis->paShdrs[iRelocs].sh_size > 0)
+ {
+ /*
+ * Load the relocations.
+ */
+ uint8_t *pbRelocsBuf = NULL;
+ const uint8_t *pbRelocs;
+ if (pThis->pvBits)
+ pbRelocs = (const uint8_t *)pThis->pvBits + pThis->paShdrs[iRelocs].sh_offset;
+ else
+ {
+ pbRelocs = pbRelocsBuf = (uint8_t *)RTMemTmpAlloc(pThis->paShdrs[iRelocs].sh_size);
+ if (!pbRelocsBuf)
+ return VERR_NO_TMP_MEMORY;
+ rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbRelocsBuf,
+ pThis->paShdrs[iRelocs].sh_size,
+ pThis->paShdrs[iRelocs].sh_offset);
+ if (RT_FAILURE(rc))
+ {
+ RTMemTmpFree(pbRelocsBuf);
+ return rc;
+ }
+ }
+
+ /*
+ * Apply the relocations.
+ */
+ if (pThis->Ehdr.e_type == ET_REL)
+ rc = RTLDRELF_NAME(RelocateSection)(pThis, pThis->LinkAddress,
+ RTLDRELF_NAME(GetImportStubCallback), NULL /*pvUser*/,
+ pThis->paShdrs[iDbgInfo].sh_addr,
+ pThis->paShdrs[iDbgInfo].sh_size,
+ (const uint8_t *)pvBuf,
+ (uint8_t *)pvBuf,
+ pbRelocs,
+ pThis->paShdrs[iRelocs].sh_size);
+ else
+ rc = RTLDRELF_NAME(RelocateSectionExecDyn)(pThis, pThis->LinkAddress,
+ RTLDRELF_NAME(GetImportStubCallback), NULL /*pvUser*/,
+ pThis->paShdrs[iDbgInfo].sh_addr,
+ pThis->paShdrs[iDbgInfo].sh_size,
+ (const uint8_t *)pvBuf,
+ (uint8_t *)pvBuf,
+ pbRelocs,
+ pThis->paShdrs[iRelocs].sh_size);
+
+ RTMemTmpFree(pbRelocsBuf);
+ }
+ else
+ rc = VINF_SUCCESS;
+ return rc;
}
@@ -810,6 +1399,7 @@ static RTLDROPS RTLDRELF_MID(s_rtldrElf,Ops) =
RTLDRELF_NAME(LinkAddressToRva),
RTLDRELF_NAME(SegOffsetToRva),
RTLDRELF_NAME(RvaToSegOffset),
+ RTLDRELF_NAME(ReadDbgInfo),
42
};
@@ -949,6 +1539,13 @@ static int RTLDRELF_NAME(ValidateElfHeader)(const Elf_Ehdr *pEhdr, const char *p
return VERR_BAD_EXE_FORMAT;
}
+ if (pEhdr->e_shstrndx == 0 || pEhdr->e_shstrndx > pEhdr->e_shnum)
+ {
+ Log(("RTLdrELF: %s: The section headers string table is out of bounds! e_shstrndx=" FMT_ELF_HALF " e_shnum=" FMT_ELF_HALF "\n",
+ pszLogName, pEhdr->e_shstrndx, pEhdr->e_shnum));
+ return VERR_BAD_EXE_FORMAT;
+ }
+
return VINF_SUCCESS;
}
@@ -956,7 +1553,6 @@ static int RTLDRELF_NAME(ValidateElfHeader)(const Elf_Ehdr *pEhdr, const char *p
* Gets the section header name.
*
* @returns pszName.
- * @param pReader The loader reader instance.
* @param pEhdr The elf header.
* @param offName The offset of the section header name.
* @param pszName Where to store the name.
@@ -965,13 +1561,13 @@ static int RTLDRELF_NAME(ValidateElfHeader)(const Elf_Ehdr *pEhdr, const char *p
const char *RTLDRELF_NAME(GetSHdrName)(PRTLDRMODELF pModElf, Elf_Word offName, char *pszName, size_t cbName)
{
RTFOFF off = pModElf->paShdrs[pModElf->Ehdr.e_shstrndx].sh_offset + offName;
- int rc = pModElf->pReader->pfnRead(pModElf->pReader, pszName, cbName - 1, off);
+ int rc = pModElf->Core.pReader->pfnRead(pModElf->Core.pReader, pszName, cbName - 1, off);
if (RT_FAILURE(rc))
{
/* read by for byte. */
for (unsigned i = 0; i < cbName; i++, off++)
{
- rc = pModElf->pReader->pfnRead(pModElf->pReader, pszName + i, 1, off);
+ rc = pModElf->Core.pReader->pfnRead(pModElf->Core.pReader, pszName + i, 1, off);
if (RT_FAILURE(rc))
{
pszName[i] = '\0';
@@ -1016,6 +1612,31 @@ static int RTLDRELF_NAME(ValidateSectionHeader)(PRTLDRMODELF pModElf, unsigned i
pShdr->sh_offset, pShdr->sh_size, pShdr->sh_link, pShdr->sh_info, pShdr->sh_addralign,
pShdr->sh_entsize));
+ if (iShdr == 0)
+ {
+ if ( pShdr->sh_name != 0
+ || pShdr->sh_type != SHT_NULL
+ || pShdr->sh_flags != 0
+ || pShdr->sh_addr != 0
+ || pShdr->sh_size != 0
+ || pShdr->sh_offset != 0
+ || pShdr->sh_link != SHN_UNDEF
+ || pShdr->sh_addralign != 0
+ || pShdr->sh_entsize != 0 )
+ {
+ Log(("RTLdrELF: %s: Bad #0 section: %.*Rhxs\n", pszLogName, sizeof(*pShdr), pShdr ));
+ return VERR_BAD_EXE_FORMAT;
+ }
+ return VINF_SUCCESS;
+ }
+
+ if (pShdr->sh_name >= pModElf->cbShStr)
+ {
+ Log(("RTLdrELF: %s: Shdr #%d: sh_name (%d) is beyond the end of the section header string table (%d)!\n",
+ pszLogName, iShdr, pShdr->sh_name, pModElf->cbShStr)); NOREF(pszLogName);
+ return VERR_BAD_EXE_FORMAT;
+ }
+
if (pShdr->sh_link >= pModElf->Ehdr.e_shnum)
{
Log(("RTLdrELF: %s: Shdr #%d: sh_link (%d) is beyond the end of the section table (%d)!\n",
@@ -1036,6 +1657,7 @@ static int RTLDRELF_NAME(ValidateSectionHeader)(PRTLDRMODELF pModElf, unsigned i
break;
case SHT_NULL:
+ break;
case SHT_PROGBITS:
case SHT_SYMTAB:
case SHT_STRTAB:
@@ -1096,7 +1718,6 @@ static int RTLDRELF_NAME(Open)(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH
{
const char *pszLogName = pReader->pfnLogName(pReader);
RTFOFF cbRawImage = pReader->pfnSize(pReader);
- AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
/*
* Create the loader module instance.
@@ -1107,17 +1728,28 @@ static int RTLDRELF_NAME(Open)(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH
pModElf->Core.u32Magic = RTLDRMOD_MAGIC;
pModElf->Core.eState = LDR_STATE_INVALID;
- pModElf->pReader = pReader;
+ pModElf->Core.pReader = pReader;
+ pModElf->Core.enmFormat = RTLDRFMT_ELF;
+ pModElf->Core.enmType = RTLDRTYPE_OBJECT;
+ pModElf->Core.enmEndian = RTLDRENDIAN_LITTLE;
+#if ELF_MODE == 32
+ pModElf->Core.enmArch = RTLDRARCH_X86_32;
+#else
+ pModElf->Core.enmArch = RTLDRARCH_AMD64;
+#endif
//pModElf->pvBits = NULL;
//pModElf->Ehdr = {0};
//pModElf->paShdrs = NULL;
//pModElf->paSyms = NULL;
pModElf->iSymSh = ~0U;
- pModElf->cSyms = 0;
+ //pModElf->cSyms = 0;
pModElf->iStrSh = ~0U;
- pModElf->cbStr = 0;
- pModElf->cbImage = 0;
+ //pModElf->cbStr = 0;
+ //pModElf->cbImage = 0;
+ //pModElf->LinkAddress = 0;
//pModElf->pStr = NULL;
+ //pModElf->cbShStr = 0;
+ //pModElf->pShStr = NULL;
/*
* Read and validate the ELF header and match up the CPU architecture.
@@ -1137,39 +1769,32 @@ static int RTLDRELF_NAME(Open)(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH
if (RT_SUCCESS(rc))
{
/*
- * Read the section headers.
+ * Read the section headers, keeping a prestine copy for the module
+ * introspection methods.
*/
- Elf_Shdr *paShdrs = (Elf_Shdr *)RTMemAlloc(pModElf->Ehdr.e_shnum * sizeof(Elf_Shdr));
+ size_t const cbShdrs = pModElf->Ehdr.e_shnum * sizeof(Elf_Shdr);
+ Elf_Shdr *paShdrs = (Elf_Shdr *)RTMemAlloc(cbShdrs * 2);
if (paShdrs)
{
pModElf->paShdrs = paShdrs;
- rc = pReader->pfnRead(pReader, paShdrs, pModElf->Ehdr.e_shnum * sizeof(Elf_Shdr),
- pModElf->Ehdr.e_shoff);
+ rc = pReader->pfnRead(pReader, paShdrs, cbShdrs, pModElf->Ehdr.e_shoff);
if (RT_SUCCESS(rc))
{
+ memcpy(&paShdrs[pModElf->Ehdr.e_shnum], paShdrs, cbShdrs);
+ pModElf->paOrgShdrs = &paShdrs[pModElf->Ehdr.e_shnum];
+
+ pModElf->cbShStr = paShdrs[pModElf->Ehdr.e_shstrndx].sh_size;
+
/*
- * Validate the section headers, allocate memory for the sections (determine the image size),
- * and find relevant sections.
+ * Validate the section headers and find relevant sections.
*/
+ Elf_Addr uNextAddr = 0;
for (unsigned i = 0; i < pModElf->Ehdr.e_shnum; i++)
{
rc = RTLDRELF_NAME(ValidateSectionHeader)(pModElf, i, pszLogName, cbRawImage);
if (RT_FAILURE(rc))
break;
- /* Allocate memory addresses for the section. */
- if (paShdrs[i].sh_flags & SHF_ALLOC)
- {
- paShdrs[i].sh_addr = paShdrs[i].sh_addralign
- ? RT_ALIGN_T(pModElf->cbImage, paShdrs[i].sh_addralign, Elf_Addr)
- : (Elf_Addr)pModElf->cbImage;
- pModElf->cbImage = (size_t)paShdrs[i].sh_addr + (size_t)paShdrs[i].sh_size;
- AssertMsgReturn(pModElf->cbImage == paShdrs[i].sh_addr + paShdrs[i].sh_size,
- (FMT_ELF_ADDR "\n", paShdrs[i].sh_addr + paShdrs[i].sh_size),
- VERR_IMAGE_TOO_BIG);
- Log2(("RTLdrElf: %s: Assigned " FMT_ELF_ADDR " to section #%d\n", pszLogName, paShdrs[i].sh_addr, i));
- }
-
/* We're looking for symbol tables. */
if (paShdrs[i].sh_type == SHT_SYMTAB)
{
@@ -1186,19 +1811,81 @@ static int RTLDRELF_NAME(Open)(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH
pModElf->cbStr = (unsigned)paShdrs[pModElf->iStrSh].sh_size;
AssertReturn(pModElf->cbStr == paShdrs[pModElf->iStrSh].sh_size, VERR_IMAGE_TOO_BIG);
}
+
+ /* Special checks for the section string table. */
+ if (i == pModElf->Ehdr.e_shstrndx)
+ {
+ if (paShdrs[i].sh_type != SHT_STRTAB)
+ {
+ Log(("RTLdrElf: Section header string table is not a SHT_STRTAB: %#x\n", paShdrs[i].sh_type));
+ rc = VERR_BAD_EXE_FORMAT;
+ break;
+ }
+ if (paShdrs[i].sh_size == 0)
+ {
+ Log(("RTLdrElf: Section header string table is empty\n"));
+ rc = VERR_BAD_EXE_FORMAT;
+ break;
+ }
+ }
+
+ /* Kluge for the .data..percpu segment in 64-bit linux kernels. */
+ if (paShdrs[i].sh_flags & SHF_ALLOC)
+ {
+ if ( paShdrs[i].sh_addr == 0
+ && paShdrs[i].sh_addr < uNextAddr)
+ {
+ Elf_Addr uAddr = RT_ALIGN_T(uNextAddr, paShdrs[i].sh_addralign, Elf_Addr);
+ Log(("RTLdrElf: Out of order section #%d; adjusting sh_addr from " FMT_ELF_ADDR " to " FMT_ELF_ADDR "\n",
+ paShdrs[i].sh_addr, uAddr));
+ paShdrs[i].sh_addr = uAddr;
+ }
+ uNextAddr = paShdrs[i].sh_addr + paShdrs[i].sh_size;
+ }
} /* for each section header */
- Log2(("RTLdrElf: iSymSh=%u cSyms=%u iStrSh=%u cbStr=%u rc=%Rrc cbImage=%#zx\n",
- pModElf->iSymSh, pModElf->cSyms, pModElf->iStrSh, pModElf->cbStr, rc, pModElf->cbImage));
-#if 0
/*
- * Are the section headers fine?
- * We require there to be symbol & string tables (at least for the time being).
+ * Calculate the image base address if the image isn't relocatable.
*/
- if ( pModElf->iSymSh == ~0U
- || pModElf->iStrSh == ~0U)
- rc = VERR_LDRELF_NO_SYMBOL_OR_NO_STRING_TABS;
-#endif
+ if (RT_SUCCESS(rc) && pModElf->Ehdr.e_type != ET_REL)
+ {
+ pModElf->LinkAddress = ~(Elf_Addr)0;
+ for (unsigned i = 0; i < pModElf->Ehdr.e_shnum; i++)
+ if ( (paShdrs[i].sh_flags & SHF_ALLOC)
+ && paShdrs[i].sh_addr < pModElf->LinkAddress)
+ pModElf->LinkAddress = paShdrs[i].sh_addr;
+ if (pModElf->LinkAddress == ~(Elf_Addr)0)
+ {
+ AssertFailed();
+ rc = VERR_LDR_GENERAL_FAILURE;
+ }
+ }
+
+ /*
+ * Perform allocations / RVA calculations, determine the image size.
+ */
+ if (RT_SUCCESS(rc))
+ for (unsigned i = 0; i < pModElf->Ehdr.e_shnum; i++)
+ if (paShdrs[i].sh_flags & SHF_ALLOC)
+ {
+ if (pModElf->Ehdr.e_type == ET_REL)
+ paShdrs[i].sh_addr = paShdrs[i].sh_addralign
+ ? RT_ALIGN_T(pModElf->cbImage, paShdrs[i].sh_addralign, Elf_Addr)
+ : (Elf_Addr)pModElf->cbImage;
+ else
+ paShdrs[i].sh_addr -= pModElf->LinkAddress;
+ Elf_Addr EndAddr = paShdrs[i].sh_addr + paShdrs[i].sh_size;
+ if (pModElf->cbImage < EndAddr)
+ {
+ pModElf->cbImage = (size_t)EndAddr;
+ AssertMsgReturn(pModElf->cbImage == EndAddr, (FMT_ELF_ADDR "\n", EndAddr), VERR_IMAGE_TOO_BIG);
+ }
+ Log2(("RTLdrElf: %s: Assigned " FMT_ELF_ADDR " to section #%d\n", pszLogName, paShdrs[i].sh_addr, i));
+ }
+
+ Log2(("RTLdrElf: iSymSh=%u cSyms=%u iStrSh=%u cbStr=%u rc=%Rrc cbImage=%#zx LinkAddress=" FMT_ELF_ADDR "\n",
+ pModElf->iSymSh, pModElf->cSyms, pModElf->iStrSh, pModElf->cbStr, rc,
+ pModElf->cbImage, pModElf->LinkAddress));
if (RT_SUCCESS(rc))
{
pModElf->Core.pOps = &RTLDRELF_MID(s_rtldrElf,Ops);
diff --git a/src/VBox/Runtime/common/ldr/ldrEx.cpp b/src/VBox/Runtime/common/ldr/ldrEx.cpp
index 8bc6b9bd..ba73910d 100644
--- a/src/VBox/Runtime/common/ldr/ldrEx.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrEx.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * 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;
@@ -165,15 +165,6 @@ int rtldrOpenWithReader(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch
}
-/**
- * Gets the size of the loaded image.
- * This is only supported for modules which has been opened using RTLdrOpen() and RTLdrOpenBits().
- *
- * @returns image size (in bytes).
- * @returns ~(size_t)0 on if not opened by RTLdrOpen().
- * @param hLdrMod Handle to the loader module.
- * @remark Not supported for RTLdrLoad() images.
- */
RTDECL(size_t) RTLdrSize(RTLDRMOD hLdrMod)
{
LogFlow(("RTLdrSize: hLdrMod=%RTldrm\n", hLdrMod));
@@ -547,3 +538,34 @@ RTDECL(int) RTLdrRvaToSegOffset(RTLDRMOD hLdrMod, RTLDRADDR Rva, uint32_t *piSeg
}
RT_EXPORT_SYMBOL(RTLdrRvaToSegOffset);
+
+/**
+ * Internal method used by the IPRT debug bits.
+ *
+ * @returns IPRT status code.
+ * @param hLdrMod The loader handle which executable we wish to
+ * read from.
+ * @param pvBuf The output buffer.
+ * @param iDbgInfo The debug info ordinal number if the request
+ * corresponds exactly to a debug info part from
+ * pfnEnumDbgInfo. Otherwise, pass UINT32_MAX.
+ * @param off Where in the executable file to start reading.
+ * @param cb The number of bytes to read.
+ *
+ * @remarks Fixups will only be applied if @a iDbgInfo is specified.
+ */
+DECLHIDDEN(int) rtLdrReadAt(RTLDRMOD hLdrMod, void *pvBuf, uint32_t iDbgInfo, RTFOFF off, size_t cb)
+{
+ AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), VERR_INVALID_HANDLE);
+ PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
+
+ if (iDbgInfo != UINT32_MAX)
+ {
+ AssertReturn(pMod->pOps->pfnReadDbgInfo, VERR_NOT_SUPPORTED);
+ return pMod->pOps->pfnReadDbgInfo(pMod, iDbgInfo, off, cb, pvBuf);
+ }
+
+ AssertReturn(pMod->pReader, VERR_NOT_SUPPORTED);
+ return pMod->pReader->pfnRead(pMod->pReader, pvBuf, cb, off);
+}
+
diff --git a/src/VBox/Runtime/common/ldr/ldrFile.cpp b/src/VBox/Runtime/common/ldr/ldrFile.cpp
index 65f408d4..e10fe702 100644
--- a/src/VBox/Runtime/common/ldr/ldrFile.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrFile.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * 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;
@@ -253,7 +253,7 @@ RTDECL(int) RTLdrOpen(const char *pszFilename, uint32_t fFlags, RTLDRARCH enmArc
{
LogFlow(("RTLdrOpen: pszFilename=%p:{%s} fFlags=%#x enmArch=%d phLdrMod=%p\n",
pszFilename, pszFilename, fFlags, enmArch, phLdrMod));
- AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
+ AssertMsgReturn(!(fFlags & ~RTLDR_O_VALID_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
AssertMsgReturn(enmArch > RTLDRARCH_INVALID && enmArch < RTLDRARCH_END, ("%d\n", enmArch), VERR_INVALID_PARAMETER);
/*
@@ -305,6 +305,7 @@ RTDECL(int) RTLdrOpenkLdr(const char *pszFilename, uint32_t fFlags, RTLDRARCH en
#ifdef LDR_WITH_KLDR
LogFlow(("RTLdrOpenkLdr: pszFilename=%p:{%s} fFlags=%#x enmArch=%d phLdrMod=%p\n",
pszFilename, pszFilename, fFlags, enmArch, phLdrMod));
+ AssertMsgReturn(!(fFlags & ~RTLDR_O_VALID_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
/*
* Resolve RTLDRARCH_HOST.
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);
+
diff --git a/src/VBox/Runtime/common/ldr/ldrNative.cpp b/src/VBox/Runtime/common/ldr/ldrNative.cpp
index ad94d1cf..38fe571f 100644
--- a/src/VBox/Runtime/common/ldr/ldrNative.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrNative.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * 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;
@@ -62,7 +62,7 @@ static DECLCALLBACK(int) rtldrNativeDone(PRTLDRMODINTERNAL pMod)
/**
* Operations for a native module.
*/
-static const RTLDROPS s_rtldrNativeOps =
+static const RTLDROPS g_rtldrNativeOps =
{
"native",
rtldrNativeClose,
@@ -80,6 +80,7 @@ static const RTLDROPS s_rtldrNativeOps =
NULL,
NULL,
NULL,
+ NULL,
42
};
@@ -127,10 +128,26 @@ RTDECL(int) RTLdrLoadEx(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fF
PRTLDRMODNATIVE pMod = (PRTLDRMODNATIVE)RTMemAlloc(sizeof(*pMod));
if (pMod)
{
- pMod->Core.u32Magic = RTLDRMOD_MAGIC;
- pMod->Core.eState = LDR_STATE_LOADED;
- pMod->Core.pOps = &s_rtldrNativeOps;
- pMod->hNative = ~(uintptr_t)0;
+ pMod->Core.u32Magic = RTLDRMOD_MAGIC;
+ pMod->Core.eState = LDR_STATE_LOADED;
+ pMod->Core.pOps = &g_rtldrNativeOps;
+ pMod->Core.pReader = NULL;
+ pMod->Core.enmFormat = RTLDRFMT_NATIVE;
+ pMod->Core.enmType = RTLDRTYPE_SHARED_LIBRARY_RELOCATABLE; /* approx */
+#ifdef RT_BIG_ENDIAN
+ pMod->Core.enmEndian = RTLDRENDIAN_BIG;
+#else
+ pMod->Core.enmEndian = RTLDRENDIAN_LITTLE;
+#endif
+#ifdef RT_ARCH_AMD64
+ pMod->Core.enmArch = RTLDRARCH_AMD64;
+#elif defined(RT_ARCH_X86)
+ pMod->Core.enmArch = RTLDRARCH_X86_32;
+#else
+ pMod->Core.enmArch = RTLDRARCH_HOST;
+#endif
+ pMod->hNative = ~(uintptr_t)0;
+ pMod->fFlags = fFlags;
/*
* Attempt to open the module.
@@ -154,6 +171,54 @@ RTDECL(int) RTLdrLoadEx(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fF
RT_EXPORT_SYMBOL(RTLdrLoadEx);
+RTDECL(int) RTLdrLoadSystem(const char *pszFilename, bool fNoUnload, PRTLDRMOD phLdrMod)
+{
+ LogFlow(("RTLdrLoadSystem: pszFilename=%p:{%s} fNoUnload=%RTbool phLdrMod=%p\n",
+ pszFilename, pszFilename, fNoUnload, phLdrMod));
+
+ /*
+ * Validate input.
+ */
+ AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
+ *phLdrMod = NIL_RTLDRMOD;
+ AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(!RTPathHavePath(pszFilename), ("%s\n", pszFilename), VERR_INVALID_PARAMETER);
+
+ /*
+ * Check the filename.
+ */
+ size_t cchFilename = strlen(pszFilename);
+ AssertMsgReturn(cchFilename < (RTPATH_MAX / 4) * 3, ("%zu\n", cchFilename), VERR_INVALID_PARAMETER);
+
+ const char *pszExt = "";
+ if (!RTPathHaveExt(pszFilename))
+ pszExt = RTLdrGetSuff();
+
+ /*
+ * Let the platform specific code do the rest.
+ */
+ int rc = rtldrNativeLoadSystem(pszFilename, pszExt, fNoUnload ? RTLDRLOAD_FLAGS_NO_UNLOAD : 0, phLdrMod);
+ LogFlow(("RTLdrLoadSystem: returns %Rrc\n", rc));
+ return rc;
+}
+
+
+RTDECL(void *) RTLdrGetSystemSymbol(const char *pszFilename, const char *pszSymbol)
+{
+ void *pvRet = NULL;
+ RTLDRMOD hLdrMod;
+ int rc = RTLdrLoadSystem(pszFilename, true /*fNoUnload*/, &hLdrMod);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTLdrGetSymbol(hLdrMod, pszSymbol, &pvRet);
+ if (RT_FAILURE(rc))
+ pvRet = NULL; /* paranoia */
+ RTLdrClose(hLdrMod);
+ }
+ return pvRet;
+}
+
+
/**
* Loads a dynamic load library (/shared object) image file residing in the
* RTPathAppPrivateArch() directory.
@@ -241,3 +306,14 @@ RTDECL(const char *) RTLdrGetSuff(void)
}
RT_EXPORT_SYMBOL(RTLdrGetSuff);
+
+RTDECL(uintptr_t) RTLdrGetNativeHandle(RTLDRMOD hLdrMod)
+{
+ PRTLDRMODNATIVE pThis = (PRTLDRMODNATIVE)hLdrMod;
+ AssertPtrReturn(pThis, ~(uintptr_t)0);
+ AssertReturn(pThis->Core.u32Magic == RTLDRMOD_MAGIC, ~(uintptr_t)0);
+ AssertReturn(pThis->Core.pOps == &g_rtldrNativeOps, ~(uintptr_t)0);
+ return pThis->hNative;
+}
+RT_EXPORT_SYMBOL(RTLdrGetNativeHandle);
+
diff --git a/src/VBox/Runtime/common/ldr/ldrPE.cpp b/src/VBox/Runtime/common/ldr/ldrPE.cpp
index 259f8e93..283b861c 100644
--- a/src/VBox/Runtime/common/ldr/ldrPE.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrPE.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -35,8 +35,10 @@
#include <iprt/alloc.h>
#include <iprt/assert.h>
#include <iprt/log.h>
+#include <iprt/path.h>
#include <iprt/string.h>
#include <iprt/err.h>
+#include <iprt/formats/codeview.h>
#include "internal/ldrPE.h"
#include "internal/ldr.h"
@@ -62,13 +64,13 @@ typedef struct RTLDRMODPE
{
/** Core module structure. */
RTLDRMODINTERNAL Core;
- /** Pointer to the reader instance. */
- PRTLDRREADER pReader;
/** Pointer to internal copy of image bits.
* @todo the reader should take care of this. */
void *pvBits;
/** The offset of the NT headers. */
RTFOFF offNtHdrs;
+ /** The offset of the first byte after the section table. */
+ RTFOFF offEndOfHdrs;
/** The machine type (IMAGE_FILE_HEADER::Machine). */
uint16_t u16Machine;
@@ -87,12 +89,16 @@ typedef struct RTLDRMODPE
uint32_t cbImage;
/** Size of the header (IMAGE_OPTIONAL_HEADER32::SizeOfHeaders). */
uint32_t cbHeaders;
+ /** The image timestamp. */
+ uint32_t uTimestamp;
/** The import data directory entry. */
IMAGE_DATA_DIRECTORY ImportDir;
/** The base relocation data directory entry. */
IMAGE_DATA_DIRECTORY RelocDir;
/** The export data directory entry. */
IMAGE_DATA_DIRECTORY ExportDir;
+ /** The debug directory entry. */
+ IMAGE_DATA_DIRECTORY DebugDir;
} RTLDRMODPE, *PRTLDRMODPE;
/**
@@ -130,7 +136,227 @@ typedef struct RTLDROPSPE
*******************************************************************************/
static void rtldrPEConvert32BitOptionalHeaderTo64Bit(PIMAGE_OPTIONAL_HEADER64 pOptHdr);
static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg);
-static int rtldrPEApplyFixups(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, RTUINTPTR BaseAddress, RTUINTPTR OldBaseAddress);
+static int rtldrPEApplyFixups(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, RTUINTPTR BaseAddress, RTUINTPTR OldBaseAddress);
+
+
+
+/**
+ * Reads a section of a PE image given by RVA + size, using mapped bits if
+ * available or allocating heap memory and reading from the file.
+ *
+ * @returns IPRT status code.
+ * @param pThis Pointer to the PE loader module structure.
+ * @param pvBits Read only bits if available. NULL if not.
+ * @param uRva The RVA to read at.
+ * @param cbMem The number of bytes to read.
+ * @param ppvMem Where to return the memory on success (heap or
+ * inside pvBits).
+ */
+static int rtldrPEReadPartByRva(PRTLDRMODPE pThis, const void *pvBits, uint32_t uRva, uint32_t cbMem, void const **ppvMem)
+{
+ *ppvMem = NULL;
+ if (!cbMem)
+ return VINF_SUCCESS;
+
+ /*
+ * Use bits if we've got some.
+ */
+ if (pvBits)
+ {
+ *ppvMem = (uint8_t const *)pvBits + uRva;
+ return VINF_SUCCESS;
+ }
+ if (pThis->pvBits)
+ {
+ *ppvMem = (uint8_t const *)pThis->pvBits + uRva;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Allocate a buffer and read the bits from the file (or whatever).
+ */
+ if (!pThis->Core.pReader)
+ return VERR_ACCESS_DENIED;
+
+ uint8_t *pbMem = (uint8_t *)RTMemAllocZ(cbMem);
+ if (!pbMem)
+ return VERR_NO_MEMORY;
+ *ppvMem = pbMem;
+
+ /* Do the reading on a per section base. */
+ RTFOFF const cbFile = pThis->Core.pReader->pfnSize(pThis->Core.pReader);
+ for (;;)
+ {
+ /* Translate the RVA into a file offset. */
+ uint32_t offFile = uRva;
+ uint32_t cbToRead = cbMem;
+ uint32_t cbToAdv = cbMem;
+
+ if (uRva < pThis->paSections[0].VirtualAddress)
+ {
+ /* Special header section. */
+ cbToRead = pThis->paSections[0].VirtualAddress - uRva;
+ if (cbToRead > cbMem)
+ cbToRead = cbMem;
+ cbToAdv = cbToRead;
+
+ /* The following capping is an approximation. */
+ uint32_t offFirstRawData = RT_ALIGN(pThis->cbHeaders, _4K);
+ if ( pThis->paSections[0].PointerToRawData > 0
+ && pThis->paSections[0].SizeOfRawData > 0)
+ offFirstRawData = pThis->paSections[0].PointerToRawData;
+ if (offFile > offFirstRawData)
+ cbToRead = 0;
+ else if (offFile + cbToRead > offFirstRawData)
+ cbToRead = offFile + cbToRead - offFirstRawData;
+ }
+ else
+ {
+ /* Find the matching section and its mapping size. */
+ uint32_t j = 0;
+ uint32_t cbMapping = 0;
+ while (j < pThis->cSections)
+ {
+ cbMapping = (j + 1 < pThis->cSections ? pThis->paSections[j + 1].VirtualAddress : pThis->cbImage)
+ - pThis->paSections[j].VirtualAddress;
+ if (uRva - pThis->paSections[j].VirtualAddress < cbMapping)
+ break;
+ j++;
+ }
+ if (j >= cbMapping)
+ break; /* This shouldn't happen, just return zeros if it does. */
+
+ /* Adjust the sizes and calc the file offset. */
+ if (cbToAdv > cbMapping)
+ cbToAdv = cbToRead = cbMapping;
+ if ( pThis->paSections[j].PointerToRawData > 0
+ && pThis->paSections[j].SizeOfRawData > 0)
+ {
+ offFile = uRva - pThis->paSections[j].VirtualAddress;
+ if (offFile + cbToRead > pThis->paSections[j].SizeOfRawData)
+ cbToRead = pThis->paSections[j].SizeOfRawData - offFile;
+ offFile += pThis->paSections[j].PointerToRawData;
+ }
+ else
+ {
+ offFile = UINT32_MAX;
+ cbToRead = 0;
+ }
+ }
+
+ /* Perform the read after adjusting a little (paranoia). */
+ if (offFile > cbFile)
+ cbToRead = 0;
+ if (cbToRead)
+ {
+ if ((RTFOFF)offFile + cbToRead > cbFile)
+ cbToRead = cbFile - (RTFOFF)offFile;
+ int rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbMem, cbToRead, offFile);
+ if (RT_FAILURE(rc))
+ {
+ RTMemFree((void *)*ppvMem);
+ *ppvMem = NULL;
+ return rc;
+ }
+ }
+
+ /* Advance */
+ if (cbMem == cbToRead)
+ break;
+ cbMem -= cbToRead;
+ pbMem += cbToRead;
+ uRva += cbToRead;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Reads a part of a PE file from the file and into a heap block.
+ *
+ * @returns IRPT status code.
+ * @param pThis Pointer to the PE loader module structure..
+ * @param offFile The file offset.
+ * @param cbMem The number of bytes to read.
+ * @param ppvMem Where to return the heap block with the bytes on
+ * success.
+ */
+static int rtldrPEReadPartFromFile(PRTLDRMODPE pThis, uint32_t offFile, uint32_t cbMem, void const **ppvMem)
+{
+ *ppvMem = NULL;
+ if (!cbMem)
+ return VINF_SUCCESS;
+
+ /*
+ * Allocate a buffer and read the bits from the file (or whatever).
+ */
+ if (!pThis->Core.pReader)
+ return VERR_ACCESS_DENIED;
+
+ uint8_t *pbMem = (uint8_t *)RTMemAlloc(cbMem);
+ if (!pbMem)
+ return VERR_NO_MEMORY;
+
+ int rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbMem, cbMem, offFile);
+ if (RT_FAILURE(rc))
+ {
+ RTMemFree((void *)*ppvMem);
+ return rc;
+ }
+
+ *ppvMem = pbMem;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Reads a part of a PE image into memory one way or another.
+ *
+ * Either the RVA or the offFile must be valid. We'll prefer the RVA if
+ * possible.
+ *
+ * @returns IPRT status code.
+ * @param pThis Pointer to the PE loader module structure.
+ * @param pvBits Read only bits if available. NULL if not.
+ * @param uRva The RVA to read at.
+ * @param offFile The file offset.
+ * @param cbMem The number of bytes to read.
+ * @param ppvMem Where to return the memory on success (heap or
+ * inside pvBits).
+ */
+static int rtldrPEReadPart(PRTLDRMODPE pThis, const void *pvBits, RTFOFF offFile, RTLDRADDR uRva,
+ uint32_t cbMem, void const **ppvMem)
+{
+ if (uRva == NIL_RTLDRADDR || uRva > pThis->cbImage)
+ {
+ if (offFile < 0)
+ return VERR_INVALID_PARAMETER;
+ return rtldrPEReadPartFromFile(pThis, offFile, cbMem, ppvMem);
+ }
+ return rtldrPEReadPartByRva(pThis, pvBits, uRva, cbMem, ppvMem);
+}
+
+
+/**
+ * Frees up memory returned by rtldrPEReadPart*.
+ *
+ * @param pThis Pointer to the PE loader module structure..
+ * @param pvBits Read only bits if available. NULL if not..
+ * @param pvMem The memory we were given by the reader method.
+ */
+static void rtldrPEFreePart(PRTLDRMODPE pThis, const void *pvBits, void const *pvMem)
+{
+ if (!pvMem)
+ return;
+
+ if (pvBits && (uintptr_t)pvBits - (uintptr_t)pvMem < pThis->cbImage)
+ return;
+ if (pThis->pvBits && (uintptr_t)pThis->pvBits - (uintptr_t)pvMem < pThis->cbImage)
+ return;
+
+ RTMemFree((void *)pvMem);
+}
/** @copydoc RTLDROPS::pfnGetImageSize */
@@ -153,7 +379,7 @@ static int rtldrPEGetBitsNoImportsNorFixups(PRTLDRMODPE pModPe, void *pvBits)
/*
* Both these checks are related to pfnDone().
*/
- PRTLDRREADER pReader = pModPe->pReader;
+ PRTLDRREADER pReader = pModPe->Core.pReader;
if (!pReader)
{
AssertMsgFailed(("You've called done!\n"));
@@ -666,6 +892,140 @@ static DECLCALLBACK(int) rtldrPEGetSymbolEx(PRTLDRMODINTERNAL pMod, const void *
}
+/**
+ * Slow version of rtldrPEEnumSymbols that'll work without all of the image
+ * being accessible.
+ *
+ * This is mainly for use in debuggers and similar.
+ */
+static int rtldrPEEnumSymbolsSlow(PRTLDRMODPE pThis, unsigned fFlags, RTUINTPTR BaseAddress,
+ PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
+{
+ /*
+ * We enumerates by ordinal, which means using a slow linear search for
+ * getting any name
+ */
+ PCIMAGE_EXPORT_DIRECTORY pExpDir = NULL;
+ int rc = rtldrPEReadPartByRva(pThis, NULL, pThis->ExportDir.VirtualAddress, pThis->ExportDir.Size,
+ (void const **)&pExpDir);
+ if (RT_FAILURE(rc))
+ return rc;
+ uint32_t const cOrdinals = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
+
+ uint32_t const *paAddress = NULL;
+ rc = rtldrPEReadPartByRva(pThis, NULL, pExpDir->AddressOfFunctions, cOrdinals * sizeof(uint32_t),
+ (void const **)&paAddress);
+ uint32_t const *paRVANames = NULL;
+ if (RT_SUCCESS(rc) && pExpDir->NumberOfNames)
+ rc = rtldrPEReadPartByRva(pThis, NULL, pExpDir->AddressOfNames, pExpDir->NumberOfNames * sizeof(uint32_t),
+ (void const **)&paRVANames);
+ uint16_t const *paOrdinals = NULL;
+ if (RT_SUCCESS(rc) && pExpDir->NumberOfNames)
+ rc = rtldrPEReadPartByRva(pThis, NULL, pExpDir->AddressOfNameOrdinals, pExpDir->NumberOfNames * sizeof(uint16_t),
+ (void const **)&paOrdinals);
+ if (RT_SUCCESS(rc))
+ {
+ uintptr_t uNamePrev = 0;
+ for (uint32_t uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++)
+ {
+ if (paAddress[uOrdinal] /* needed? */)
+ {
+ /*
+ * Look for name.
+ */
+ uint32_t uRvaName = UINT32_MAX;
+ /* Search from previous + 1 to the end. */
+ unsigned uName = uNamePrev + 1;
+ while (uName < pExpDir->NumberOfNames)
+ {
+ if (paOrdinals[uName] == uOrdinal)
+ {
+ uRvaName = paRVANames[uName];
+ uNamePrev = uName;
+ break;
+ }
+ uName++;
+ }
+ if (uRvaName == UINT32_MAX)
+ {
+ /* Search from start to the previous. */
+ uName = 0;
+ for (uName = 0 ; uName <= uNamePrev; uName++)
+ {
+ if (paOrdinals[uName] == uOrdinal)
+ {
+ uRvaName = paRVANames[uName];
+ uNamePrev = uName;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Get address.
+ */
+ uintptr_t uRVAExport = paAddress[uOrdinal];
+ RTUINTPTR Value;
+ if ( uRVAExport - (uintptr_t)pThis->ExportDir.VirtualAddress
+ < pThis->ExportDir.Size)
+ {
+ if (!(fFlags & RTLDR_ENUM_SYMBOL_FLAGS_NO_FWD))
+ {
+ /* Resolve forwarder. */
+ AssertMsgFailed(("Forwarders are not supported!\n"));
+ }
+ continue;
+ }
+
+ /* Get plain export address */
+ Value = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
+
+ /* Read in the name if found one. */
+ char szAltName[32];
+ const char *pszName = NULL;
+ if (uRvaName != UINT32_MAX)
+ {
+ uint32_t cbName = 0x1000 - (uRvaName & 0xfff);
+ if (cbName < 10 || cbName > 512)
+ cbName = 128;
+ rc = rtldrPEReadPartByRva(pThis, NULL, uRvaName, cbName, (void const **)&pszName);
+ while (RT_SUCCESS(rc) && RTStrNLen(pszName, cbName) == cbName)
+ {
+ rtldrPEFreePart(pThis, NULL, pszName);
+ pszName = NULL;
+ if (cbName >= _4K)
+ break;
+ cbName += 128;
+ rc = rtldrPEReadPartByRva(pThis, NULL, uRvaName, cbName, (void const **)&pszName);
+ }
+ }
+ if (!pszName)
+ {
+ RTStrPrintf(szAltName, sizeof(szAltName), "Ordinal%#x", uOrdinal);
+ pszName = szAltName;
+ }
+
+ /*
+ * Call back.
+ */
+ rc = pfnCallback(&pThis->Core, pszName, uOrdinal + pExpDir->Base, Value, pvUser);
+ if (pszName != szAltName && pszName)
+ rtldrPEFreePart(pThis, NULL, pszName);
+ if (rc)
+ break;
+ }
+ }
+ }
+
+ rtldrPEFreePart(pThis, NULL, paOrdinals);
+ rtldrPEFreePart(pThis, NULL, paRVANames);
+ rtldrPEFreePart(pThis, NULL, paAddress);
+ rtldrPEFreePart(pThis, NULL, pExpDir);
+ return rc;
+
+}
+
+
/** @copydoc RTLDROPS::pfnEnumSymbols */
static DECLCALLBACK(int) rtldrPEEnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFlags, const void *pvBits, RTUINTPTR BaseAddress,
PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
@@ -689,7 +1049,7 @@ static DECLCALLBACK(int) rtldrPEEnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFl
{
int rc = rtldrPEReadBits(pModPe);
if (RT_FAILURE(rc))
- return rc;
+ return rtldrPEEnumSymbolsSlow(pModPe, fFlags, BaseAddress, pfnCallback, pvUser);
}
pvBits = pModPe->pvBits;
}
@@ -744,16 +1104,19 @@ static DECLCALLBACK(int) rtldrPEEnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFl
*/
uintptr_t uRVAExport = paAddress[uOrdinal];
RTUINTPTR Value;
- if ( uRVAExport - (uintptr_t)pModPe->ExportDir.VirtualAddress
- < pModPe->ExportDir.Size)
+ if ( uRVAExport - (uintptr_t)pModPe->ExportDir.VirtualAddress
+ < pModPe->ExportDir.Size)
{
- /* Resolve forwarder. */
- AssertMsgFailed(("Forwarders are not supported!\n"));
+ if (!(fFlags & RTLDR_ENUM_SYMBOL_FLAGS_NO_FWD))
+ {
+ /* Resolve forwarder. */
+ AssertMsgFailed(("Forwarders are not supported!\n"));
+ }
continue;
}
- else
- /* Get plain export address */
- Value = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
+
+ /* Get plain export address */
+ Value = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
/*
* Call back.
@@ -772,16 +1135,271 @@ static DECLCALLBACK(int) rtldrPEEnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFl
static DECLCALLBACK(int) rtldrPE_EnumDbgInfo(PRTLDRMODINTERNAL pMod, const void *pvBits,
PFNRTLDRENUMDBG pfnCallback, void *pvUser)
{
- NOREF(pMod); NOREF(pvBits); NOREF(pfnCallback); NOREF(pvUser);
- return VINF_NOT_SUPPORTED;
+ PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
+ int rc;
+
+ /*
+ * Debug info directory empty?
+ */
+ if ( !pModPe->DebugDir.VirtualAddress
+ || !pModPe->DebugDir.Size)
+ return VINF_SUCCESS;
+
+ /*
+ * Get the debug directory.
+ */
+ if (!pvBits)
+ pvBits = pModPe->pvBits;
+
+ PCIMAGE_DEBUG_DIRECTORY paDbgDir;
+ int rcRet = rtldrPEReadPartByRva(pModPe, pvBits, pModPe->DebugDir.VirtualAddress, pModPe->DebugDir.Size,
+ (void const **)&paDbgDir);
+ if (RT_FAILURE(rcRet))
+ return rcRet;
+
+ /*
+ * Enumerate the debug directory.
+ */
+ uint32_t const cEntries = pModPe->DebugDir.Size / sizeof(paDbgDir[0]);
+ for (uint32_t i = 0; i < cEntries; i++)
+ {
+ if (paDbgDir[i].PointerToRawData < pModPe->offEndOfHdrs)
+ continue;
+ if (paDbgDir[i].SizeOfData < 4)
+ continue;
+
+ void const *pvPart = NULL;
+ char szPath[RTPATH_MAX];
+ RTLDRDBGINFO DbgInfo;
+ RT_ZERO(DbgInfo.u);
+ DbgInfo.iDbgInfo = i;
+ DbgInfo.offFile = paDbgDir[i].PointerToRawData;
+ DbgInfo.LinkAddress = paDbgDir[i].AddressOfRawData < pModPe->cbImage
+ && paDbgDir[i].AddressOfRawData >= pModPe->offEndOfHdrs
+ ? paDbgDir[i].AddressOfRawData : NIL_RTLDRADDR;
+ DbgInfo.cb = paDbgDir[i].SizeOfData;
+ DbgInfo.pszExtFile = NULL;
+
+ rc = VINF_SUCCESS;
+ switch (paDbgDir[i].Type)
+ {
+ case IMAGE_DEBUG_TYPE_CODEVIEW:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW;
+ DbgInfo.u.Cv.cbImage = pModPe->cbImage;
+ DbgInfo.u.Cv.uMajorVer = paDbgDir[i].MajorVersion;
+ DbgInfo.u.Cv.uMinorVer = paDbgDir[i].MinorVersion;
+ DbgInfo.u.Cv.uTimestamp = paDbgDir[i].TimeDateStamp;
+ if ( paDbgDir[i].SizeOfData < sizeof(szPath)
+ && paDbgDir[i].SizeOfData > 16
+ && ( DbgInfo.LinkAddress != NIL_RTLDRADDR
+ || DbgInfo.offFile > 0)
+ )
+ {
+ rc = rtldrPEReadPart(pModPe, pvBits, DbgInfo.offFile, DbgInfo.LinkAddress, paDbgDir[i].SizeOfData, &pvPart);
+ if (RT_SUCCESS(rc))
+ {
+ PCCVPDB20INFO pCv20 = (PCCVPDB20INFO)pvPart;
+ if ( pCv20->u32Magic == CVPDB20INFO_MAGIC
+ && pCv20->offDbgInfo == 0
+ && paDbgDir[i].SizeOfData > RT_UOFFSETOF(CVPDB20INFO, szPdbFilename) )
+ {
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_PDB20;
+ DbgInfo.u.Pdb20.cbImage = pModPe->cbImage;
+ DbgInfo.u.Pdb20.uTimestamp = pCv20->uTimestamp;
+ DbgInfo.u.Pdb20.uAge = pCv20->uAge;
+ DbgInfo.pszExtFile = (const char *)&pCv20->szPdbFilename[0];
+ }
+ else if ( pCv20->u32Magic == CVPDB70INFO_MAGIC
+ && paDbgDir[i].SizeOfData > RT_UOFFSETOF(CVPDB70INFO, szPdbFilename) )
+ {
+ PCCVPDB70INFO pCv70 = (PCCVPDB70INFO)pCv20;
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_PDB70;
+ DbgInfo.u.Pdb70.cbImage = pModPe->cbImage;
+ DbgInfo.u.Pdb70.Uuid = pCv70->PdbUuid;
+ DbgInfo.u.Pdb70.uAge = pCv70->uAge;
+ DbgInfo.pszExtFile = (const char *)&pCv70->szPdbFilename[0];
+ }
+ }
+ else
+ rcRet = rc;
+ }
+ break;
+
+ case IMAGE_DEBUG_TYPE_MISC:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
+ if ( paDbgDir[i].SizeOfData < sizeof(szPath)
+ && paDbgDir[i].SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data))
+ {
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_DBG;
+ DbgInfo.u.Dbg.cbImage = pModPe->cbImage;
+ if (DbgInfo.LinkAddress != NIL_RTLDRADDR)
+ DbgInfo.u.Dbg.uTimestamp = paDbgDir[i].TimeDateStamp;
+ else
+ DbgInfo.u.Dbg.uTimestamp = pModPe->uTimestamp; /* NT4 SP1 ntfs.sys hack. Generic? */
+
+ rc = rtldrPEReadPart(pModPe, pvBits, DbgInfo.offFile, DbgInfo.LinkAddress, paDbgDir[i].SizeOfData, &pvPart);
+ if (RT_SUCCESS(rc))
+ {
+ PCIMAGE_DEBUG_MISC pMisc = (PCIMAGE_DEBUG_MISC)pvPart;
+ if ( pMisc->DataType == IMAGE_DEBUG_MISC_EXENAME
+ && pMisc->Length == paDbgDir[i].SizeOfData)
+ {
+ if (!pMisc->Unicode)
+ DbgInfo.pszExtFile = (const char *)&pMisc->Data[0];
+ else
+ {
+ char *pszPath = szPath;
+ rc = RTUtf16ToUtf8Ex((PCRTUTF16)&pMisc->Data[0],
+ (pMisc->Length - RT_OFFSETOF(IMAGE_DEBUG_MISC, Data)) / sizeof(RTUTF16),
+ &pszPath, sizeof(szPath), NULL);
+ if (RT_SUCCESS(rc))
+ DbgInfo.pszExtFile = szPath;
+ else
+ rcRet = rc; /* continue without a filename. */
+ }
+ }
+ }
+ else
+ rcRet = rc; /* continue without a filename. */
+ }
+ break;
+
+ case IMAGE_DEBUG_TYPE_COFF:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_COFF;
+ DbgInfo.u.Coff.cbImage = pModPe->cbImage;
+ DbgInfo.u.Coff.uMajorVer = paDbgDir[i].MajorVersion;
+ DbgInfo.u.Coff.uMinorVer = paDbgDir[i].MinorVersion;
+ DbgInfo.u.Coff.uTimestamp = paDbgDir[i].TimeDateStamp;
+ break;
+
+ default:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
+ break;
+ }
+
+ /* Fix (hack) the file name encoding. We don't have Windows-1252 handy,
+ so we'll be using Latin-1 as a reasonable approximation.
+ (I don't think we know exactly which encoding this is anyway, as
+ it's probably the current ANSI/Windows code page for the process
+ generating the image anyways.) */
+ if (DbgInfo.pszExtFile && DbgInfo.pszExtFile != szPath)
+ {
+ char *pszPath = szPath;
+ rc = RTLatin1ToUtf8Ex(DbgInfo.pszExtFile,
+ paDbgDir[i].SizeOfData - ((uintptr_t)DbgInfo.pszExtFile - (uintptr_t)pvBits),
+ &pszPath, sizeof(szPath), NULL);
+ if (RT_FAILURE(rc))
+ {
+ rcRet = rc;
+ DbgInfo.pszExtFile = NULL;
+ }
+ }
+ if (DbgInfo.pszExtFile)
+ RTPathChangeToUnixSlashes(szPath, true /*fForce*/);
+
+ rc = pfnCallback(pMod, &DbgInfo, pvUser);
+ rtldrPEFreePart(pModPe, pvBits, pvPart);
+ if (rc != VINF_SUCCESS)
+ {
+ rcRet = rc;
+ break;
+ }
+ }
+
+ rtldrPEFreePart(pModPe, pvBits, paDbgDir);
+ return rcRet;
}
/** @copydoc RTLDROPS::pfnEnumSegments. */
static DECLCALLBACK(int) rtldrPE_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser)
{
- NOREF(pMod); NOREF(pfnCallback); NOREF(pvUser);
- return VINF_NOT_SUPPORTED;
+ PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
+ RTLDRSEG SegInfo;
+
+ /*
+ * The first section is a fake one covering the headers.
+ */
+ SegInfo.pszName = "NtHdrs";
+ SegInfo.cchName = 6;
+ SegInfo.SelFlat = 0;
+ SegInfo.Sel16bit = 0;
+ SegInfo.fFlags = 0;
+ SegInfo.fProt = RTMEM_PROT_READ;
+ SegInfo.Alignment = 1;
+ SegInfo.LinkAddress = pModPe->uImageBase;
+ SegInfo.RVA = 0;
+ SegInfo.offFile = 0;
+ SegInfo.cb = pModPe->cbHeaders;
+ SegInfo.cbFile = pModPe->cbHeaders;
+ SegInfo.cbMapped = pModPe->cbHeaders;
+ if ((pModPe->paSections[0].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
+ SegInfo.cbMapped = pModPe->paSections[0].VirtualAddress;
+ int rc = pfnCallback(pMod, &SegInfo, pvUser);
+
+ /*
+ * Then all the normal sections.
+ */
+ PCIMAGE_SECTION_HEADER pSh = pModPe->paSections;
+ for (uint32_t i = 0; i < pModPe->cSections && rc == VINF_SUCCESS; i++, pSh++)
+ {
+ char szName[32];
+ SegInfo.pszName = (const char *)&pSh->Name[0];
+ SegInfo.cchName = (uint32_t)RTStrNLen(SegInfo.pszName, sizeof(pSh->Name));
+ if (SegInfo.cchName >= sizeof(pSh->Name))
+ {
+ memcpy(szName, &pSh->Name[0], sizeof(pSh->Name));
+ szName[sizeof(sizeof(pSh->Name))] = '\0';
+ SegInfo.pszName = szName;
+ }
+ else if (SegInfo.cchName == 0)
+ {
+ SegInfo.pszName = szName;
+ SegInfo.cchName = (uint32_t)RTStrPrintf(szName, sizeof(szName), "UnamedSect%02u", i);
+ }
+ SegInfo.SelFlat = 0;
+ SegInfo.Sel16bit = 0;
+ SegInfo.fFlags = 0;
+ SegInfo.fProt = RTMEM_PROT_NONE;
+ if (pSh->Characteristics & IMAGE_SCN_MEM_READ)
+ SegInfo.fProt |= RTMEM_PROT_READ;
+ if (pSh->Characteristics & IMAGE_SCN_MEM_WRITE)
+ SegInfo.fProt |= RTMEM_PROT_WRITE;
+ if (pSh->Characteristics & IMAGE_SCN_MEM_EXECUTE)
+ SegInfo.fProt |= RTMEM_PROT_EXEC;
+ SegInfo.Alignment = (pSh->Characteristics & IMAGE_SCN_ALIGN_MASK) >> IMAGE_SCN_ALIGN_SHIFT;
+ if (SegInfo.Alignment > 0)
+ SegInfo.Alignment = RT_BIT_64(SegInfo.Alignment - 1);
+ if (pSh->Characteristics & IMAGE_SCN_TYPE_NOLOAD)
+ {
+ SegInfo.LinkAddress = NIL_RTLDRADDR;
+ SegInfo.RVA = NIL_RTLDRADDR;
+ SegInfo.cbMapped = pSh->Misc.VirtualSize;
+ }
+ else
+ {
+ SegInfo.LinkAddress = pSh->VirtualAddress + pModPe->uImageBase ;
+ SegInfo.RVA = pSh->VirtualAddress;
+ SegInfo.cbMapped = RT_ALIGN(SegInfo.cb, SegInfo.Alignment);
+ if (i + 1 < pModPe->cSections && !(pSh[1].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
+ SegInfo.cbMapped = pSh[1].VirtualAddress - pSh->VirtualAddress;
+ }
+ SegInfo.cb = pSh->Misc.VirtualSize;
+ if (pSh->PointerToRawData == 0 || pSh->SizeOfRawData == 0)
+ {
+ SegInfo.offFile = -1;
+ SegInfo.cbFile = 0;
+ }
+ else
+ {
+ SegInfo.offFile = pSh->PointerToRawData;
+ SegInfo.cbFile = pSh->SizeOfRawData;
+ }
+
+ rc = pfnCallback(pMod, &SegInfo, pvUser);
+ }
+
+ return rc;
}
@@ -789,16 +1407,53 @@ static DECLCALLBACK(int) rtldrPE_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDREN
static DECLCALLBACK(int) rtldrPE_LinkAddressToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress,
uint32_t *piSeg, PRTLDRADDR poffSeg)
{
- NOREF(pMod); NOREF(LinkAddress); NOREF(piSeg); NOREF(poffSeg);
- return VERR_NOT_IMPLEMENTED;
+ PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
+
+ LinkAddress -= pModPe->uImageBase;
+
+ /* Special header segment. */
+ if (LinkAddress < pModPe->paSections[0].VirtualAddress)
+ {
+ *piSeg = 0;
+ *poffSeg = LinkAddress;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Search the normal sections. (Could do this in binary fashion, they're
+ * sorted, but too much bother right now.)
+ */
+ if (LinkAddress > pModPe->cbImage)
+ return VERR_LDR_INVALID_LINK_ADDRESS;
+ uint32_t i = pModPe->cSections;
+ PCIMAGE_SECTION_HEADER paShs = pModPe->paSections;
+ while (i-- > 0)
+ if (!(paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
+ {
+ uint32_t uAddr = paShs[i].VirtualAddress;
+ if (LinkAddress >= uAddr)
+ {
+ *poffSeg = LinkAddress - uAddr;
+ *piSeg = i + 1;
+ return VINF_SUCCESS;
+ }
+ }
+
+ return VERR_LDR_INVALID_LINK_ADDRESS;
}
/** @copydoc RTLDROPS::pfnLinkAddressToRva. */
static DECLCALLBACK(int) rtldrPE_LinkAddressToRva(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva)
{
- NOREF(pMod); NOREF(LinkAddress); NOREF(pRva);
- return VERR_NOT_IMPLEMENTED;
+ PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
+
+ LinkAddress -= pModPe->uImageBase;
+ if (LinkAddress > pModPe->cbImage)
+ return VERR_LDR_INVALID_LINK_ADDRESS;
+ *pRva = LinkAddress;
+
+ return VINF_SUCCESS;
}
@@ -806,8 +1461,19 @@ static DECLCALLBACK(int) rtldrPE_LinkAddressToRva(PRTLDRMODINTERNAL pMod, RTLDRA
static DECLCALLBACK(int) rtldrPE_SegOffsetToRva(PRTLDRMODINTERNAL pMod, uint32_t iSeg, RTLDRADDR offSeg,
PRTLDRADDR pRva)
{
- NOREF(pMod); NOREF(iSeg); NOREF(offSeg); NOREF(pRva);
- return VERR_NOT_IMPLEMENTED;
+ PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
+
+ if (iSeg > pModPe->cSections)
+ return VERR_LDR_INVALID_SEG_OFFSET;
+
+ /** @todo should validate offSeg here... too lazy right now. */
+ if (iSeg == 0)
+ *pRva = offSeg;
+ else if (pModPe->paSections[iSeg].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
+ return VERR_LDR_INVALID_SEG_OFFSET;
+ else
+ *pRva = offSeg + pModPe->paSections[iSeg].VirtualAddress;
+ return VINF_SUCCESS;
}
@@ -815,8 +1481,11 @@ static DECLCALLBACK(int) rtldrPE_SegOffsetToRva(PRTLDRMODINTERNAL pMod, uint32_t
static DECLCALLBACK(int) rtldrPE_RvaToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR Rva,
uint32_t *piSeg, PRTLDRADDR poffSeg)
{
- NOREF(pMod); NOREF(Rva); NOREF(piSeg); NOREF(poffSeg);
- return VERR_NOT_IMPLEMENTED;
+ PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
+ int rc = rtldrPE_LinkAddressToSegOffset(pMod, Rva + pModPe->uImageBase, piSeg, poffSeg);
+ if (RT_FAILURE(rc))
+ rc = VERR_LDR_INVALID_RVA;
+ return rc;
}
@@ -829,12 +1498,6 @@ static DECLCALLBACK(int) rtldrPEDone(PRTLDRMODINTERNAL pMod)
RTMemFree(pModPe->pvBits);
pModPe->pvBits = NULL;
}
- if (pModPe->pReader)
- {
- int rc = pModPe->pReader->pfnDestroy(pModPe->pReader);
- AssertRC(rc);
- pModPe->pReader = NULL;
- }
return VINF_SUCCESS;
}
@@ -852,12 +1515,6 @@ static DECLCALLBACK(int) rtldrPEClose(PRTLDRMODINTERNAL pMod)
RTMemFree(pModPe->pvBits);
pModPe->pvBits = NULL;
}
- if (pModPe->pReader)
- {
- int rc = pModPe->pReader->pfnDestroy(pModPe->pReader);
- AssertRC(rc);
- pModPe->pReader = NULL;
- }
return VINF_SUCCESS;
}
@@ -884,6 +1541,7 @@ static const RTLDROPSPE s_rtldrPE32Ops =
rtldrPE_LinkAddressToRva,
rtldrPE_SegOffsetToRva,
rtldrPE_RvaToSegOffset,
+ NULL,
42
},
rtldrPEResolveImports32,
@@ -913,6 +1571,7 @@ static const RTLDROPSPE s_rtldrPE64Ops =
rtldrPE_LinkAddressToRva,
rtldrPE_SegOffsetToRva,
rtldrPE_RvaToSegOffset,
+ NULL,
42
},
rtldrPEResolveImports64,
@@ -1004,10 +1663,11 @@ static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64
*
* @returns iprt status code.
* @param pFileHdr Pointer to the file header that needs validating.
+ * @param fFlags Valid RTLDR_O_XXX combination.
* @param pszLogName The log name to prefix the errors with.
* @param penmArch Where to store the CPU architecture.
*/
-int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, const char *pszLogName, PRTLDRARCH penmArch)
+static int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, uint32_t fFlags, const char *pszLogName, PRTLDRARCH penmArch)
{
size_t cbOptionalHeader;
switch (pFileHdr->Machine)
@@ -1034,7 +1694,8 @@ int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, const char *pszLogNam
return VERR_BAD_EXE_FORMAT;
}
/* This restriction needs to be implemented elsewhere. */
- if (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+ if ( (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+ && !(fFlags & RTLDR_O_FOR_DEBUG))
{
Log(("rtldrPEOpen: %s: IMAGE_FILE_RELOCS_STRIPPED\n", pszLogName));
return VERR_BAD_EXE_FORMAT;
@@ -1064,9 +1725,10 @@ int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, const char *pszLogNam
* @param offNtHdrs The offset of the NT headers from the start of the file.
* @param pFileHdr Pointer to the file header (valid).
* @param cbRawImage The raw image size.
+ * @param fFlags Loader flags, RTLDR_O_XXX.
*/
static int rtldrPEValidateOptionalHeader(const IMAGE_OPTIONAL_HEADER64 *pOptHdr, const char *pszLogName, RTFOFF offNtHdrs,
- const IMAGE_FILE_HEADER *pFileHdr, RTFOFF cbRawImage)
+ const IMAGE_FILE_HEADER *pFileHdr, RTFOFF cbRawImage, uint32_t fFlags)
{
const uint16_t CorrectMagic = pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC;
@@ -1193,6 +1855,12 @@ static int rtldrPEValidateOptionalHeader(const IMAGE_OPTIONAL_HEADER64 *pOptHdr,
Log(("rtldrPEOpen: %s: Security directory is misaligned: %#x\n", pszLogName, i, pDir->VirtualAddress));
return VERR_LDRPE_CERT_MALFORMED;
}
+ /* When using the in-memory reader with a debugger, we may get
+ into trouble here since we might not have access to the whole
+ physical file. So skip the tests below. Makes VBoxGuest.sys
+ load and check out just fine, for instance. */
+ if (fFlags & RTLDR_O_FOR_DEBUG)
+ continue;
break;
case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: // 8 /* (MIPS GP) */
@@ -1241,9 +1909,10 @@ static int rtldrPEValidateOptionalHeader(const IMAGE_OPTIONAL_HEADER64 *pOptHdr,
* @param pszLogName The log name to prefix the errors with.
* @param pOptHdr Pointer to the optional header (valid).
* @param cbRawImage The raw image size.
+ * @param fFlags Loader flags, RTLDR_O_XXX.
*/
-int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsigned cSections, const char *pszLogName,
- const IMAGE_OPTIONAL_HEADER64 *pOptHdr, RTFOFF cbRawImage)
+static int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsigned cSections, const char *pszLogName,
+ const IMAGE_OPTIONAL_HEADER64 *pOptHdr, RTFOFF cbRawImage, uint32_t fFlags)
{
const uint32_t cbImage = pOptHdr->SizeOfImage;
const IMAGE_SECTION_HEADER *pSH = &paSections[0];
@@ -1262,7 +1931,10 @@ int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsign
pSH->PointerToRawData, pSH->SizeOfRawData,
pSH->PointerToRelocations, pSH->NumberOfRelocations,
pSH->PointerToLinenumbers, pSH->NumberOfLinenumbers));
- if (pSH->Characteristics & (IMAGE_SCN_MEM_16BIT | IMAGE_SCN_MEM_FARDATA | IMAGE_SCN_MEM_PURGEABLE | IMAGE_SCN_MEM_PRELOAD))
+
+ AssertCompile(IMAGE_SCN_MEM_16BIT == IMAGE_SCN_MEM_PURGEABLE);
+ if ( ( pSH->Characteristics & (IMAGE_SCN_MEM_PURGEABLE | IMAGE_SCN_MEM_PRELOAD | IMAGE_SCN_MEM_FARDATA) )
+ && !(fFlags & RTLDR_O_FOR_DEBUG)) /* purgable/16-bit seen on w2ksp0 hal.dll, ignore the bunch. */
{
Log(("rtldrPEOpen: %s: Unsupported section flag(s) %#x section #%d '%.*s'!!!\n",
pszLogName, pSH->Characteristics, iSH, sizeof(pSH->Name), pSH->Name));
@@ -1344,7 +2016,7 @@ int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsign
static int rtldrPEReadRVA(PRTLDRMODPE pModPe, void *pvBuf, uint32_t cb, uint32_t RVA)
{
const IMAGE_SECTION_HEADER *pSH = pModPe->paSections;
- PRTLDRREADER pReader = pModPe->pReader;
+ PRTLDRREADER pReader = pModPe->Core.pReader;
uint32_t cbRead;
int rc;
@@ -1421,10 +2093,11 @@ static int rtldrPEReadRVA(PRTLDRMODPE pModPe, void *pvBuf, uint32_t cb, uint32_t
* @returns iprt status code.
* @param pModPe The PE module instance.
* @param pOptHdr Pointer to the optional header (valid).
+ * @param fFlags Loader flags, RTLDR_O_XXX.
*/
-int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr)
+static int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr, uint32_t fFlags)
{
- const char *pszLogName = pModPe->pReader->pfnLogName(pModPe->pReader); NOREF(pszLogName);
+ const char *pszLogName = pModPe->Core.pReader->pfnLogName(pModPe->Core.pReader); NOREF(pszLogName);
union /* combine stuff we're reading to help reduce stack usage. */
{
IMAGE_LOAD_CONFIG_DIRECTORY64 Cfg64;
@@ -1490,15 +2163,16 @@ int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64
}
/*
- * If the image is signed, take a look at the signature.
+ * If the image is signed and we're not doing this for debug purposes,
+ * take a look at the signature.
*/
Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
- if (Dir.Size)
+ if (Dir.Size && !(fFlags & RTLDR_O_FOR_DEBUG))
{
PWIN_CERTIFICATE pFirst = (PWIN_CERTIFICATE)RTMemTmpAlloc(Dir.Size);
if (!pFirst)
return VERR_NO_TMP_MEMORY;
- int rc = pModPe->pReader->pfnRead(pModPe->pReader, pFirst, Dir.Size, Dir.VirtualAddress);
+ int rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pFirst, Dir.Size, Dir.VirtualAddress);
if (RT_SUCCESS(rc))
{
uint32_t off = 0;
@@ -1556,15 +2230,13 @@ int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64
*
* @returns iprt status code.
* @param pReader The loader reader instance which will provide the raw image bits.
- * @param fFlags Reserved, MBZ.
+ * @param fFlags Loader flags, RTLDR_O_XXX.
* @param enmArch Architecture specifier.
* @param offNtHdrs The offset of the NT headers (where you find "PE\0\0").
* @param phLdrMod Where to store the handle.
*/
int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs, PRTLDRMOD phLdrMod)
{
- AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
-
/*
* Read and validate the file header.
*/
@@ -1574,7 +2246,7 @@ int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF
return rc;
RTLDRARCH enmArchImage;
const char *pszLogName = pReader->pfnLogName(pReader);
- rc = rtldrPEValidateFileHeader(&FileHdr, pszLogName, &enmArchImage);
+ rc = rtldrPEValidateFileHeader(&FileHdr, fFlags, pszLogName, &enmArchImage);
if (RT_FAILURE(rc))
return rc;
@@ -1594,7 +2266,7 @@ int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF
return rc;
if (FileHdr.SizeOfOptionalHeader != sizeof(OptHdr))
rtldrPEConvert32BitOptionalHeaderTo64Bit(&OptHdr);
- rc = rtldrPEValidateOptionalHeader(&OptHdr, pszLogName, offNtHdrs, &FileHdr, pReader->pfnSize(pReader));
+ rc = rtldrPEValidateOptionalHeader(&OptHdr, pszLogName, offNtHdrs, &FileHdr, pReader->pfnSize(pReader), fFlags);
if (RT_FAILURE(rc))
return rc;
@@ -1605,11 +2277,12 @@ int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF
PIMAGE_SECTION_HEADER paSections = (PIMAGE_SECTION_HEADER)RTMemAlloc(cbSections);
if (!paSections)
return VERR_NO_MEMORY;
- rc = pReader->pfnRead(pReader, paSections, cbSections, offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader);
+ rc = pReader->pfnRead(pReader, paSections, cbSections,
+ offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader);
if (RT_SUCCESS(rc))
{
rc = rtldrPEValidateSectionHeaders(paSections, FileHdr.NumberOfSections, pszLogName,
- &OptHdr, pReader->pfnSize(pReader));
+ &OptHdr, pReader->pfnSize(pReader), fFlags);
if (RT_SUCCESS(rc))
{
/*
@@ -1624,9 +2297,24 @@ int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF
pModPe->Core.pOps = &s_rtldrPE64Ops.Core;
else
pModPe->Core.pOps = &s_rtldrPE32Ops.Core;
- pModPe->pReader = pReader;
+ pModPe->Core.pReader = pReader;
+ pModPe->Core.enmFormat= RTLDRFMT_PE;
+ pModPe->Core.enmType = FileHdr.Characteristics & IMAGE_FILE_DLL
+ ? FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED
+ ? RTLDRTYPE_EXECUTABLE_FIXED
+ : RTLDRTYPE_EXECUTABLE_RELOCATABLE
+ : FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED
+ ? RTLDRTYPE_SHARED_LIBRARY_FIXED
+ : RTLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
+ pModPe->Core.enmEndian= RTLDRENDIAN_LITTLE;
+ pModPe->Core.enmArch = FileHdr.Machine == IMAGE_FILE_MACHINE_I386
+ ? RTLDRARCH_X86_32
+ : FileHdr.Machine == IMAGE_FILE_MACHINE_AMD64
+ ? RTLDRARCH_AMD64
+ : RTLDRARCH_WHATEVER;
pModPe->pvBits = NULL;
pModPe->offNtHdrs = offNtHdrs;
+ pModPe->offEndOfHdrs = offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader + cbSections;
pModPe->u16Machine = FileHdr.Machine;
pModPe->fFile = FileHdr.Characteristics;
pModPe->cSections = FileHdr.NumberOfSections;
@@ -1635,15 +2323,17 @@ int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF
pModPe->uImageBase = (RTUINTPTR)OptHdr.ImageBase;
pModPe->cbImage = OptHdr.SizeOfImage;
pModPe->cbHeaders = OptHdr.SizeOfHeaders;
+ pModPe->uTimestamp = FileHdr.TimeDateStamp;
pModPe->ImportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
pModPe->RelocDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
pModPe->ExportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
+ pModPe->DebugDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
/*
* Perform validation of some selected data directories which requires
* inspection of the actual data.
*/
- rc = rtldrPEValidateDirectories(pModPe, &OptHdr);
+ rc = rtldrPEValidateDirectories(pModPe, &OptHdr, fFlags);
if (RT_SUCCESS(rc))
{
*phLdrMod = &pModPe->Core;
diff --git a/src/VBox/Runtime/common/ldr/ldrkStuff.cpp b/src/VBox/Runtime/common/ldr/ldrkStuff.cpp
index 61b36663..da53c29f 100644
--- a/src/VBox/Runtime/common/ldr/ldrkStuff.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrkStuff.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * 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;
@@ -240,9 +240,10 @@ static int rtkldrRdr_Create( PPKRDR ppRdr, const char *pszFilename)
/** @copydoc KLDRRDROPS::pfnDestroy */
static int rtkldrRdr_Destroy( PKRDR pRdr)
{
- PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader;
- int rc = pReader->pfnDestroy(pReader);
- return rtkldrConvertErrorFromIPRT(rc);
+ PRTKLDRRDR pThis = (PRTKLDRRDR)pRdr;
+ pThis->pReader = NULL;
+ RTMemFree(pThis);
+ return 0;
}
@@ -598,23 +599,49 @@ static int rtkldrEnumDbgInfoWrapper(PKLDRMOD pMod, KU32 iDbgInfo, KLDRDBGINFOTYP
PRTLDRMODKLDRARGS pArgs = (PRTLDRMODKLDRARGS)pvUser;
NOREF(pMod);
- RTLDRDBGINFOTYPE enmMyType;
+ 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: enmMyType = RTLDRDBGINFOTYPE_UNKNOWN; break;
- case KLDRDBGINFOTYPE_STABS: enmMyType = RTLDRDBGINFOTYPE_STABS; break;
- case KLDRDBGINFOTYPE_DWARF: enmMyType = RTLDRDBGINFOTYPE_DWARF; break;
- case KLDRDBGINFOTYPE_CODEVIEW: enmMyType = RTLDRDBGINFOTYPE_CODEVIEW; break;
- case KLDRDBGINFOTYPE_WATCOM: enmMyType = RTLDRDBGINFOTYPE_WATCOM; break;
- case KLDRDBGINFOTYPE_HLL: enmMyType = RTLDRDBGINFOTYPE_HLL; break;
+ 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();
- enmMyType = RTLDRDBGINFOTYPE_UNKNOWN;
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
break;
}
- int rc = pArgs->u.pfnEnumDbgInfo(&pArgs->pMod->Core, iDbgInfo, enmMyType, iMajorVer, iMinorVer, pszPartNm,
- offFile, LinkAddress, cb, pszExtFile, pArgs->pvUser);
+ int rc = pArgs->u.pfnEnumDbgInfo(&pArgs->pMod->Core, &DbgInfo, pArgs->pvUser);
if (RT_FAILURE(rc))
return rc; /* don't bother converting. */
return 0;
@@ -645,13 +672,29 @@ static DECLCALLBACK(int) rtkldr_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDRENU
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;
- Seg.pchName = paSegments[iSeg].pchName;
- Seg.cchName = paSegments[iSeg].cchName;
+ 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;
@@ -784,6 +827,15 @@ static DECLCALLBACK(int) rtkldr_RvaToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR
}
+/** @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);
+}
+
+
/**
* Operations for a kLdr module.
*/
@@ -805,6 +857,7 @@ static const RTLDROPS g_rtkldrOps =
rtkldr_LinkAddressToRva,
rtkldr_SegOffsetToRva,
rtkldr_RvaToSegOffset,
+ rtkldr_ReadDbgInfo,
42
};
@@ -836,6 +889,9 @@ int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTL
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));
@@ -847,7 +903,7 @@ int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTL
/* Try open it. */
PKLDRMOD pMod;
- int krc = kLdrModOpenFromRdr(&pRdr->Core, fFlags, enmCpuArch, &pMod);
+ int krc = kLdrModOpenFromRdr(&pRdr->Core, fKFlags, enmCpuArch, &pMod);
if (!krc)
{
/* Create a module wrapper for it. */
@@ -855,9 +911,59 @@ int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTL
if (pNewMod)
{
pNewMod->Core.u32Magic = RTLDRMOD_MAGIC;
- pNewMod->Core.eState = LDR_STATE_OPENED;
- pNewMod->Core.pOps = &g_rtkldrOps;
- pNewMod->pMod = pMod;
+ 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
@@ -874,9 +980,14 @@ int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTL
#endif
return VINF_SUCCESS;
}
+
+ /* bail out */
kLdrModClose(pMod);
krc = KERR_NO_MEMORY;
}
+ else
+ RTMemFree(pRdr);
+
return rtkldrConvertError(krc);
}