summaryrefslogtreecommitdiffstats
path: root/src/lib/kStuff/kLdr/kLdrModNative.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/kStuff/kLdr/kLdrModNative.c')
-rw-r--r--src/lib/kStuff/kLdr/kLdrModNative.c1206
1 files changed, 1206 insertions, 0 deletions
diff --git a/src/lib/kStuff/kLdr/kLdrModNative.c b/src/lib/kStuff/kLdr/kLdrModNative.c
new file mode 100644
index 0000000..01ff4a6
--- /dev/null
+++ b/src/lib/kStuff/kLdr/kLdrModNative.c
@@ -0,0 +1,1206 @@
+/* $Id: kLdrModNative.c 117 2020-03-15 15:23:36Z bird $ */
+/** @file
+ * kLdr - The Module Interpreter for the Native Loaders.
+ */
+
+/*
+ * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include "kLdrInternal.h"
+
+#if K_OS == K_OS_OS2
+# define INCL_BASE
+# include <os2.h>
+
+# ifndef LIBPATHSTRICT
+# define LIBPATHSTRICT 3
+# endif
+ extern APIRET DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction);
+# define QHINF_EXEINFO 1 /* NE exeinfo. */
+# define QHINF_READRSRCTBL 2 /* Reads from the resource table. */
+# define QHINF_READFILE 3 /* Reads from the executable file. */
+# define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */
+# define QHINF_LIBPATH 5 /* Gets the entire libpath. */
+# define QHINF_FIXENTRY 6 /* NE only */
+# define QHINF_STE 7 /* NE only */
+# define QHINF_MAPSEL 8 /* NE only */
+
+#elif K_OS == K_OS_WINDOWS
+# undef IMAGE_NT_SIGNATURE
+# undef IMAGE_DOS_SIGNATURE
+# include <windows.h>
+# ifndef IMAGE_SCN_TYPE_NOLOAD
+# define IMAGE_SCN_TYPE_NOLOAD 0x00000002
+# endif
+
+/*#elif defined(__NT__)
+#include <winnt.h> */
+
+#elif K_OS == K_OS_DARWIN
+# include <dlfcn.h>
+# include <errno.h>
+
+#else
+# error "port me"
+#endif
+
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** @def KLDRMODNATIVE_STRICT
+ * Define KLDRMODNATIVE_STRICT to enabled strict checks in KLDRMODNATIVE. */
+#define KLDRMODNATIVE_STRICT 1
+
+/** @def KLDRMODNATIVE_ASSERT
+ * Assert that an expression is true when KLDR_STRICT is defined.
+ */
+#ifdef KLDRMODNATIVE_STRICT
+# define KLDRMODNATIVE_ASSERT(expr) kHlpAssert(expr)
+#else
+# define KLDRMODNATIVE_ASSERT(expr) do {} while (0)
+#endif
+
+#if K_OS == K_OS_WINDOWS
+/** @def KLDRMODNATIVE_RVA2TYPE
+ * Converts a RVA to a pointer of the specified type.
+ * @param pvBits The bits (image base).
+ * @param uRVA The image relative virtual address.
+ * @param type The type to cast to.
+ */
+# define KLDRMODNATIVE_RVA2TYPE(pvBits, uRVA, type) \
+ ( (type) ((KUPTR)(pvBits) + (uRVA)) )
+
+#endif /* PE OSes */
+
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Instance data for the module interpreter for the Native Loaders.
+ */
+typedef struct KLDRMODNATIVE
+{
+ /** Pointer to the module. (Follows the section table.) */
+ PKLDRMOD pMod;
+ /** Reserved flags. */
+ KU32 f32Reserved;
+ /** The number of imported modules.
+ * If ~(KU32)0 this hasn't been determined yet. */
+ KU32 cImportModules;
+#if K_OS == K_OS_OS2
+ /** The module handle. */
+ HMODULE hmod;
+
+#elif K_OS == K_OS_WINDOWS
+ /** The module handle. */
+ HANDLE hmod;
+ /** Pointer to the NT headers. */
+ const IMAGE_NT_HEADERS *pNtHdrs;
+ /** Pointer to the section header array. */
+ const IMAGE_SECTION_HEADER *paShdrs;
+
+#elif K_OS == K_OS_DARWIN
+ /** The dlopen() handle.*/
+ void *pvMod;
+
+#else
+# error "Port me"
+#endif
+} KLDRMODNATIVE, *PKLDRMODNATIVE;
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static KI32 kldrModNativeNumberOfImports(PKLDRMOD pMod, const void *pvBits);
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+extern KLDRMODOPS g_kLdrModNativeOps;
+
+
+
+/**
+ * Use native loader to load the file opened by pRdr.
+ *
+ * @returns 0 on success and *ppMod pointing to a module instance.
+ * On failure, a non-zero OS specific error code is returned.
+ * @param pOps Pointer to the registered method table.
+ * @param pRdr The file provider instance to use.
+ * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
+ * @param ppMod Where to store the module instance pointer.
+ */
+static int kldrModNativeCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch,
+ KLDRFOFF offNewHdr, PPKLDRMOD ppMod)
+{
+ int rc = kLdrModOpenNative(kRdrName(pRdr), fFlags, ppMod);
+ if (rc)
+ return rc;
+ rc = kRdrClose(pRdr);
+ KLDRMODNATIVE_ASSERT(!rc);
+ return 0;
+}
+
+
+/**
+ * Loads a module using the native module loader.
+ *
+ * @returns 0 on success.
+ * @returns non-zero native or kLdr status code on failure.
+ * @param pszFilename The filename or module name to be loaded.
+ * @param fFlags Module open flags, KLDRMOD_OPEN_FLAGS_XXX.
+ * @param ppMod Where to store the module interpreter instance pointer.
+ */
+int kLdrModOpenNative(const char *pszFilename, KU32 fFlags, PPKLDRMOD ppMod)
+{
+ int rc;
+
+ /*
+ * Load the image.
+ */
+#if K_OS == K_OS_OS2
+ HMODULE hmod;
+ kHlpAssertReturn(!(fFlags & ~KLDRMOD_OPEN_FLAGS_VALID_MASK), KERR_INVALID_PARAMETER);
+
+ rc = DosLoadModule(NULL, 0, (PCSZ)pszFilename, &hmod);
+ if (rc)
+ return rc;
+ rc = kLdrModOpenNativeByHandle((KUPTR)hmod, fFlags, ppMod);
+ if (rc)
+ DosFreeModule(hmod);
+
+#elif K_OS == K_OS_WINDOWS
+ HMODULE hmod;
+ kHlpAssertReturn(!(fFlags & ~KLDRMOD_OPEN_FLAGS_VALID_MASK), KERR_INVALID_PARAMETER);
+
+ hmod = LoadLibrary(pszFilename);
+ if (!hmod)
+ return GetLastError();
+ rc = kLdrModOpenNativeByHandle((KUPTR)hmod, fFlags, ppMod);
+ if (rc)
+ FreeLibrary(hmod);
+
+#elif K_OS == K_OS_DARWIN
+ void *pvMod;
+ kHlpAssertReturn(!(fFlags & ~KLDRMOD_OPEN_FLAGS_VALID_MASK), KERR_INVALID_PARAMETER);
+
+ pvMod = dlopen(pszFilename, 0);
+ if (!pvMod)
+ return ENOENT;
+ rc = kLdrModOpenNativeByHandle((KUPTR)pvMod, fFlags, ppMod);
+ if (rc)
+ dlclose(pvMod);
+
+#else
+# error "Port me"
+#endif
+ return rc;
+}
+
+
+/**
+ * Creates a native module interpret for an already module already
+ * loaded by the native loader.
+ *
+ * @returns 0 on success.
+ * @returns non-zero native or kLdr status code on failure.
+ * @param pszFilename The filename or module name to be loaded.
+ * @param fFlags Module open flags, KLDRMOD_OPEN_FLAGS_XXX.
+ * @param ppMod Where to store the module interpreter instance pointer.
+ * @remark This will not make the native loader increment the load count.
+ */
+int kLdrModOpenNativeByHandle(KUPTR uHandle, KU32 fFlags, PPKLDRMOD ppMod)
+{
+ KSIZE cb;
+ KU32 cchFilename;
+ KU32 cSegments;
+ PKLDRMOD pMod;
+ PKLDRMODNATIVE pModNative;
+
+ /*
+ * Delcare variables, parse the module header or whatever and determin the
+ * size of the module instance.
+ */
+#if K_OS == K_OS_OS2
+ char szFilename[CCHMAXPATH];
+ int rc;
+
+ /* get the filename. */
+ rc = DosQueryModuleName((HMODULE)uHandle, sizeof(szFilename), szFilename);
+ if (rc)
+ {
+ KLDRMODNATIVE_ASSERT(rc);
+ szFilename[0] = '\0';
+ }
+
+ /* get the segment count. */
+ /** @todo DosQueryHeaderInfo should be able to get us what we want on OS/2. */
+ cSegments = 1;
+
+#elif K_OS == K_OS_WINDOWS
+ DWORD dw;
+ char szFilename[MAX_PATH];
+ const IMAGE_NT_HEADERS *pNtHdrs;
+ const IMAGE_SECTION_HEADER *paShdrs;
+ const IMAGE_DOS_HEADER *pDosHdr = (const IMAGE_DOS_HEADER *)uHandle;
+ unsigned i;
+
+ /* get the filename. */
+ dw = GetModuleFileName((HANDLE)uHandle, szFilename, sizeof(szFilename));
+ if (dw <= 0)
+ {
+ KLDRMODNATIVE_ASSERT(dw <= 0);
+ szFilename[0] = '\0';
+ }
+
+ /* get the segment count. */
+ if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE)
+ pNtHdrs = (const IMAGE_NT_HEADERS *)((KUPTR)pDosHdr + pDosHdr->e_lfanew);
+ else
+ pNtHdrs = (const IMAGE_NT_HEADERS *)pDosHdr;
+ if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE)
+ {
+ KLDRMODNATIVE_ASSERT(!"bad signature");
+ return KLDR_ERR_UNKNOWN_FORMAT;
+ }
+ if (pNtHdrs->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))
+ {
+ KLDRMODNATIVE_ASSERT(!"bad optional header size");
+ return KLDR_ERR_UNKNOWN_FORMAT;
+ }
+ cSegments = pNtHdrs->FileHeader.NumberOfSections + 1;
+ paShdrs = (const IMAGE_SECTION_HEADER *)(pNtHdrs + 1);
+
+#elif K_OS == K_OS_DARWIN
+ char szFilename[1] = "";
+ cSegments = 0; /** @todo Figure out the Mac OS X dynamic loader. */
+
+#else
+# error "Port me"
+#endif
+
+ kHlpAssertReturn(!(fFlags & ~KLDRMOD_OPEN_FLAGS_VALID_MASK), KERR_INVALID_PARAMETER);
+
+ /*
+ * Calc the instance size, allocate and initialize it.
+ */
+ cchFilename = (KU32)kHlpStrLen(szFilename);
+ cb = K_ALIGN_Z(sizeof(KLDRMODNATIVE), 16)
+ + K_OFFSETOF(KLDRMOD, aSegments[cSegments])
+ + cchFilename + 1;
+ pModNative = (PKLDRMODNATIVE)kHlpAlloc(cb);
+ if (!pModNative)
+ return KERR_NO_MEMORY;
+
+ /* KLDRMOD */
+ pMod = (PKLDRMOD)((KU8 *)pModNative + K_ALIGN_Z(sizeof(KLDRMODNATIVE), 16));
+ pMod->pvData = pModNative;
+ pMod->pRdr = NULL;
+ pMod->pOps = NULL; /* set upon success. */
+ pMod->cSegments = cSegments;
+ pMod->cchFilename = cchFilename;
+ pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
+ kHlpMemCopy((char *)pMod->pszFilename, szFilename, cchFilename + 1);
+ pMod->pszName = kHlpGetFilename(pMod->pszFilename); /** @todo get soname */
+ pMod->cchName = cchFilename - (KU32)(pMod->pszName - pMod->pszFilename);
+ pMod->fFlags = fFlags;
+#if defined(__i386__) || defined(__X86__) || defined(_M_IX86)
+ pMod->enmCpu = KCPU_I386;
+ pMod->enmArch = KCPUARCH_X86_32;
+ pMod->enmEndian = KLDRENDIAN_LITTLE;
+#elif defined(__X86_64__) || defined(__x86_64__) || defined(__AMD64__) || defined(_M_IX64)
+ pMod->enmCpu = KCPU_K8;
+ pMod->enmArch = KCPUARCH_AMD64;
+ pMod->enmEndian = KLDRENDIAN_LITTLE;
+#else
+# error "Port me"
+#endif
+ pMod->enmFmt = KLDRFMT_NATIVE;
+ pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
+ pMod->u32Magic = 0; /* set upon success. */
+
+ /* KLDRMODNATIVE */
+ pModNative->pMod = pMod;
+ pModNative->f32Reserved = 0;
+ pModNative->cImportModules = ~(KU32)0;
+
+ /*
+ * Set native instance data.
+ */
+#if K_OS == K_OS_OS2
+ pModNative->hmod = (HMODULE)uHandle;
+
+ /* just fake a segment for now. */
+ pMod->aSegments[0].pvUser = NULL;
+ pMod->aSegments[0].pchName = "fake";
+ pMod->aSegments[0].cchName = sizeof("fake") - 1;
+ pMod->aSegments[0].enmProt = KPROT_NOACCESS;
+ pMod->aSegments[0].cb = 0;
+ pMod->aSegments[0].Alignment = 0;
+ pMod->aSegments[0].LinkAddress = NIL_KLDRADDR;
+ pMod->aSegments[0].offFile = -1;
+ pMod->aSegments[0].cbFile = 0;
+ pMod->aSegments[0].RVA = NIL_KLDRADDR;
+ pMod->aSegments[0].cbMapped = 0;
+ pMod->aSegments[0].MapAddress = 0;
+
+#elif K_OS == K_OS_WINDOWS
+ pModNative->hmod = (HMODULE)uHandle;
+ pModNative->pNtHdrs = pNtHdrs;
+ pModNative->paShdrs = paShdrs;
+
+ if (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL)
+ pMod->enmType = !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+ ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
+ : KLDRTYPE_SHARED_LIBRARY_FIXED;
+ else
+ pMod->enmType = !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+ ? KLDRTYPE_EXECUTABLE_RELOCATABLE
+ : KLDRTYPE_EXECUTABLE_FIXED;
+
+ /* The implied headers section. */
+ pMod->aSegments[0].pvUser = NULL;
+ pMod->aSegments[0].pchName = "TheHeaders";
+ pMod->aSegments[0].cchName = sizeof("TheHeaders") - 1;
+ pMod->aSegments[0].enmProt = KPROT_READONLY;
+ pMod->aSegments[0].cb = pNtHdrs->OptionalHeader.SizeOfHeaders;
+ pMod->aSegments[0].Alignment = pNtHdrs->OptionalHeader.SectionAlignment;
+ pMod->aSegments[0].LinkAddress = pNtHdrs->OptionalHeader.ImageBase;
+ pMod->aSegments[0].offFile = 0;
+ pMod->aSegments[0].cbFile = pNtHdrs->OptionalHeader.SizeOfHeaders;
+ pMod->aSegments[0].RVA = 0;
+ if (pMod->cSegments > 1)
+ pMod->aSegments[0].cbMapped = paShdrs[0].VirtualAddress;
+ else
+ pMod->aSegments[0].cbMapped = pNtHdrs->OptionalHeader.SizeOfHeaders;
+ pMod->aSegments[0].MapAddress = uHandle;
+
+ /* The section headers. */
+ for (i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
+ {
+ const char *pch;
+ KU32 cchSegName;
+
+ /* unused */
+ pMod->aSegments[i + 1].pvUser = NULL;
+
+ /* name */
+ pMod->aSegments[i + 1].pchName = pch = &paShdrs[i].Name[0];
+ cchSegName = IMAGE_SIZEOF_SHORT_NAME;
+ while ( cchSegName > 0
+ && (pch[cchSegName - 1] == ' ' || pch[cchSegName - 1] == '\0'))
+ cchSegName--;
+ pMod->aSegments[i + 1].cchName = cchSegName;
+
+ /* size and addresses */
+ if (!(paShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
+ {
+ pMod->aSegments[i + 1].cb = paShdrs[i].Misc.VirtualSize;
+ pMod->aSegments[i + 1].RVA = paShdrs[i].VirtualAddress;
+ pMod->aSegments[i + 1].LinkAddress = paShdrs[i].VirtualAddress + pNtHdrs->OptionalHeader.ImageBase;
+ pMod->aSegments[i + 1].MapAddress = paShdrs[i].VirtualAddress + uHandle;
+ pMod->aSegments[i + 1].cbMapped = paShdrs[i].Misc.VirtualSize;
+ if (i + 2 < pMod->cSegments)
+ pMod->aSegments[i + 1].cbMapped = paShdrs[i + 1].VirtualAddress
+ - paShdrs[i].VirtualAddress;
+ }
+ else
+ {
+ pMod->aSegments[i + 1].cb = 0;
+ pMod->aSegments[i + 1].cbMapped = 0;
+ pMod->aSegments[i + 1].LinkAddress = NIL_KLDRADDR;
+ pMod->aSegments[i + 1].RVA = 0;
+ pMod->aSegments[i + 1].MapAddress = 0;
+ }
+
+ /* file location */
+ pMod->aSegments[i + 1].offFile = paShdrs[i].PointerToRawData;
+ pMod->aSegments[i + 1].cbFile = paShdrs[i].SizeOfRawData;
+ if ( pMod->aSegments[i + 1].cbMapped > 0 /* if mapped */
+ && (KLDRSIZE)pMod->aSegments[i + 1].cbFile > pMod->aSegments[i + 1].cbMapped)
+ pMod->aSegments[i + 1].cbFile = (KLDRFOFF)pMod->aSegments[i + 1].cbMapped;
+
+ /* protection */
+ switch ( paShdrs[i].Characteristics
+ & (IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
+ {
+ case 0:
+ case IMAGE_SCN_MEM_SHARED:
+ pMod->aSegments[i + 1].enmProt = KPROT_NOACCESS;
+ break;
+ case IMAGE_SCN_MEM_READ:
+ case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
+ pMod->aSegments[i + 1].enmProt = KPROT_READONLY;
+ break;
+ case IMAGE_SCN_MEM_WRITE:
+ case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
+ pMod->aSegments[i + 1].enmProt = KPROT_WRITECOPY;
+ break;
+ case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
+ case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
+ pMod->aSegments[i + 1].enmProt = KPROT_READWRITE;
+ break;
+ case IMAGE_SCN_MEM_EXECUTE:
+ case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_SHARED:
+ pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE;
+ break;
+ case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ:
+ case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
+ pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READ;
+ break;
+ case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE:
+ case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
+ pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_WRITECOPY;
+ break;
+ case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
+ case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
+ pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READWRITE;
+ break;
+ }
+
+ /* alignment. */
+ switch (paShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
+ {
+ case 0: /* hope this is right... */
+ pMod->aSegments[i + 1].Alignment = pNtHdrs->OptionalHeader.SectionAlignment;
+ break;
+ case IMAGE_SCN_ALIGN_1BYTES: pMod->aSegments[i + 1].Alignment = 1; break;
+ case IMAGE_SCN_ALIGN_2BYTES: pMod->aSegments[i + 1].Alignment = 2; break;
+ case IMAGE_SCN_ALIGN_4BYTES: pMod->aSegments[i + 1].Alignment = 4; break;
+ case IMAGE_SCN_ALIGN_8BYTES: pMod->aSegments[i + 1].Alignment = 8; break;
+ case IMAGE_SCN_ALIGN_16BYTES: pMod->aSegments[i + 1].Alignment = 16; break;
+ case IMAGE_SCN_ALIGN_32BYTES: pMod->aSegments[i + 1].Alignment = 32; break;
+ case IMAGE_SCN_ALIGN_64BYTES: pMod->aSegments[i + 1].Alignment = 64; break;
+ case IMAGE_SCN_ALIGN_128BYTES: pMod->aSegments[i + 1].Alignment = 128; break;
+ case IMAGE_SCN_ALIGN_256BYTES: pMod->aSegments[i + 1].Alignment = 256; break;
+ case IMAGE_SCN_ALIGN_512BYTES: pMod->aSegments[i + 1].Alignment = 512; break;
+ case IMAGE_SCN_ALIGN_1024BYTES: pMod->aSegments[i + 1].Alignment = 1024; break;
+ case IMAGE_SCN_ALIGN_2048BYTES: pMod->aSegments[i + 1].Alignment = 2048; break;
+ case IMAGE_SCN_ALIGN_4096BYTES: pMod->aSegments[i + 1].Alignment = 4096; break;
+ case IMAGE_SCN_ALIGN_8192BYTES: pMod->aSegments[i + 1].Alignment = 8192; break;
+ default: kHlpAssert(0); pMod->aSegments[i + 1].Alignment = 0; break;
+ }
+ }
+
+#elif K_OS == K_OS_DARWIN
+ /** @todo Figure out the Mac OS X dynamic loader. */
+
+#else
+# error "Port me"
+#endif
+
+ /*
+ * We're done.
+ */
+ pMod->u32Magic = KLDRMOD_MAGIC;
+ pMod->pOps = &g_kLdrModNativeOps;
+ *ppMod = pMod;
+ return 0;
+}
+
+
+/** @copydoc KLDRMODOPS::pfnDestroy */
+static int kldrModNativeDestroy(PKLDRMOD pMod)
+{
+ PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+ int rc;
+
+#if K_OS == K_OS_OS2
+ rc = DosFreeModule(pModNative->hmod);
+
+#elif K_OS == K_OS_WINDOWS
+ if (FreeLibrary(pModNative->hmod))
+ rc = 0;
+ else
+ rc = GetLastError();
+
+#elif K_OS == K_OS_DARWIN
+ dlclose(pModNative->pvMod);
+
+#else
+# error "Port me"
+#endif
+
+ pMod->u32Magic = 0;
+ pMod->pOps = NULL;
+ kHlpFree(pModNative);
+ return rc;
+}
+
+
+/** @copydoc kLdrModQuerySymbol */
+static int kldrModNativeQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
+ const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
+ PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
+{
+ PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+ const char *pszSymbol = pchSymbol;
+#if K_OS == K_OS_OS2
+ APIRET rc;
+ PFN pfn;
+#elif K_OS == K_OS_WINDOWS
+ FARPROC pfn;
+#elif K_OS == K_OS_DARWIN
+ void *pfn;
+#else
+# error "Port me"
+#endif
+
+ /* make stack copy of the symbol if it isn't zero terminated. */
+ if (pszSymbol && pszSymbol[cchSymbol])
+ {
+ char *pszCopy = kHlpAllocA(cchSymbol + 1);
+ kHlpMemCopy(pszCopy, pchSymbol, cchSymbol);
+ pszCopy[cchSymbol] = '\0';
+ pszSymbol = pszCopy;
+ }
+
+#if K_OS == K_OS_OS2
+ if (!pchSymbol && iSymbol >= 0x10000)
+ return KLDR_ERR_SYMBOL_NOT_FOUND;
+
+ if (puValue)
+ {
+ rc = DosQueryProcAddr(pModNative->hmod,
+ pszSymbol ? 0 : iSymbol,
+ (PCSZ)pszSymbol,
+ &pfn);
+ if (rc)
+ return rc == ERROR_PROC_NOT_FOUND ? KLDR_ERR_SYMBOL_NOT_FOUND : rc;
+ *puValue = (KUPTR)pfn;
+ }
+ if (pfKind)
+ {
+ ULONG ulProcType;
+ rc = DosQueryProcType(pModNative->hmod,
+ pszSymbol ? 0 : iSymbol,
+ (PCSZ)pszSymbol,
+ &ulProcType);
+ if (rc)
+ {
+ if (puValue)
+ *puValue = 0;
+ return rc == ERROR_PROC_NOT_FOUND ? KLDR_ERR_SYMBOL_NOT_FOUND : rc;
+ }
+ *pfKind = (ulProcType & PT_32BIT ? KLDRSYMKIND_32BIT : KLDRSYMKIND_16BIT)
+ | KLDRSYMKIND_NO_TYPE;
+ }
+
+#elif K_OS == K_OS_WINDOWS
+ if (!pszSymbol && iSymbol >= 0x10000)
+ return KLDR_ERR_SYMBOL_NOT_FOUND;
+
+ pfn = GetProcAddress(pModNative->hmod, pszSymbol ? pszSymbol : (const char *)(KUPTR)iSymbol);
+ if (puValue)
+ *puValue = (KUPTR)pfn;
+ if (pfKind)
+ *pfKind = (pModNative->pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
+ ? KLDRSYMKIND_32BIT : KLDRSYMKIND_16BIT)
+ | KLDRSYMKIND_NO_TYPE;
+
+#elif K_OS == K_OS_DARWIN
+ if (!pszSymbol && iSymbol != NIL_KLDRMOD_SYM_ORDINAL)
+ return KLDR_ERR_SYMBOL_NOT_FOUND;
+
+ pfn = dlsym(pModNative->pvMod, pszSymbol);
+ if (!pfn)
+ return KLDR_ERR_SYMBOL_NOT_FOUND;
+ if (puValue)
+ *puValue = (KUPTR)pfn;
+ if (pfKind)
+ *pfKind = (sizeof(KUPTR) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
+ | KLDRSYMKIND_NO_TYPE;
+
+#else
+# error "Port me"
+#endif
+
+ return 0;
+}
+
+
+/** @copydoc kLdrModEnumSymbols */
+static int kldrModNativeEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
+ KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
+{
+ PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+ /** @todo implement export enumeration on OS/2. */
+ (void)pModNative;
+ return ERROR_NOT_SUPPORTED;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+ const KU32 *paFunctions;
+ const IMAGE_EXPORT_DIRECTORY *pExpDir;
+ const KU32 *paRVANames;
+ const KU16 *paOrdinals;
+ KU32 iFunction;
+ KU32 cFunctions;
+ KU32 cNames;
+ int rc;
+
+ /*
+ * Make sure we've got mapped bits and resolve any base address aliases.
+ */
+ if ( pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
+ < sizeof(IMAGE_EXPORT_DIRECTORY))
+ return 0; /* no exports to enumerate, return success. */
+
+ pExpDir = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod,
+ pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
+ PIMAGE_EXPORT_DIRECTORY);
+
+ /*
+ * Enumerate the ordinal exports.
+ */
+ paRVANames = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfNames, const KU32 *);
+ paOrdinals = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfNameOrdinals, const KU16 *);
+ paFunctions = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfFunctions, const KU32 *);
+ cFunctions = pExpDir->NumberOfFunctions;
+ cNames = pExpDir->NumberOfNames;
+ for (iFunction = 0; iFunction < cFunctions; iFunction++)
+ {
+ unsigned fFoundName;
+ KU32 iName;
+ const KU32 uRVA = paFunctions[iFunction];
+ const KLDRADDR uValue = BaseAddress + uRVA;
+ KU32 fKind = (pModNative->pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
+ ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
+ | KLDRSYMKIND_NO_TYPE;
+ if ( uRVA - pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
+ < pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
+ fKind |= KLDRSYMKIND_FORWARDER;
+
+ /*
+ * Any symbol names?
+ */
+ fFoundName = 0;
+ for (iName = 0; iName < cNames; iName++)
+ {
+ const char *pszName;
+ if (paOrdinals[iName] != iFunction)
+ continue;
+ fFoundName = 1;
+
+ pszName = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, paRVANames[iName], const char *);
+ rc = pfnCallback(pMod, iFunction + pExpDir->Base, pszName, strlen(pszName), NULL,
+ uValue, fKind, pvUser);
+ if (rc)
+ return rc;
+ }
+
+ /*
+ * If no names, call once with the ordinal only.
+ */
+ if (!fFoundName)
+ {
+ rc = pfnCallback(pMod, iFunction + pExpDir->Base, NULL, 0, NULL, uValue, fKind, pvUser);
+ if (rc)
+ return rc;
+ }
+ }
+ return 0;
+
+#elif K_OS == K_OS_DARWIN
+ /** @todo implement enumeration on darwin. */
+ (void)pModNative;
+ return KLDR_ERR_TODO;
+
+#else
+# error "Port me"
+#endif
+
+}
+
+
+/** @copydoc kLdrModGetImport */
+static int kldrModNativeGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName)
+{
+ PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+ /** @todo implement import enumeration on OS/2. */
+ (void)pModNative;
+ return ERROR_NOT_SUPPORTED;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+ const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
+ const char *pszImportName;
+ KSIZE cchImportName;
+ int rc;
+
+ /*
+ * Simple bounds check.
+ */
+ if (iImport >= (KU32)kldrModNativeNumberOfImports(pMod, pvBits))
+ return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
+
+ /*
+ * Get the name.
+ */
+ pImpDesc = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod,
+ pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
+ + sizeof(IMAGE_IMPORT_DESCRIPTOR) * iImport,
+ const IMAGE_IMPORT_DESCRIPTOR *);
+ pszImportName = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pImpDesc->Name, const char *);
+ cchImportName = kHlpStrLen(pszImportName);
+ if (cchImportName < cchName)
+ {
+ kHlpMemCopy(pszName, pszImportName, cchImportName + 1);
+ rc = 0;
+ }
+ else
+ {
+ kHlpMemCopy(pszName, pszImportName, cchName);
+ if (cchName)
+ pszName[cchName - 1] = '\0';
+ rc = KERR_BUFFER_OVERFLOW;
+ }
+
+ return rc;
+
+#elif K_OS == K_OS_DARWIN
+ /** @todo Implement import enumeration on darwin. */
+ (void)pModNative;
+ return KLDR_ERR_TODO;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModNumberOfImports */
+static KI32 kldrModNativeNumberOfImports(PKLDRMOD pMod, const void *pvBits)
+{
+ PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+ /** @todo implement import counting on OS/2. */
+ (void)pModNative;
+ return -1;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+ if (pModNative->cImportModules == ~(KU32)0)
+ {
+ /*
+ * We'll have to walk the import descriptors to figure out their number.
+ */
+ pModNative->cImportModules = 0;
+ if ( pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
+ && pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
+ {
+ const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
+
+ pImpDesc = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod,
+ pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
+ const IMAGE_IMPORT_DESCRIPTOR *);
+ while (pImpDesc->Name && pImpDesc->FirstThunk)
+ {
+ pModNative->cImportModules++;
+ pImpDesc++;
+ }
+ }
+ }
+ return pModNative->cImportModules;
+
+#elif K_OS == K_OS_DARWIN
+ /** @todo Implement import counting on Darwin. */
+ (void)pModNative;
+ return -1;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModGetStackInfo */
+static int kldrModNativeGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
+{
+ PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+ /** @todo implement stack info on OS/2. */
+ (void)pModNative;
+ return ERROR_NOT_SUPPORTED;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+ pStackInfo->Address = NIL_KLDRADDR;
+ pStackInfo->LinkAddress = NIL_KLDRADDR;
+ pStackInfo->cbStack = pStackInfo->cbStackThread = pModNative->pNtHdrs->OptionalHeader.SizeOfStackReserve;
+
+ return 0;
+
+#elif K_OS == K_OS_DARWIN
+ /** @todo Implement stack info on Darwin. */
+ (void)pModNative;
+ return KLDR_ERR_TODO;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModQueryMainEntrypoint */
+static int kldrModNativeQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
+{
+ PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+ /** @todo implement me on OS/2. */
+ (void)pModNative;
+ return ERROR_NOT_SUPPORTED;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+ /*
+ * Convert the address from the header.
+ */
+ *pMainEPAddress = pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint
+ ? BaseAddress + pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint
+ : NIL_KLDRADDR;
+ return 0;
+
+#elif K_OS == K_OS_DARWIN
+ /** @todo Implement me on Darwin. */
+ (void)pModNative;
+ return KLDR_ERR_TODO;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModEnumDbgInfo */
+static int kldrModNativeEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
+{
+ PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+ /** @todo implement me on OS/2. */
+ (void)pModNative;
+ return ERROR_NOT_SUPPORTED;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+ const IMAGE_DEBUG_DIRECTORY *pDbgDir;
+ KU32 iDbgInfo;
+ KU32 cb;
+ int rc;
+
+ /*
+ * Check that there is a debug directory first.
+ */
+ cb = pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
+ if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
+ || !pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
+ return 0;
+
+ /*
+ * Enumerate the debug directory.
+ */
+ pDbgDir = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod,
+ pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
+ const IMAGE_DEBUG_DIRECTORY *);
+ for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY))
+ {
+ KLDRDBGINFOTYPE enmDbgInfoType;
+
+ /* convert the type. */
+ switch (pDbgDir->Type)
+ {
+ case IMAGE_DEBUG_TYPE_UNKNOWN:
+ case IMAGE_DEBUG_TYPE_FPO:
+ case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/
+ case IMAGE_DEBUG_TYPE_MISC:
+ case IMAGE_DEBUG_TYPE_EXCEPTION:
+ case IMAGE_DEBUG_TYPE_FIXUP:
+ case IMAGE_DEBUG_TYPE_BORLAND:
+ default:
+ enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN;
+ break;
+ case IMAGE_DEBUG_TYPE_CODEVIEW:
+ enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW;
+ break;
+ }
+
+ rc = pfnCallback(pMod, iDbgInfo,
+ enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion, NULL /*pszPartNm*/,
+ pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1,
+ pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR,
+ pDbgDir->SizeOfData,
+ NULL /*pszExtFile*/, pvUser);
+ if (rc)
+ break;
+
+ /* next */
+ if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY))
+ break;
+ }
+
+ return rc;
+
+#elif K_OS == K_OS_DARWIN
+ /** @todo Implement me on Darwin. */
+ (void)pModNative;
+ return KLDR_ERR_TODO;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModHasDbgInfo */
+static int kldrModNativeHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
+{
+ PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+ /** @todo implement me on OS/2. */
+ (void)pModNative;
+ return KLDR_ERR_NO_DEBUG_INFO;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+ /*
+ * Base this entirely on the presence of a debug directory.
+ */
+ if ( pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
+ < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
+ || !pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
+ return KLDR_ERR_NO_DEBUG_INFO;
+ return 0;
+
+#elif K_OS == K_OS_DARWIN
+ /** @todo Implement me on Darwin. */
+ (void)pModNative;
+ return KLDR_ERR_NO_DEBUG_INFO;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModMap */
+static int kldrModNativeMap(PKLDRMOD pMod)
+{
+ return 0;
+}
+
+
+/** @copydoc kLdrModUnmap */
+static int kldrModNativeUnmap(PKLDRMOD pMod)
+{
+ return 0;
+}
+
+
+/** @copydoc kLdrModAllocTLS */
+static int kldrModNativeAllocTLS(PKLDRMOD pMod, void *pvMapping)
+{
+ return 0;
+}
+
+
+/** @copydoc kLdrModFreeTLS */
+static void kldrModNativeFreeTLS(PKLDRMOD pMod, void *pvMapping)
+{
+}
+
+
+/** @copydoc kLdrModReload */
+static int kldrModNativeReload(PKLDRMOD pMod)
+{
+ return 0;
+}
+
+
+/** @copydoc kLdrModFixupMapping */
+static int kldrModNativeFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+ return 0;
+}
+
+
+#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS || defined(__NT__)
+/** Common worker on platforms where there is one entrypoint which does both. */
+static int kLdrModNativeCallInitTerm(PKLDRMODNATIVE pModNative, KUPTR uHandle, KBOOL fInit)
+{
+# if K_OS == K_OS_WINDOWS || defined(__NT__)
+ /* No TLS init/term for now. */
+ KU32 const uRvaEntrypoint = pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint;
+ if ( uRvaEntrypoint != 0
+ && uRvaEntrypoint < pModNative->pNtHdrs->OptionalHeader.SizeOfCode
+ && (pModNative->pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL))
+ {
+ KI32 rc = kldrModPEDoCall(uRvaEntrypoint + (KUPTR)pModNative->hmod, uHandle,
+ fInit ? DLL_PROCESS_ATTACH : DLL_PROCESS_DETACH, NULL /*pvReserved*/);
+ if (rc)
+ return 0;
+ return fInit ? KLDR_ERR_MODULE_INIT_FAILED : KLDR_ERR_THREAD_ATTACH_FAILED;
+ }
+# elif K_OS == K_OS_OS2
+ //KI32 kldrModLXDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved)
+# endif
+ return 0;
+}
+#endif
+
+/** @copydoc kLdrModCallInit */
+static int kldrModNativeCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle)
+{
+#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS || defined(__NT__)
+ if (pMod->fFlags & KLDRMOD_OPEN_FLAGS_NATIVE_ALLOW_INIT_TERM)
+ return kLdrModNativeCallInitTerm((PKLDRMODNATIVE)pMod->pvData, uHandle, K_TRUE /*fInit*/);
+#endif
+ return 0;
+}
+
+
+/** @copydoc kLdrModCallTerm */
+static int kldrModNativeCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle)
+{
+#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS || defined(__NT__)
+ if (pMod->fFlags & KLDRMOD_OPEN_FLAGS_NATIVE_ALLOW_INIT_TERM)
+ return kLdrModNativeCallInitTerm((PKLDRMODNATIVE)pMod->pvData, uHandle, K_FALSE /*fInit*/);
+#endif
+ return 0;
+}
+
+
+/** @copydoc kLdrModCallThread */
+static int kldrModNativeCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching)
+{
+ return 0;
+}
+
+
+/** @copydoc kLdrModSize */
+static KLDRADDR kldrModNativeSize(PKLDRMOD pMod)
+{
+#if K_OS == K_OS_OS2
+ return 0; /* don't bother */
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+ /* just because we can. */
+ PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+ return pModNative->pNtHdrs->OptionalHeader.SizeOfImage;
+
+#elif K_OS == K_OS_DARWIN
+ /** @todo Implement me on Darwin. */
+ return 0;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModGetBits */
+static int kldrModNativeGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+#if K_OS == K_OS_OS2
+ return ERROR_NOT_SUPPORTED; /* don't bother */
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+ return ERROR_NOT_SUPPORTED; /* don't bother even if we could implement this. */
+
+#elif K_OS == K_OS_DARWIN
+ return KLDR_ERR_TODO; /* don't bother. */
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModRelocateBits */
+static int kldrModNativeRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
+ PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+#if K_OS == K_OS_OS2
+ return ERROR_NOT_SUPPORTED; /* don't bother */
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+ return ERROR_NOT_SUPPORTED; /* don't bother even if we could implement this. */
+
+#elif K_OS == K_OS_DARWIN
+ return KLDR_ERR_TODO; /* don't bother. */
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/**
+ * The native module interpreter method table.
+ */
+KLDRMODOPS g_kLdrModNativeOps =
+{
+ "Native",
+ NULL,
+ kldrModNativeCreate,
+ kldrModNativeDestroy,
+ kldrModNativeQuerySymbol,
+ kldrModNativeEnumSymbols,
+ kldrModNativeGetImport,
+ kldrModNativeNumberOfImports,
+ NULL /* can execute one is optional */,
+ kldrModNativeGetStackInfo,
+ kldrModNativeQueryMainEntrypoint,
+ NULL /* pfnQueryImageUuid */,
+ NULL /* fixme */,
+ NULL /* fixme */,
+ kldrModNativeEnumDbgInfo,
+ kldrModNativeHasDbgInfo,
+ kldrModNativeMap,
+ kldrModNativeUnmap,
+ kldrModNativeAllocTLS,
+ kldrModNativeFreeTLS,
+ kldrModNativeReload,
+ kldrModNativeFixupMapping,
+ kldrModNativeCallInit,
+ kldrModNativeCallTerm,
+ kldrModNativeCallThread,
+ kldrModNativeSize,
+ kldrModNativeGetBits,
+ kldrModNativeRelocateBits,
+ NULL /* fixme */,
+ 42 /* the end */
+};
+