diff --git a/.gitmodules b/.gitmodules index 9f18be11e..6acb3dc8a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,6 @@ [submodule "cxxopts"] path = libs/cxxopts url = https://github.com/jarro2783/cxxopts +[submodule "dlfcn-win32"] + path = libs/dlfcn-win32 + url = https://github.com/dlfcn-win32/dlfcn-win32 diff --git a/Makefile b/Makefile index 2dda052f9..1dc0cf531 100644 --- a/Makefile +++ b/Makefile @@ -415,7 +415,7 @@ endif ifeq ($(ENABLE_PLUGINS),1) CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags libffi) -DYOSYS_ENABLE_PLUGINS ifeq ($(OS), MINGW) -CXXFLAGS += -Ilibs/dlfcn-win32 +CXXFLAGS += -Ilibs/dlfcn-win32/src endif LIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) ifneq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD MINGW)) @@ -648,7 +648,7 @@ OBJS += kernel/fstdata.o endif ifeq ($(ENABLE_PLUGINS),1) ifeq ($(OS), MINGW) -OBJS += libs/dlfcn-win32/dlfcn.o +OBJS += libs/dlfcn-win32/src/dlfcn.o endif endif @@ -754,6 +754,10 @@ else $(P) $(CXX) -o libyosys.so -shared -Wl,-soname,$(LIBDIR)/libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC) endif +%.o: %.c + $(Q) mkdir -p $(dir $@) + $(P) $(CC) -o $@ -c $< + %.o: %.cc $(Q) mkdir -p $(dir $@) $(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< @@ -788,7 +792,7 @@ LIBS_NOVERIFIC = $(LIBS) endif $(PROGRAM_PREFIX)yosys-config: misc/yosys-config.in $(YOSYS_SRC)/Makefile - $(P) $(SED) -e 's#@CXXFLAGS@#$(subst -Ilibs/dlfcn-win32,,$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(strip $(CXXFLAGS_NOVERIFIC))))#;' \ + $(P) $(SED) -e 's#@CXXFLAGS@#$(subst -Ilibs/dlfcn-win32/src,,$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(strip $(CXXFLAGS_NOVERIFIC))))#;' \ -e 's#@CXX@#$(strip $(CXX))#;' -e 's#@LINKFLAGS@#$(strip $(LINKFLAGS) $(PLUGIN_LINKFLAGS))#;' -e 's#@LIBS@#$(strip $(LIBS_NOVERIFIC) $(PLUGIN_LIBS))#;' \ -e 's#@BINDIR@#$(strip $(BINDIR))#;' -e 's#@DATDIR@#$(strip $(DATDIR))#;' < $< > $(PROGRAM_PREFIX)yosys-config $(Q) chmod +x $(PROGRAM_PREFIX)yosys-config diff --git a/libs/dlfcn-win32 b/libs/dlfcn-win32 new file mode 160000 index 000000000..048bff80f --- /dev/null +++ b/libs/dlfcn-win32 @@ -0,0 +1 @@ +Subproject commit 048bff80f2bd00bb651bcc3357cb6f76e3d76fd5 diff --git a/libs/dlfcn-win32/dlfcn.cc b/libs/dlfcn-win32/dlfcn.cc deleted file mode 100644 index 03ed34dba..000000000 --- a/libs/dlfcn-win32/dlfcn.cc +++ /dev/null @@ -1,820 +0,0 @@ -/* - * dlfcn-win32 - * Copyright (c) 2007 Ramiro Polla - * Copyright (c) 2015 Tiancheng "Timothy" Gu - * Copyright (c) 2019 Pali Rohár - * Copyright (c) 2020 Ralf Habacker - * - * 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. - */ - -#ifdef _DEBUG -#define _CRTDBG_MAP_ALLOC -#include -#include -#endif -#include -#include -#include - -/* Older versions do not have this type */ -#if _WIN32_WINNT < 0x0500 -typedef ULONG ULONG_PTR; -#endif - -/* Older SDK versions do not have these macros */ -#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS -#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x4 -#endif -#ifndef GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT -#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 0x2 -#endif - -#ifdef _MSC_VER -/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */ -#pragma intrinsic( _ReturnAddress ) -#else -/* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */ -#ifndef _ReturnAddress -#define _ReturnAddress( ) ( __builtin_extract_return_addr( __builtin_return_address( 0 ) ) ) -#endif -#endif - -#ifdef DLFCN_WIN32_SHARED -#define DLFCN_WIN32_EXPORTS -#endif -#include "dlfcn.h" - -#if defined( _MSC_VER ) && _MSC_VER >= 1300 -/* https://docs.microsoft.com/en-us/cpp/cpp/noinline */ -#define DLFCN_NOINLINE __declspec( noinline ) -#elif defined( __GNUC__ ) && ( ( __GNUC__ > 3 ) || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 1 ) ) -/* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html */ -#define DLFCN_NOINLINE __attribute__(( noinline )) -#else -#define DLFCN_NOINLINE -#endif - -/* Note: - * MSDN says these functions are not thread-safe. We make no efforts to have - * any kind of thread safety. - */ - -typedef struct local_object { - HMODULE hModule; - struct local_object *previous; - struct local_object *next; -} local_object; - -static local_object first_object; - -/* These functions implement a double linked list for the local objects. */ -static local_object *local_search( HMODULE hModule ) -{ - local_object *pobject; - - if( hModule == NULL ) - return NULL; - - for( pobject = &first_object; pobject; pobject = pobject->next ) - if( pobject->hModule == hModule ) - return pobject; - - return NULL; -} - -static BOOL local_add( HMODULE hModule ) -{ - local_object *pobject; - local_object *nobject; - - if( hModule == NULL ) - return TRUE; - - pobject = local_search( hModule ); - - /* Do not add object again if it's already on the list */ - if( pobject != NULL ) - return TRUE; - - for( pobject = &first_object; pobject->next; pobject = pobject->next ); - - nobject = (local_object *) malloc( sizeof( local_object ) ); - - if( !nobject ) - return FALSE; - - pobject->next = nobject; - nobject->next = NULL; - nobject->previous = pobject; - nobject->hModule = hModule; - - return TRUE; -} - -static void local_rem( HMODULE hModule ) -{ - local_object *pobject; - - if( hModule == NULL ) - return; - - pobject = local_search( hModule ); - - if( pobject == NULL ) - return; - - if( pobject->next ) - pobject->next->previous = pobject->previous; - if( pobject->previous ) - pobject->previous->next = pobject->next; - - free( pobject ); -} - -/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one - * static buffer. - * MSDN says the buffer cannot be larger than 64K bytes, so we set it to - * the limit. - */ -static char error_buffer[65535]; -static BOOL error_occurred; - -static void save_err_str( const char *str, DWORD dwMessageId ) -{ - DWORD ret; - size_t pos, len; - - len = strlen( str ); - if( len > sizeof( error_buffer ) - 5 ) - len = sizeof( error_buffer ) - 5; - - /* Format error message to: - * "": - */ - pos = 0; - error_buffer[pos++] = '"'; - memcpy( error_buffer + pos, str, len ); - pos += len; - error_buffer[pos++] = '"'; - error_buffer[pos++] = ':'; - error_buffer[pos++] = ' '; - - ret = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwMessageId, - MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), - error_buffer + pos, (DWORD) ( sizeof( error_buffer ) - pos ), NULL ); - pos += ret; - - /* When FormatMessageA() fails it returns zero and does not touch buffer - * so add trailing null byte */ - if( ret == 0 ) - error_buffer[pos] = '\0'; - - if( pos > 1 ) - { - /* POSIX says the string must not have trailing */ - if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' ) - error_buffer[pos-2] = '\0'; - } - - error_occurred = TRUE; -} - -static void save_err_ptr_str( const void *ptr, DWORD dwMessageId ) -{ - char ptr_buf[2 + 2 * sizeof( ptr ) + 1]; - char num; - size_t i; - - ptr_buf[0] = '0'; - ptr_buf[1] = 'x'; - - for( i = 0; i < 2 * sizeof( ptr ); i++ ) - { - num = (char) ( ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF ); - ptr_buf[2 + i] = num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) ); - } - - ptr_buf[2 + 2 * sizeof( ptr )] = 0; - - save_err_str( ptr_buf, dwMessageId ); -} - -static UINT MySetErrorMode( UINT uMode ) -{ - static BOOL (WINAPI *SetThreadErrorModePtr)(DWORD, DWORD *) = NULL; - static BOOL failed = FALSE; - HMODULE kernel32; - DWORD oldMode; - - if( !failed && SetThreadErrorModePtr == NULL ) - { - kernel32 = GetModuleHandleA( "Kernel32.dll" ); - if( kernel32 != NULL ) - SetThreadErrorModePtr = (BOOL (WINAPI *)(DWORD, DWORD *)) (LPVOID) GetProcAddress( kernel32, "SetThreadErrorMode" ); - if( SetThreadErrorModePtr == NULL ) - failed = TRUE; - } - - if( !failed ) - { - if( !SetThreadErrorModePtr( uMode, &oldMode ) ) - return 0; - else - return oldMode; - } - else - { - return SetErrorMode( uMode ); - } -} - -static HMODULE MyGetModuleHandleFromAddress( const void *addr ) -{ - static BOOL (WINAPI *GetModuleHandleExAPtr)(DWORD, LPCSTR, HMODULE *) = NULL; - static BOOL failed = FALSE; - HMODULE kernel32; - HMODULE hModule; - MEMORY_BASIC_INFORMATION info; - SIZE_T sLen; - - if( !failed && GetModuleHandleExAPtr == NULL ) - { - kernel32 = GetModuleHandleA( "Kernel32.dll" ); - if( kernel32 != NULL ) - GetModuleHandleExAPtr = (BOOL (WINAPI *)(DWORD, LPCSTR, HMODULE *)) (LPVOID) GetProcAddress( kernel32, "GetModuleHandleExA" ); - if( GetModuleHandleExAPtr == NULL ) - failed = TRUE; - } - - if( !failed ) - { - /* If GetModuleHandleExA is available use it with GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS */ - if( !GetModuleHandleExAPtr( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (const char *)addr, &hModule ) ) - return NULL; - } - else - { - /* To get HMODULE from address use undocumented hack from https://stackoverflow.com/a/2396380 - * The HMODULE of a DLL is the same value as the module's base address. - */ - sLen = VirtualQuery( addr, &info, sizeof( info ) ); - if( sLen != sizeof( info ) ) - return NULL; - hModule = (HMODULE) info.AllocationBase; - } - - return hModule; -} - -/* Load Psapi.dll at runtime, this avoids linking caveat */ -static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ) -{ - static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD) = NULL; - static BOOL failed = FALSE; - UINT uMode; - HMODULE psapi; - - if( failed ) - return FALSE; - - if( EnumProcessModulesPtr == NULL ) - { - /* Windows 7 and newer versions have K32EnumProcessModules in Kernel32.dll which is always pre-loaded */ - psapi = GetModuleHandleA( "Kernel32.dll" ); - if( psapi != NULL ) - EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( psapi, "K32EnumProcessModules" ); - - /* Windows Vista and older version have EnumProcessModules in Psapi.dll which needs to be loaded */ - if( EnumProcessModulesPtr == NULL ) - { - /* Do not let Windows display the critical-error-handler message box */ - uMode = MySetErrorMode( SEM_FAILCRITICALERRORS ); - psapi = LoadLibraryA( "Psapi.dll" ); - if( psapi != NULL ) - { - EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( psapi, "EnumProcessModules" ); - if( EnumProcessModulesPtr == NULL ) - FreeLibrary( psapi ); - } - MySetErrorMode( uMode ); - } - - if( EnumProcessModulesPtr == NULL ) - { - failed = TRUE; - return FALSE; - } - } - - return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded ); -} - -DLFCN_EXPORT -void *dlopen( const char *file, int mode ) -{ - HMODULE hModule; - UINT uMode; - - error_occurred = FALSE; - - /* Do not let Windows display the critical-error-handler message box */ - uMode = MySetErrorMode( SEM_FAILCRITICALERRORS ); - - if( file == NULL ) - { - /* POSIX says that if the value of file is NULL, a handle on a global - * symbol object must be provided. That object must be able to access - * all symbols from the original program file, and any objects loaded - * with the RTLD_GLOBAL flag. - * The return value from GetModuleHandle( ) allows us to retrieve - * symbols only from the original program file. EnumProcessModules() is - * used to access symbols from other libraries. For objects loaded - * with the RTLD_LOCAL flag, we create our own list later on. They are - * excluded from EnumProcessModules() iteration. - */ - hModule = GetModuleHandle( NULL ); - - if( !hModule ) - save_err_str( "(null)", GetLastError( ) ); - } - else - { - HANDLE hCurrentProc; - DWORD dwProcModsBefore, dwProcModsAfter; - char lpFileName[MAX_PATH]; - size_t i, len; - - len = strlen( file ); - - if( len >= sizeof( lpFileName ) ) - { - save_err_str( file, ERROR_FILENAME_EXCED_RANGE ); - hModule = NULL; - } - else - { - /* MSDN says backslashes *must* be used instead of forward slashes. */ - for( i = 0; i < len; i++ ) - { - if( file[i] == '/' ) - lpFileName[i] = '\\'; - else - lpFileName[i] = file[i]; - } - lpFileName[len] = '\0'; - - hCurrentProc = GetCurrentProcess( ); - - if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 ) - dwProcModsBefore = 0; - - /* POSIX says the search path is implementation-defined. - * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely - * to UNIX's search paths (start with system folders instead of current - * folder). - */ - hModule = LoadLibraryExA( lpFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ); - - if( !hModule ) - { - save_err_str( lpFileName, GetLastError( ) ); - } - else - { - if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 ) - dwProcModsAfter = 0; - - /* If the object was loaded with RTLD_LOCAL, add it to list of local - * objects, so that its symbols cannot be retrieved even if the handle for - * the original program file is passed. POSIX says that if the same - * file is specified in multiple invocations, and any of them are - * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the - * symbols will remain global. If number of loaded modules was not - * changed after calling LoadLibraryEx(), it means that library was - * already loaded. - */ - if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter ) - { - if( !local_add( hModule ) ) - { - save_err_str( lpFileName, ERROR_NOT_ENOUGH_MEMORY ); - FreeLibrary( hModule ); - hModule = NULL; - } - } - else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter ) - { - local_rem( hModule ); - } - } - } - } - - /* Return to previous state of the error-mode bit flags. */ - MySetErrorMode( uMode ); - - return (void *) hModule; -} - -DLFCN_EXPORT -int dlclose( void *handle ) -{ - HMODULE hModule = (HMODULE) handle; - BOOL ret; - - error_occurred = FALSE; - - ret = FreeLibrary( hModule ); - - /* If the object was loaded with RTLD_LOCAL, remove it from list of local - * objects. - */ - if( ret ) - local_rem( hModule ); - else - save_err_ptr_str( handle, GetLastError( ) ); - - /* dlclose's return value in inverted in relation to FreeLibrary's. */ - ret = !ret; - - return (int) ret; -} - -DLFCN_NOINLINE /* Needed for _ReturnAddress() */ -DLFCN_EXPORT -void *dlsym( void *handle, const char *name ) -{ - FARPROC symbol; - HMODULE hCaller; - HMODULE hModule; - DWORD dwMessageId; - - error_occurred = FALSE; - - symbol = NULL; - hCaller = NULL; - hModule = GetModuleHandle( NULL ); - dwMessageId = 0; - - if( handle == RTLD_DEFAULT ) - { - /* The symbol lookup happens in the normal global scope; that is, - * a search for a symbol using this handle would find the same - * definition as a direct use of this symbol in the program code. - * So use same lookup procedure as when filename is NULL. - */ - handle = hModule; - } - else if( handle == RTLD_NEXT ) - { - /* Specifies the next object after this one that defines name. - * This one refers to the object containing the invocation of dlsym(). - * The next object is the one found upon the application of a load - * order symbol resolution algorithm. To get caller function of dlsym() - * use _ReturnAddress() intrinsic. To get HMODULE of caller function - * use MyGetModuleHandleFromAddress() which calls either standard - * GetModuleHandleExA() function or hack via VirtualQuery(). - */ - hCaller = MyGetModuleHandleFromAddress( _ReturnAddress( ) ); - - if( hCaller == NULL ) - { - dwMessageId = ERROR_INVALID_PARAMETER; - goto end; - } - } - - if( handle != RTLD_NEXT ) - { - symbol = GetProcAddress( (HMODULE) handle, name ); - - if( symbol != NULL ) - goto end; - } - - /* If the handle for the original program file is passed, also search - * in all globally loaded objects. - */ - - if( hModule == handle || handle == RTLD_NEXT ) - { - HANDLE hCurrentProc; - HMODULE *modules; - DWORD cbNeeded; - DWORD dwSize; - size_t i; - - hCurrentProc = GetCurrentProcess( ); - - /* GetModuleHandle( NULL ) only returns the current program file. So - * if we want to get ALL loaded module including those in linked DLLs, - * we have to use EnumProcessModules( ). - */ - if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 ) - { - modules = (HMODULE *)malloc( dwSize ); - if( modules ) - { - if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded ) - { - for( i = 0; i < dwSize / sizeof( HMODULE ); i++ ) - { - if( handle == RTLD_NEXT && hCaller ) - { - /* Next modules can be used for RTLD_NEXT */ - if( hCaller == modules[i] ) - hCaller = NULL; - continue; - } - if( local_search( modules[i] ) ) - continue; - symbol = GetProcAddress( modules[i], name ); - if( symbol != NULL ) - { - free( modules ); - goto end; - } - } - - } - free( modules ); - } - else - { - dwMessageId = ERROR_NOT_ENOUGH_MEMORY; - goto end; - } - } - } - -end: - if( symbol == NULL ) - { - if( !dwMessageId ) - dwMessageId = ERROR_PROC_NOT_FOUND; - save_err_str( name, dwMessageId ); - } - - return *(void **) (&symbol); -} - -DLFCN_EXPORT -char *dlerror( void ) -{ - /* If this is the second consecutive call to dlerror, return NULL */ - if( !error_occurred ) - return NULL; - - /* POSIX says that invoking dlerror( ) a second time, immediately following - * a prior invocation, shall result in NULL being returned. - */ - error_occurred = FALSE; - - return error_buffer; -} - -/* See https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2 - * for details */ - -/* Get specific image section */ -static BOOL get_image_section( HMODULE module, int index, void **ptr, DWORD *size ) -{ - IMAGE_DOS_HEADER *dosHeader; - IMAGE_NT_HEADERS *ntHeaders; - IMAGE_OPTIONAL_HEADER *optionalHeader; - - dosHeader = (IMAGE_DOS_HEADER *) module; - - if( dosHeader->e_magic != IMAGE_DOS_SIGNATURE ) - return FALSE; - - ntHeaders = (IMAGE_NT_HEADERS *) ( (BYTE *) dosHeader + dosHeader->e_lfanew ); - - if( ntHeaders->Signature != IMAGE_NT_SIGNATURE ) - return FALSE; - - optionalHeader = &ntHeaders->OptionalHeader; - - if( optionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC ) - return FALSE; - - if( index < 0 || index > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ) - return FALSE; - - if( optionalHeader->DataDirectory[index].Size == 0 || optionalHeader->DataDirectory[index].VirtualAddress == 0 ) - return FALSE; - - if( size != NULL ) - *size = optionalHeader->DataDirectory[index].Size; - - *ptr = (void *)( (BYTE *) module + optionalHeader->DataDirectory[index].VirtualAddress ); - - return TRUE; -} - -/* Return symbol name for a given address from export table */ -static const char *get_export_symbol_name( HMODULE module, IMAGE_EXPORT_DIRECTORY *ied, const void *addr, void **func_address ) -{ - DWORD i; - void *candidateAddr = NULL; - int candidateIndex = -1; - BYTE *base = (BYTE *) module; - DWORD *functionAddressesOffsets = (DWORD *) (base + ied->AddressOfFunctions); - DWORD *functionNamesOffsets = (DWORD *) (base + ied->AddressOfNames); - USHORT *functionNameOrdinalsIndexes = (USHORT *) (base + ied->AddressOfNameOrdinals); - - for( i = 0; i < ied->NumberOfFunctions; i++ ) - { - if( (void *) ( base + functionAddressesOffsets[i] ) > addr || candidateAddr >= (void *) ( base + functionAddressesOffsets[i] ) ) - continue; - - candidateAddr = (void *) ( base + functionAddressesOffsets[i] ); - candidateIndex = i; - } - - if( candidateIndex == -1 ) - return NULL; - - *func_address = candidateAddr; - - for( i = 0; i < ied->NumberOfNames; i++ ) - { - if( functionNameOrdinalsIndexes[i] == candidateIndex ) - return (const char *) ( base + functionNamesOffsets[i] ); - } - - return NULL; -} - -static BOOL is_valid_address( const void *addr ) -{ - MEMORY_BASIC_INFORMATION info; - SIZE_T result; - - if( addr == NULL ) - return FALSE; - - /* check valid pointer */ - result = VirtualQuery( addr, &info, sizeof( info ) ); - - if( result == 0 || info.AllocationBase == NULL || info.AllocationProtect == 0 || info.AllocationProtect == PAGE_NOACCESS ) - return FALSE; - - return TRUE; -} - -/* Return state if address points to an import thunk - * - * An import thunk is setup with a 'jmp' instruction followed by an - * absolute address (32bit) or relative offset (64bit) pointing into - * the import address table (iat), which is partially maintained by - * the runtime linker. - */ -static BOOL is_import_thunk( const void *addr ) -{ - return *(short *) addr == 0x25ff ? TRUE : FALSE; -} - -/* Return adress from the import address table (iat), - * if the original address points to a thunk table entry. - */ -static void *get_address_from_import_address_table( void *iat, DWORD iat_size, const void *addr ) -{ - BYTE *thkp = (BYTE *) addr; - /* Get offset from thunk table (after instruction 0xff 0x25) - * 4018c8 <_VirtualQuery>: ff 25 4a 8a 00 00 - */ - ULONG offset = *(ULONG *)( thkp + 2 ); -#ifdef _WIN64 - /* On 64 bit the offset is relative - * 4018c8: ff 25 4a 8a 00 00 jmpq *0x8a4a(%rip) # 40a318 <__imp_VirtualQuery> - * And can be also negative (MSVC in WDK) - * 100002f20: ff 25 3a e1 ff ff jmpq *-0x1ec6(%rip) # 0x100001060 - * So cast to signed LONG type - */ - BYTE *ptr = (BYTE *)( thkp + 6 + (LONG) offset ); -#else - /* On 32 bit the offset is absolute - * 4019b4: ff 25 90 71 40 00 jmp *0x40719 - */ - BYTE *ptr = (BYTE *) offset; -#endif - - if( !is_valid_address( ptr ) || ptr < (BYTE *) iat || ptr > (BYTE *) iat + iat_size ) - return NULL; - - return *(void **) ptr; -} - -/* Holds module filename */ -static char module_filename[2*MAX_PATH]; - -static BOOL fill_info( const void *addr, Dl_info *info ) -{ - HMODULE hModule; - DWORD dwSize; - IMAGE_EXPORT_DIRECTORY *ied; - void *funcAddress = NULL; - - /* Get module of the specified address */ - hModule = MyGetModuleHandleFromAddress( addr ); - - if( hModule == NULL ) - return FALSE; - - dwSize = GetModuleFileNameA( hModule, module_filename, sizeof( module_filename ) ); - - if( dwSize == 0 || dwSize == sizeof( module_filename ) ) - return FALSE; - - info->dli_fname = module_filename; - info->dli_fbase = (void *) hModule; - - /* Find function name and function address in module's export table */ - if( get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_EXPORT, (void **) &ied, NULL ) ) - info->dli_sname = get_export_symbol_name( hModule, ied, addr, &funcAddress ); - else - info->dli_sname = NULL; - - info->dli_saddr = info->dli_sname == NULL ? NULL : funcAddress != NULL ? funcAddress : (void *) addr; - - return TRUE; -} - -DLFCN_EXPORT -int dladdr( const void *addr, Dl_info *info ) -{ - if( info == NULL ) - return 0; - - if( !is_valid_address( addr ) ) - return 0; - - if( is_import_thunk( addr ) ) - { - void *iat; - DWORD iatSize; - HMODULE hModule; - - /* Get module of the import thunk address */ - hModule = MyGetModuleHandleFromAddress( addr ); - - if( hModule == NULL ) - return 0; - - if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) ) - { - /* Fallback for cases where the iat is not defined, - * for example i586-mingw32msvc-gcc */ - IMAGE_IMPORT_DESCRIPTOR *iid; - DWORD iidSize; - - if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IMPORT, (void **) &iid, &iidSize ) ) - return 0; - - if( iid == NULL || iid->Characteristics == 0 || iid->FirstThunk == 0 ) - return 0; - - iat = (void *)( (BYTE *) hModule + iid->FirstThunk ); - /* We assume that in this case iid and iat's are in linear order */ - iatSize = iidSize - (DWORD) ( (BYTE *) iat - (BYTE *) iid ); - } - - addr = get_address_from_import_address_table( iat, iatSize, addr ); - - if( !is_valid_address( addr ) ) - return 0; - } - - if( !fill_info( addr, info ) ) - return 0; - - return 1; -} - -#ifdef DLFCN_WIN32_SHARED -BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) -{ - (void) hinstDLL; - (void) fdwReason; - (void) lpvReserved; - return TRUE; -} -#endif diff --git a/libs/dlfcn-win32/dlfcn.h b/libs/dlfcn-win32/dlfcn.h deleted file mode 100644 index bf5c7d4d1..000000000 --- a/libs/dlfcn-win32/dlfcn.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * dlfcn-win32 - * Copyright (c) 2007 Ramiro Polla - * - * 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. - */ - -#ifndef DLFCN_H -#define DLFCN_H - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(DLFCN_WIN32_SHARED) -#if defined(DLFCN_WIN32_EXPORTS) -# define DLFCN_EXPORT __declspec(dllexport) -#else -# define DLFCN_EXPORT __declspec(dllimport) -#endif -#else -# define DLFCN_EXPORT -#endif - -/* Relocations are performed when the object is loaded. */ -#define RTLD_NOW 0 - -/* Relocations are performed at an implementation-defined time. - * Windows API does not support lazy symbol resolving (when first reference - * to a given symbol occurs). So RTLD_LAZY implementation is same as RTLD_NOW. - */ -#define RTLD_LAZY RTLD_NOW - -/* All symbols are available for relocation processing of other modules. */ -#define RTLD_GLOBAL (1 << 1) - -/* All symbols are not made available for relocation processing by other modules. */ -#define RTLD_LOCAL (1 << 2) - -/* These two were added in The Open Group Base Specifications Issue 6. - * Note: All other RTLD_* flags in any dlfcn.h are not standard compliant. - */ - -/* The symbol lookup happens in the normal global scope. */ -#define RTLD_DEFAULT ((void *)0) - -/* Specifies the next object after this one that defines name. */ -#define RTLD_NEXT ((void *)-1) - -/* Structure filled in by dladdr() */ -typedef struct dl_info -{ - const char *dli_fname; /* Filename of defining object (thread unsafe and reused on every call to dladdr) */ - void *dli_fbase; /* Load address of that object */ - const char *dli_sname; /* Name of nearest lower symbol */ - void *dli_saddr; /* Exact value of nearest symbol */ -} Dl_info; - -/* Open a symbol table handle. */ -DLFCN_EXPORT void *dlopen(const char *file, int mode); - -/* Close a symbol table handle. */ -DLFCN_EXPORT int dlclose(void *handle); - -/* Get the address of a symbol from a symbol table handle. */ -DLFCN_EXPORT void *dlsym(void *handle, const char *name); - -/* Get diagnostic information. */ -DLFCN_EXPORT char *dlerror(void); - -/* Translate address to symbolic information (no POSIX standard) */ -DLFCN_EXPORT int dladdr(const void *addr, Dl_info *info); - -#ifdef __cplusplus -} -#endif - -#endif /* DLFCN_H */