# HG changeset patch # User Tassilo Philipp # Date 1493898137 -7200 # Node ID 85b61e8facfe523a18ba66782018c98f60768770 # Parent cde7b1f3b8f24295b6a2ecfba8ce463d10a297b2 dynload: - added new function dlGetLibraryPath to get path of already loaded lib - covered new function in dynload_plain test - cleanups/cosmetics for consistency diff -r cde7b1f3b8f2 -r 85b61e8facfe dynload/dynload.h --- a/dynload/dynload.h Tue May 02 03:49:56 2017 +0200 +++ b/dynload/dynload.h Thu May 04 13:42:17 2017 +0200 @@ -36,17 +36,21 @@ #define DL_API #endif -/* --- public api ---------------------------------------------------------- */ /* shared library loading and explicit symbol resolving */ +/* dlLoadLibrary will search for specified lib (e.g. as leaf name, only), */ +/* to the platforms dynamic linking style */ typedef struct DLLib_ DLLib; -DL_API DLLib* dlLoadLibrary(const char* libpath); -DL_API void dlFreeLibrary(DLLib* pLib); -DL_API void* dlFindSymbol(DLLib* pLib, const char* pSymbolName); +DL_API DLLib* dlLoadLibrary (const char* libPath); +DL_API void dlFreeLibrary (DLLib* pLib); +DL_API void* dlFindSymbol (DLLib* pLib, const char* pSymbolName); +DL_API int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize); + /* symbol table enumeration - only for symbol lookup, not resolve */ +/* note that dlSymsInit does not search library paths */ typedef struct DLSyms_ DLSyms; diff -r cde7b1f3b8f2 -r 85b61e8facfe dynload/dynload_syms_mach-o.c --- a/dynload/dynload_syms_mach-o.c Tue May 02 03:49:56 2017 +0200 +++ b/dynload/dynload_syms_mach-o.c Thu May 04 13:42:17 2017 +0200 @@ -97,6 +97,7 @@ if(st0.st_ino == st1.st_ino/*!strcmp(name, libPath)*/) { pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(i); +//@@@ slide = _dyld_get_image_vmaddr_slide(i); break; /* found header */ } } diff -r cde7b1f3b8f2 -r 85b61e8facfe dynload/dynload_unix.c --- a/dynload/dynload_unix.c Tue May 02 03:49:56 2017 +0200 +++ b/dynload/dynload_unix.c Thu May 04 13:42:17 2017 +0200 @@ -6,7 +6,7 @@ Description: License: - Copyright (c) 2007-2015 Daniel Adler , + Copyright (c) 2007-2017 Daniel Adler , Tassilo Philipp Permission to use, copy, modify, and distribute this software for any @@ -24,7 +24,6 @@ */ - /* dynload_unix.c @@ -35,7 +34,14 @@ #include "dynload.h" +#include "../autovar/autovar_OS.h" +#include + +#if defined(__GLIBC__) /* to access dlinfo */ +# define _GNU_SOURCE +# define __USE_GNU +#endif #include @@ -45,20 +51,118 @@ } -void* dlFindSymbol(DLLib* libHandle, const char* symbol) +void* dlFindSymbol(DLLib* pLib, const char* pSymbolName) { - return dlsym((void*)libHandle, symbol); + return dlsym((void*)pLib, pSymbolName); +} + + +void dlFreeLibrary(DLLib* pLib) +{ + /* Check for NULL for cross-platform consistency. *BSD seems to do that in + dlclose, Linux does not. POSIX states "if handle does not refer to an open + object, dlclose() returns a non-zero value", which unfortunately sounds + like it's not explicitly specified. */ + if(pLib) + dlclose((void*)pLib); } -void dlFreeLibrary(DLLib* libHandle) +/* code for dlGetLibraryPath differs on Darwin */ +#if defined(OS_Darwin) + +#include +#include + +int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) { + uint32_t i; + int l = -1; + + /*if(pLib == RTLD_DEFAULT) + return NULL; @@@ return exec's path */ - /* Check for NULL for cross-platform consistency. *BSD seems to do that in - dlclose, Linux does not. POSIX states "if handle does not refer to an open - object, dlclose() returns a non-zero value", which unfortunately sounds - like it's not explicitly specified. */ - if(libHandle) - dlclose((void*)libHandle); + /* Darwin's code doesn't come with (non-standard) dlinfo(), so use dyld(1) */ + /* code. There doesn't seem to be a direct way to query the library path, */ + /* so "double-load" temporarily all already loaded images (just increases */ + /* ref count) and compare handles until we found ours. Return the name. */ + for(i=_dyld_image_count(); i>0;) /* iterate libs from end, more likely ours */ + { + const char* libPath = _dyld_get_image_name(--i); + void* lib = dlopen(libPath, RTLD_LAZY); + if(lib) { + dlclose(lib); + /* compare handle pointers' high bits (in low 2 bits some flags might */ + /* be stored - should be safe b/c address needs alignment, anywas) */ + if(((intptr_t)pLib ^ (intptr_t)lib) < 4) { + l = strlen(libPath); + if(l < bufSize) /* l+'\0' <= bufSize */ + strcpy(sOut, libPath); + break; + } + } + } + + return l+1; /* strlen + '\0' */ } +#else /* non-Darwin --> */ + +#if defined(OS_OpenBSD) /* doesn't have dlinfo() but dl_iterate_phdr() --> */ + +/* @@@ dl_iterate_phdr() only exists on OpenBSD >= 3.7 */ + +#include +#include + +typedef struct { + DLLib* pLib; + char* sOut; + int bufSize; +} iter_phdr_data; + +static int iter_phdr_cb(struct dl_phdr_info* info, size_t size, void* data) +{ + int l = -1; + iter_phdr_data* d = (iter_phdr_data*)data; + /* unable to relate info->dlpi_addr directly to our dlopen handle, let's */ + /* do what we do on macOS above, re-dlopen the already loaded lib (just */ + /* increases ref count) and compare handles. */ + void* lib = dlopen(info->dlpi_name, RTLD_LAZY); + if(lib) { + dlclose(lib); + if(lib == (void*)d->pLib) { + l = strlen(info->dlpi_name); + if(l < d->bufSize) /* l+'\0' <= bufSize */ + strcpy(d->sOut, info->dlpi_name); + } + } + return l+1; /* strlen + '\0'; is 0 if lib not found, which continues iter */ +} + +int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) +{ + iter_phdr_data d = { pLib, sOut, bufSize }; + return dl_iterate_phdr(iter_phdr_cb, &d); +} + +#else /* use dlinfo() --> */ + +#include + +int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) +{ + struct link_map* p; + int l = -1; + if(dlinfo(pLib, RTLD_DI_LINKMAP, &p) == 0) { + l = strlen(p->l_name); + if(l < bufSize) /* l+'\0' <= bufSize */ + strcpy(sOut, p->l_name); + } + return l+1; /* strlen + '\0' */ +} + +#endif + +#endif + diff -r cde7b1f3b8f2 -r 85b61e8facfe dynload/dynload_windows.c --- a/dynload/dynload_windows.c Tue May 02 03:49:56 2017 +0200 +++ b/dynload/dynload_windows.c Thu May 04 13:42:17 2017 +0200 @@ -44,13 +44,21 @@ return (DLLib*)(libPath != NULL ? LoadLibraryA(libPath) : GetModuleHandle(NULL)); } -void* dlFindSymbol(DLLib* libHandle, const char* symbol) + +void* dlFindSymbol(DLLib* pLib, const char* pSymbolName) { - return (void*) GetProcAddress((HINSTANCE)libHandle, symbol); + return (void*)GetProcAddress((HINSTANCE)pLib, pSymbolName); } -void dlFreeLibrary(DLLib* libHandle) + +void dlFreeLibrary(DLLib* pLib) { - FreeLibrary((HINSTANCE)libHandle); + FreeLibrary((HINSTANCE)pLib); } + +int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) +{ + return GetModuleFileNameA((HMODULE)pLib, sOut, bufSize)+1; /* strlen + '\0' */ +} + diff -r cde7b1f3b8f2 -r 85b61e8facfe test/dynload_plain/dynload_plain.c --- a/test/dynload_plain/dynload_plain.c Tue May 02 03:49:56 2017 +0200 +++ b/test/dynload_plain/dynload_plain.c Thu May 04 13:42:17 2017 +0200 @@ -27,6 +27,7 @@ #include "../common/platformInit.h" #include +#include #if defined(DC_WINDOWS) # include # define F_OK 0 @@ -42,17 +43,21 @@ DLLib* pLib; DLSyms* pSyms; const char* path = NULL; - const char* clibs[] = { // hacky/lazy list of some clib paths per platform + const char* clibs[] = { /* hacky/lazy list of some clib paths per platform */ "/lib/libc.so", "/lib/libc.so.6", "/lib/libc.so.7", + "/lib/libc.so.39.3", /* hack: for OpenBSD used in dyncall test env */ "/lib64/libc.so", "/lib64/libc.so.6", "/lib64/libc.so.7", "/lib32/libc.so", "/lib32/libc.so.6", "/lib32/libc.so.7", - "/usr/lib/system/libsystem_c.dylib", + "/usr/lib/libc.so", + "/usr/lib/libc.so.6", + "/usr/lib/libc.so.7", + "/usr/lib/system/libsystem_c.dylib", "/usr/lib/libc.dylib", "\\ReactOS\\system32\\msvcrt.dll", "C:\\ReactOS\\system32\\msvcrt.dll", @@ -72,26 +77,47 @@ printf("using clib to test at: %s\n", path); ++r; - // dl*Library tests - // -------- - pLib = dlLoadLibrary(path); // check if we can load a lib + /* dl*Library tests */ + /* ---------------- */ + pLib = dlLoadLibrary(path); /* check if we can load a lib */ if(pLib) { + char queriedPath[200]; /* enough for our test paths */ + int bs; + printf("pLib handle: %p\n", pLib); ++r; - p = dlFindSymbol(pLib, "printf"); // check if we can lookup a symbol + p = dlFindSymbol(pLib, "printf"); /* check if we can lookup a symbol */ printf("printf at: %p\n", p); r += (p != NULL); + bs = dlGetLibraryPath(pLib, queriedPath, 200); + if(bs && bs <= 200) { + struct stat st0, st1; /* to check if same file */ + int b; + printf("path of lib looked up via handle: %s\n", queriedPath); + b = (stat(path, &st0) != -1) && (stat(queriedPath, &st1) != -1); + printf("lib (inode:%d) and looked up lib (inode:%d) are same: %d\n", b?st0.st_ino:-1, b?st1.st_ino:-1, b && (st0.st_ino == st1.st_ino)); + r += b && (st0.st_ino == st1.st_ino); /* compare if same lib using inode */ +/*@@@ check of resolved path is absolute*/ + + /* check correct bufsize retval */ + b = (bs == strlen(queriedPath) + 1); + printf("looked up path's needed buffer size (%d) computed correctly: %d\n", bs, b); + r += b; + } + else + printf("failed to query lib path using lib's handle\n"); + dlFreeLibrary(pLib); } else printf("unable to open library %s\n", path); - // dlSyms* tests (intentionally after freeing lib above, as they work standalone) - // -------- - pSyms = dlSymsInit(path); // check if we can iterate over symbols - init + /* dlSyms* tests (intentionally after freeing lib above, as they work standalone) */ + /* ------------- */ + pSyms = dlSymsInit(path); /* check if we can iterate over symbols - init */ if(pSyms) { int n; const char* name; @@ -99,13 +125,13 @@ printf("pSyms handle: %p\n", pSyms); ++r; - n = dlSymsCount(pSyms); // check if there are some syms to iterate over + n = dlSymsCount(pSyms); /* check if there are some syms to iterate over */ printf("num of libc symbols: %d\n", n); r += (n > 0); for(i=0; i name, - if(pLib) { // need to lookup by name again, first + pLib = dlLoadLibrary(path); /* check if we can resolve ptr -> name, */ + if(pLib) { /* need to lookup by name again, first */ p = dlFindSymbol(pLib, "printf"); name = dlSymsNameFromValue(pSyms, p); printf("printf symbol name by its own address (%p): %s\n", p, name?name:""); @@ -131,8 +157,8 @@ printf("dlSymsInit failed\n"); } - // All worked if we got a score of 6 right ones - r = (r == 8); + /* Check final score of right ones to see if all worked */ + r = (r == 10); printf("result: dynload_plain: %d\n", r); return !r; }