/* $Id: kLdrModNative.c 2974 2007-02-14 10:12:44Z bird $ */ /** @file * * kLdr - The Module Interpreter for the Native Loaders. * * Copyright (c) 2006 knut st. osmundsen * * * This file is part of kLdr. * * kLdr is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kLdr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kLdr; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrHlp.h" #include "kLdrInternal.h" #ifdef __OS2__ # define INCL_BASE # include # 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 defined(__WIN__) # undef IMAGE_NT_SIGNATURE # undef IMAGE_DOS_SIGNATURE # include # ifndef IMAGE_SCN_TYPE_NOLOAD # define IMAGE_SCN_TYPE_NOLOAD 0x00000002 # endif /*#elif defined(__NT__) #include */ #elif defined(__DARWIN__) # include # include #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) kldrHlpAssert(expr) #else # define KLDRMODNATIVE_ASSERT(expr) do {} while (0) #endif #if defined(__WIN__) || defined(__NT__) /** @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) ((uintptr_t)(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. */ uint32_t f32Reserved; /** The number of imported modules. * If ~(uint32_t)0 this hasn't been determined yet. */ uint32_t cImportModules; #ifdef __OS2__ /** The module handle. */ HMODULE hmod; #elif defined(__WIN__) /** 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 defined(__DARWIN__) /** The dlopen() handle.*/ void *pvMod; #else # error "Port me" #endif } KLDRMODNATIVE, *PKLDRMODNATIVE; /******************************************************************************* * Internal Functions * *******************************************************************************/ static int32_t kldrModNativeNumberOfImports(PKLDRMOD pMod, const void *pvBits); /** * 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, PKLDRRDR pRdr, KLDRFOFF offNewHdr, PPKLDRMOD ppMod) { int rc = kLdrModOpenNative(kLdrRdrName(pRdr), ppMod); if (rc) return rc; rc = kLdrRdrClose(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 ppMod Where to store the module interpreter instance pointer. */ int kLdrModOpenNative(const char *pszFilename, PPKLDRMOD ppMod) { int rc; /* * Load the image. */ #ifdef __OS2__ HMODULE hmod; rc = DosLoadModule(NULL, 0, (PCSZ)pszFilename, &hmod); if (rc) return rc; rc = kLdrModOpenNativeByHandle((uintptr_t)hmod, ppMod); if (rc) DosFreeModule(hmod); #elif defined(__WIN__) HMODULE hmod; hmod = LoadLibrary(pszFilename); if (!hmod) return GetLastError(); rc = kLdrModOpenNativeByHandle((uintptr_t)hmod, ppMod); if (rc) FreeLibrary(hmod); #elif defined(__DARWIN__) void *pvMod; pvMod = dlopen(pszFilename, 0); if (!pvMod) return ENOENT; rc = kLdrModOpenNativeByHandle((uintptr_t)pvMod, 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 ppMod Where to store the module interpreter instance pointer. * @remark This will not make the native loader increment the load count. */ int kLdrModOpenNativeByHandle(uintptr_t uHandle, PPKLDRMOD ppMod) { size_t cb; size_t cchFilename; uint32_t cSegments; PKLDRMOD pMod; PKLDRMODNATIVE pModNative; /* * Delcare variables, parse the module header or whatever and determin the * size of the module instance. */ #ifdef __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 defined(__WIN__) 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 *)((uintptr_t)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 defined(__DARWIN__) char szFilename[1] = ""; cSegments = 0; /** @todo Figure out the Mac OS X dynamic loader. */ #else # error "Port me" #endif /* * Calc the instance size, allocate and initialize it. */ cchFilename = kLdrHlpStrLen(szFilename); cb = KLDR_ALIGN_Z(sizeof(KLDRMODNATIVE), 16) + KLDR_OFFSETOF(KLDRMOD, aSegments[cSegments]) + cchFilename + 1; pModNative = (PKLDRMODNATIVE)kldrHlpAlloc(cb); if (!pModNative) return KLDR_ERR_NO_MEMORY; /* KLDRMOD */ pMod = (PKLDRMOD)((uint8_t *)pModNative + KLDR_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]; kLdrHlpMemCopy((char *)pMod->pszFilename, szFilename, cchFilename + 1); pMod->pszName = kldrHlpGetFilename(pMod->pszFilename); /** @todo get soname */ pMod->cchName = cchFilename - (pMod->pszName - pMod->pszFilename); #if defined(__i386__) || defined(__X86__) || defined(_M_IX86) pMod->enmCpu = KLDRCPU_I386; pMod->enmArch = KLDRARCH_X86_32; pMod->enmEndian = KLDRENDIAN_LITTLE; #elif defined(__X86_64__) || defined(__x86_64__) || defined(__AMD64__) || defined(_M_IX64) pMod->enmCpu = KLDRCPU_K8; pMod->enmArch = KLDRARCH_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 = ~(uint32_t)0; /* * Set native instance data. */ #ifdef __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 = KLDRPROT_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 defined(__WIN__) 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 = KLDRPROT_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 = 0; /* The section headers. */ for (i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++) { const char *pch; /* unused */ pMod->aSegments[i + 1].pvUser = NULL; pMod->aSegments[i + 1].MapAddress = 0; /* name */ pMod->aSegments[i + 1].pchName = pch = &paShdrs[i].Name[0]; cb = IMAGE_SIZEOF_SHORT_NAME; while ( cb > 0 && (pch[cb - 1] == ' ' || pch[cb - 1] == '\0')) cb--; pMod->aSegments[i + 1].cchName = cb; /* size and addresses */ if (!(paShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)) { pMod->aSegments[i + 1].cb = paShdrs[i].Misc.VirtualSize; pMod->aSegments[i + 1].LinkAddress = paShdrs[i].VirtualAddress + pNtHdrs->OptionalHeader.ImageBase; pMod->aSegments[i + 1].RVA = paShdrs[i].VirtualAddress; 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; } /* 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 = 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 = KLDRPROT_NOACCESS; break; case IMAGE_SCN_MEM_READ: case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED: pMod->aSegments[i + 1].enmProt = KLDRPROT_READONLY; break; case IMAGE_SCN_MEM_WRITE: case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ: pMod->aSegments[i + 1].enmProt = KLDRPROT_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 = KLDRPROT_READWRITE; break; case IMAGE_SCN_MEM_EXECUTE: case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_SHARED: pMod->aSegments[i + 1].enmProt = KLDRPROT_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 = KLDRPROT_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 = KLDRPROT_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 = KLDRPROT_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: kldrHlpAssert(0); pMod->aSegments[i + 1].Alignment = 0; break; } } #elif defined(__DARWIN__) /** @todo Figure out the Mac OS X dynamic loader. */ #else # error "Port me" #endif /* * We're done. */ *ppMod = pMod; return 0; } /** @copydoc KLDRMODOPS::pfnDestroy */ static int kldrModNativeDestroy(PKLDRMOD pMod) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; int rc; #ifdef __OS2__ rc = DosFreeModule(pModNative->hmod); #elif defined(__WIN__) if (FreeLibrary(pModNative->hmod)) rc = 0; else rc = GetLastError(); #elif defined(__DARWIN__) dlclose(pModNative->pvMod); #else # error "Port me" #endif pMod->u32Magic = 0; pMod->pOps = NULL; kldrHlpFree(pModNative); return rc; } /** @copydoc kLdrModQuerySymbol */ static int kldrModNativeQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t iSymbol, const char *pchSymbol, size_t cchSymbol, const char *pszVersion, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; const char *pszSymbol = pchSymbol; #ifdef __OS2__ APIRET rc; PFN pfn; #elif defined(__WIN__) FARPROC pfn; #elif defined(__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 = kLdrHlpAllocA(cchSymbol + 1); kLdrHlpMemCopy(pszCopy, pchSymbol, cchSymbol); pszCopy[cchSymbol] = '\0'; pszSymbol = pszCopy; } #ifdef __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 = (uintptr_t)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 defined(__WIN__) if (!pszSymbol && iSymbol >= 0x10000) return KLDR_ERR_SYMBOL_NOT_FOUND; pfn = GetProcAddress(pModNative->hmod, pszSymbol ? pszSymbol : (const char *)(uintptr_t)iSymbol); if (puValue) *puValue = (uintptr_t)pfn; if (pfKind) *pfKind = (pModNative->pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32) ? KLDRSYMKIND_32BIT : KLDRSYMKIND_16BIT) | KLDRSYMKIND_NO_TYPE; #elif defined(__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 = (uintptr_t)pfn; if (pfKind) *pfKind = (sizeof(uintptr_t) == 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, uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; #ifdef __OS2__ /** @todo implement export enumeration on OS/2. */ (void)pModNative; return ERROR_NOT_SUPPORTED; #elif defined(__WIN__) || defined(__NT__) const uint32_t *paFunctions; const IMAGE_EXPORT_DIRECTORY *pExpDir; const uint32_t *paRVANames; const uint16_t *paOrdinals; uint32_t iFunction; uint32_t cFunctions; uint32_t 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 uint32_t *); paOrdinals = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfNameOrdinals, const uint16_t *); paFunctions = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfFunctions, const uint32_t *); cFunctions = pExpDir->NumberOfFunctions; cNames = pExpDir->NumberOfNames; for (iFunction = 0; iFunction < cFunctions; iFunction++) { unsigned fFoundName; uint32_t iName; const uint32_t uRVA = paFunctions[iFunction]; const KLDRADDR uValue = BaseAddress + uRVA; uint32_t 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 defined(__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, uint32_t iImport, char *pszName, size_t cchName) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; #ifdef __OS2__ /** @todo implement import enumeration on OS/2. */ (void)pModNative; return ERROR_NOT_SUPPORTED; #elif defined(__WIN__) || defined(__NT__) const IMAGE_IMPORT_DESCRIPTOR *pImpDesc; const char *pszImportName; size_t cchImportName; int rc; /* * Simple bounds check. */ if (iImport >= (uint32_t)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 = kLdrHlpStrLen(pszImportName); if (cchImportName < cchName) { kLdrHlpMemCopy(pszName, pszImportName, cchImportName + 1); rc = 0; } else { kLdrHlpMemCopy(pszName, pszImportName, cchName); if (cchName) pszName[cchName - 1] = '\0'; rc = KLDR_ERR_BUFFER_OVERFLOW; } return rc; #elif defined(__DARWIN__) /** @todo Implement import enumeration on darwin. */ (void)pModNative; return KLDR_ERR_TODO; #else # error "Port me" #endif } /** @copydoc kLdrModNumberOfImports */ static int32_t kldrModNativeNumberOfImports(PKLDRMOD pMod, const void *pvBits) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; #ifdef __OS2__ /** @todo implement import counting on OS/2. */ (void)pModNative; return -1; #elif defined(__WIN__) || defined(__NT__) if (pModNative->cImportModules == ~(uint32_t)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 defined(__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; #ifdef __OS2__ /** @todo implement stack info on OS/2. */ (void)pModNative; return ERROR_NOT_SUPPORTED; #elif defined(__WIN__) || defined(__NT__) pStackInfo->Address = NIL_KLDRADDR; pStackInfo->LinkAddress = NIL_KLDRADDR; pStackInfo->cbStack = pStackInfo->cbStackThread = pModNative->pNtHdrs->OptionalHeader.SizeOfStackReserve; return 0; #elif defined(__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; #ifdef __OS2__ /** @todo implement me on OS/2. */ (void)pModNative; return ERROR_NOT_SUPPORTED; #elif defined(__WIN__) || defined(__NT__) /* * Convert the address from the header. */ *pMainEPAddress = pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint ? BaseAddress + pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint : NIL_KLDRADDR; return 0; #elif defined(__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; #ifdef __OS2__ /** @todo implement me on OS/2. */ (void)pModNative; return ERROR_NOT_SUPPORTED; #elif defined(__WIN__) || defined(__NT__) const IMAGE_DEBUG_DIRECTORY *pDbgDir; uint32_t iDbgInfo; uint32_t 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, pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1, pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR, pDbgDir->SizeOfData, NULL, pvUser); if (rc) break; /* next */ if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY)) break; } return rc; #elif defined(__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; #ifdef __OS2__ /** @todo implement me on OS/2. */ (void)pModNative; return KLDR_ERR_NO_DEBUG_INFO; #elif defined(__WIN__) || 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 defined(__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) { return 0; } /** @copydoc kLdrModFreeTLS */ static void kldrModNativeFreeTLS(PKLDRMOD pMod) { } /** @copydoc kLdrModReload */ static int kldrModNativeReload(PKLDRMOD pMod) { return 0; } /** @copydoc kLdrModFixupMapping */ static int kldrModNativeFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { return 0; } /** @copydoc kLdrModCallInit */ static int kldrModNativeCallInit(PKLDRMOD pMod, uintptr_t uHandle) { return 0; } /** @copydoc kLdrModCallTerm */ static int kldrModNativeCallTerm(PKLDRMOD pMod, uintptr_t uHandle) { return 0; } /** @copydoc kLdrModCallThread */ static int kldrModNativeCallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching) { return 0; } /** @copydoc kLdrModSize */ static KLDRADDR kldrModNativeSize(PKLDRMOD pMod) { #ifdef __OS2__ return 0; /* don't bother */ #elif defined(__WIN__) || defined(__NT__) /* just because we can. */ PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; return pModNative->pNtHdrs->OptionalHeader.SizeOfImage; #elif defined(__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) { #ifdef __OS2__ return ERROR_NOT_SUPPORTED; /* don't bother */ #elif defined(__WIN__) || defined(__NT__) return ERROR_NOT_SUPPORTED; /* don't bother even if we could implement this. */ #elif defined(__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) { #ifdef __OS2__ return ERROR_NOT_SUPPORTED; /* don't bother */ #elif defined(__WIN__) || defined(__NT__) return ERROR_NOT_SUPPORTED; /* don't bother even if we could implement this. */ #elif defined(__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 /* fixme */, NULL /* fixme */, kldrModNativeEnumDbgInfo, kldrModNativeHasDbgInfo, kldrModNativeMap, kldrModNativeUnmap, kldrModNativeAllocTLS, kldrModNativeFreeTLS, kldrModNativeReload, kldrModNativeFixupMapping, kldrModNativeCallInit, kldrModNativeCallTerm, kldrModNativeCallThread, kldrModNativeSize, kldrModNativeGetBits, kldrModNativeRelocateBits, NULL /* fixme */, 42 /* the end */ };