From 872009336e131fac0d614d904eb2e28ead3ea794 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 22 Mar 2020 22:09:23 -0700 Subject: [PATCH 01/13] OSX fix osdFindSymbol RTLD_DEFAULT isn't zero on OSX --- modules/libcom/src/osi/os/posix/osdFindSymbol.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/libcom/src/osi/os/posix/osdFindSymbol.c b/modules/libcom/src/osi/os/posix/osdFindSymbol.c index acfc405e5..084865341 100644 --- a/modules/libcom/src/osi/os/posix/osdFindSymbol.c +++ b/modules/libcom/src/osi/os/posix/osdFindSymbol.c @@ -11,6 +11,12 @@ #define epicsExportSharedSymbols #include "epicsFindSymbol.h" +/* non-POSIX extension available on Linux (glibc at least) and OSX. + */ +#ifndef RTLD_DEFAULT +# define RTLD_DEFAULT 0 +#endif + epicsShareFunc void * epicsLoadLibrary(const char *name) { return dlopen(name, RTLD_LAZY | RTLD_GLOBAL); @@ -23,5 +29,5 @@ epicsShareFunc const char *epicsLoadError(void) epicsShareFunc void * epicsShareAPI epicsFindSymbol(const char *name) { - return dlsym(0, name); + return dlsym(RTLD_DEFAULT, name); } From d3b2298bcba2050932998457dbb081917a2752df Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 21 Mar 2020 22:13:53 -0700 Subject: [PATCH 02/13] WIN32 fix epicsFindSymbol() error propagation And use thread local to hold error code/message. --- .../libcom/src/osi/os/WIN32/osdFindSymbol.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c index 6de3c428e..c7553896d 100644 --- a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c +++ b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c @@ -11,7 +11,16 @@ #define epicsExportSharedSymbols #include "epicsFindSymbol.h" -static int epicsLoadErrorCode = 0; +#ifdef _MSC_VER +# define STORE static __declspec( thread ) +#elif __GNUC__ +# define STORE static __thread +#else +# define STORE static +#endif + +STORE +int epicsLoadErrorCode = 0; epicsShareFunc void * epicsLoadLibrary(const char *name) { @@ -28,7 +37,7 @@ epicsShareFunc void * epicsLoadLibrary(const char *name) epicsShareFunc const char *epicsLoadError(void) { - static char buffer[100]; + STORE char buffer[100]; FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, @@ -42,5 +51,9 @@ epicsShareFunc const char *epicsLoadError(void) epicsShareFunc void * epicsShareAPI epicsFindSymbol(const char *name) { - return GetProcAddress(0, name); + void* ret = GetProcAddress(0, name); + if(!ret) { + epicsLoadErrorCode = GetLastError(); + } + return ret; } From 24df056bcbdc223578ba0f14d9c72755054177fe Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 22 Mar 2020 08:33:42 -0700 Subject: [PATCH 03/13] WIN32 fix epicsFindSymbol() Passing zero as to GetProcAddress is undocumented, but seems to be equivalent to passing GetModuleHandle(NULL) which searches only the address space of the executable file. Emulate the effect of dlsym(0, ...) by searching all loaded modules. Probably not so efficient... --- .../libcom/src/osi/os/WIN32/osdFindSymbol.c | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c index c7553896d..19dc5e59a 100644 --- a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c +++ b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c @@ -5,8 +5,13 @@ \*************************************************************************/ /* osi/os/WIN32/osdFindSymbol.c */ +/* avoid need to link against psapi.dll + * requires windows 7 or later + */ +#define NTDDI_VERSION NTDDI_WIN7 #include +#include #define epicsExportSharedSymbols #include "epicsFindSymbol.h" @@ -51,8 +56,22 @@ epicsShareFunc const char *epicsLoadError(void) epicsShareFunc void * epicsShareAPI epicsFindSymbol(const char *name) { - void* ret = GetProcAddress(0, name); + HMODULE dlls[128]; + DWORD ndlls=0u, i; + void* ret = NULL; + + /* As a handle returned by LoadLibrary() isn't available to us, + * try all loaded modules in arbitrary order. + */ + if(K32EnumProcessModules(GetCurrentProcess(), dlls, sizeof(dlls), &ndlls)) { + for(i=0; !ret && i Date: Sat, 21 Mar 2020 12:21:09 -0700 Subject: [PATCH 04/13] add epicsLoadTest --- modules/libcom/test/Makefile | 10 +++ modules/libcom/test/epicsLoadTest.cpp | 91 +++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 modules/libcom/test/epicsLoadTest.cpp diff --git a/modules/libcom/test/Makefile b/modules/libcom/test/Makefile index cf55760a6..3457b1057 100755 --- a/modules/libcom/test/Makefile +++ b/modules/libcom/test/Makefile @@ -260,6 +260,16 @@ iocshTest_SRCS += iocshTest.cpp TESTS += iocshTest TESTFILES += $(wildcard ../iocshTest*.cmd) +TESTPROD_HOST += epicsLoadTest +epicsLoadTest_SRCS += epicsLoadTest.cpp +# test linked against static libCom? +epicsLoadTest_CPPFLAGS_STATIC_YES = -DLINKING_STATIC +epicsLoadTest_CPPFLAGS += $(epicsLoadTest_CPPFLAGS_STATIC_$(STATIC_BUILD)) +# are dynamic libraries built? +epicsLoadTest_CPPFLAGS_SHARED_YES = -DBUILDING_SHARED_LIBRARIES +epicsLoadTest_CPPFLAGS += $(epicsLoadTest_CPPFLAGS_SHARED_$(SHARED_LIBRARIES)) +TESTS += epicsLoadTest + # The testHarness runs all the test programs in a known working order. testHarness_SRCS += epicsRunLibComTests.c diff --git a/modules/libcom/test/epicsLoadTest.cpp b/modules/libcom/test/epicsLoadTest.cpp new file mode 100644 index 000000000..809081072 --- /dev/null +++ b/modules/libcom/test/epicsLoadTest.cpp @@ -0,0 +1,91 @@ +/*************************************************************************\ +* Copyright (c) 2020 Michael Davidsaver +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include + +#include + +#include "epicsUnitTest.h" +#include "testMain.h" + +#include "envDefs.h" +#include "epicsFindSymbol.h" +#include "epicsThread.h" + +namespace { + +// lookup a symbol from libCom +// which this executable is linked against (maybe statically) +// Doesn't work for static builds on windows +void loadCom() +{ + testDiag("Lookup symbol from Com"); + +#if defined (_WIN32) && defined(LINKING_STATIC) + testTodoBegin("windows static build"); +#endif + + void* ptr = epicsFindSymbol("epicsThreadGetCPUs"); + testOk(ptr==(void*)&epicsThreadGetCPUs, + "%p == %p (epicsThreadGetCPUs) : %s", + ptr, (void*)&epicsThreadGetCPUs, + epicsLoadError()); + + testTodoEnd(); +} + +void loadCA() +{ + testDiag("Load and lookup symbol from libca"); + + std::string libname; + { + std::ostringstream strm; + // running in eg. modules/libcom/test/O.linux-x86_64-debug +#ifdef _WIN32 + strm<<"..\\..\\..\\..\\bin\\"< Date: Wed, 8 Apr 2020 15:27:21 -0700 Subject: [PATCH 05/13] WIN32: epicsLoadError() strip trailing newlines --- modules/libcom/src/osi/os/WIN32/osdFindSymbol.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c index 19dc5e59a..743404611 100644 --- a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c +++ b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c @@ -43,14 +43,23 @@ epicsShareFunc void * epicsLoadLibrary(const char *name) epicsShareFunc const char *epicsLoadError(void) { STORE char buffer[100]; + DWORD n; - FormatMessage( + n = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, epicsLoadErrorCode, 0, buffer, sizeof(buffer)-1, NULL ); + + /* n - number of chars stored excluding nil. + * + * Some messages include a trailing newline, which we strip. + */ + for(; n>=1 && (buffer[n-1]=='\n' || buffer[n-1]=='\r'); n--) + buffer[n-1] = '\0'; + return buffer; } From db2cd68ce3ac9cf0b26a1505a5a39f368b103e7a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 31 Mar 2020 22:24:31 -0700 Subject: [PATCH 06/13] WIN32: osdFindSymbol() use psapi --- configure/os/CONFIG.linux-x86.win32-x86-mingw | 2 +- configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw | 2 +- modules/libcom/src/osi/os/WIN32/osdFindSymbol.c | 13 +++++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/configure/os/CONFIG.linux-x86.win32-x86-mingw b/configure/os/CONFIG.linux-x86.win32-x86-mingw index bd75f5ebd..655b33f23 100644 --- a/configure/os/CONFIG.linux-x86.win32-x86-mingw +++ b/configure/os/CONFIG.linux-x86.win32-x86-mingw @@ -21,4 +21,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \ GNU_LDLIBS_YES = # Link with system libraries -OP_SYS_LDLIBS = -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp +OP_SYS_LDLIBS = -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp diff --git a/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw b/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw index a08f19902..8430011c4 100644 --- a/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw +++ b/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw @@ -32,4 +32,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \ GNU_LDLIBS_YES = # Link with system libraries -OP_SYS_LDLIBS = -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp +OP_SYS_LDLIBS = -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp diff --git a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c index 743404611..80b3c292b 100644 --- a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c +++ b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c @@ -5,10 +5,15 @@ \*************************************************************************/ /* osi/os/WIN32/osdFindSymbol.c */ -/* avoid need to link against psapi.dll - * requires windows 7 or later +/* Avoid need to link against psapi.dll. requires windows 7 or later. + * MinGW doesn't provide wrappers until 6.0, so fallback to psapi.dll */ -#define NTDDI_VERSION NTDDI_WIN7 +#ifdef _MSC_VER +# define NTDDI_VERSION NTDDI_WIN7 +# define epicsEnumProcessModules K32EnumProcessModules +#else +# define epicsEnumProcessModules EnumProcessModules +#endif #include #include @@ -72,7 +77,7 @@ epicsShareFunc void * epicsShareAPI epicsFindSymbol(const char *name) /* As a handle returned by LoadLibrary() isn't available to us, * try all loaded modules in arbitrary order. */ - if(K32EnumProcessModules(GetCurrentProcess(), dlls, sizeof(dlls), &ndlls)) { + if(epicsEnumProcessModules(GetCurrentProcess(), dlls, sizeof(dlls), &ndlls)) { for(i=0; !ret && i Date: Sat, 18 Apr 2020 07:33:57 -0700 Subject: [PATCH 07/13] WIN32: GetLastError() returns DWORD --- modules/libcom/src/osi/os/WIN32/osdFindSymbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c index 80b3c292b..2753f0959 100644 --- a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c +++ b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c @@ -30,7 +30,7 @@ #endif STORE -int epicsLoadErrorCode = 0; +DWORD epicsLoadErrorCode = 0; epicsShareFunc void * epicsLoadLibrary(const char *name) { From aa7c2a647c054fb6417da635efcf1f3a724b5eba Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 18 Apr 2020 07:35:21 -0700 Subject: [PATCH 08/13] fix epicsLoadError() FORMAT_MESSAGE_IGNORE_INSERTS as no va_list is provided. Handle possibility of n=0 if unable to lookup error. --- .../libcom/src/osi/os/WIN32/osdFindSymbol.c | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c index 2753f0959..6c1fb401c 100644 --- a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c +++ b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c @@ -51,19 +51,27 @@ epicsShareFunc const char *epicsLoadError(void) DWORD n; n = FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM, + FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, epicsLoadErrorCode, 0, buffer, sizeof(buffer)-1, NULL ); - /* n - number of chars stored excluding nil. - * - * Some messages include a trailing newline, which we strip. - */ - for(; n>=1 && (buffer[n-1]=='\n' || buffer[n-1]=='\r'); n--) - buffer[n-1] = '\0'; + if(n) { + /* n - number of chars stored excluding nil. + * + * Some messages include a trailing newline, which we strip. + */ + for(; n>=1 && (buffer[n-1]=='\n' || buffer[n-1]=='\r'); n--) + buffer[n-1] = '\0'; + } else { + epicsSnprintf(buffer, sizeof(buffer), + "Unable to format WIN32 error code %lu", + (unsigned long)epicsLoadErrorCode); + buffer[sizeof(buffer)-1] = '\0'; + + } return buffer; } From 9edb9c2050490d405f673da689e6e47309f15635 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 18 Apr 2020 08:18:03 -0700 Subject: [PATCH 09/13] WIN32: epicsFindSymbol() fix use of EnumProcessModules() --- .../libcom/src/osi/os/WIN32/osdFindSymbol.c | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c index 6c1fb401c..c8c74b56d 100644 --- a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c +++ b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c @@ -19,6 +19,7 @@ #include #define epicsExportSharedSymbols +#include "epicsStdio.h" #include "epicsFindSymbol.h" #ifdef _MSC_VER @@ -78,23 +79,44 @@ epicsShareFunc const char *epicsLoadError(void) epicsShareFunc void * epicsShareAPI epicsFindSymbol(const char *name) { - HMODULE dlls[128]; - DWORD ndlls=0u, i; + HANDLE proc = GetCurrentProcess(); + HMODULE *dlls=NULL; + DWORD nalloc=0u, needed=0u; void* ret = NULL; /* As a handle returned by LoadLibrary() isn't available to us, * try all loaded modules in arbitrary order. */ - if(epicsEnumProcessModules(GetCurrentProcess(), dlls, sizeof(dlls), &ndlls)) { - for(i=0; !ret && i needed) + nalloc = needed; + + for(i=0, ndlls = nalloc/sizeof(*dlls); !ret && i Date: Sat, 18 Apr 2020 08:21:23 -0700 Subject: [PATCH 10/13] epicsLoadTest: test expected failure --- modules/libcom/test/epicsLoadTest.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/libcom/test/epicsLoadTest.cpp b/modules/libcom/test/epicsLoadTest.cpp index 809081072..3062f3b22 100644 --- a/modules/libcom/test/epicsLoadTest.cpp +++ b/modules/libcom/test/epicsLoadTest.cpp @@ -17,6 +17,11 @@ namespace { +void loadBad() +{ + testOk1(!epicsFindSymbol("noSuchFunction")); +} + // lookup a symbol from libCom // which this executable is linked against (maybe statically) // Doesn't work for static builds on windows @@ -70,13 +75,14 @@ void loadCA() MAIN(epicsLoadTest) { - testPlan(3); + testPlan(4); // reference to ensure linkage when linking statically, // and actually use the result to make extra doubly sure that // this call isn't optimized out by eg. an LTO pass. testDiag("# of CPUs %d", epicsThreadGetCPUs()); + loadBad(); #if defined(__rtems__) || defined(vxWorks) testSkip(3, "Target does not implement epicsFindSymbol()"); #else From c6670e756ed85e8517cdd67f21f3d9d5255d4f88 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 18 Apr 2020 21:33:17 -0700 Subject: [PATCH 11/13] epicsLoadTest: avoid stdcall name mangling on WIN32 --- modules/libcom/test/epicsLoadTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/libcom/test/epicsLoadTest.cpp b/modules/libcom/test/epicsLoadTest.cpp index 3062f3b22..77b37f2db 100644 --- a/modules/libcom/test/epicsLoadTest.cpp +++ b/modules/libcom/test/epicsLoadTest.cpp @@ -67,8 +67,8 @@ void loadCA() void *ptr = epicsLoadLibrary(libname.c_str()); testOk(!!ptr, "Loaded %p : %s", ptr, epicsLoadError()); - ptr = epicsFindSymbol("ca_context_create"); - testOk(!!ptr, "ca_context_create %p : %s", ptr, epicsLoadError()); + ptr = epicsFindSymbol("dbf_text"); + testOk(!!ptr, "dbf_text %p : %s", ptr, epicsLoadError()); } } // namespace From 379ea6e58688e8f4ed69aa7fa797971b89a50f15 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 18 Apr 2020 21:41:47 -0700 Subject: [PATCH 12/13] WIN32: epicsFindSymbol() clear error on success --- modules/libcom/src/osi/os/WIN32/osdFindSymbol.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c index c8c74b56d..6447971fc 100644 --- a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c +++ b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c @@ -39,10 +39,7 @@ epicsShareFunc void * epicsLoadLibrary(const char *name) epicsLoadErrorCode = 0; lib = LoadLibrary(name); - if (lib == NULL) - { - epicsLoadErrorCode = GetLastError(); - } + epicsLoadErrorCode = lib ? 0 : GetLastError(); return lib; } @@ -113,10 +110,7 @@ epicsShareFunc void * epicsShareAPI epicsFindSymbol(const char *name) } } - - if(!ret) { - epicsLoadErrorCode = GetLastError(); - } + epicsLoadErrorCode = ret ? 0 : GetLastError(); free(dlls); return ret; } From 17efb0b82c4a3b07f8072d3f574d12d01e2435ec Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 23 Apr 2020 15:24:39 -0700 Subject: [PATCH 13/13] WIN32: osdFindSymbol.c use PSAPI_VERSION Prefer the more specific PSAPI_VERSION to NTDDI_VERSION. --- modules/libcom/src/osi/os/WIN32/osdFindSymbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c index 6447971fc..5731c8afe 100644 --- a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c +++ b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c @@ -9,7 +9,7 @@ * MinGW doesn't provide wrappers until 6.0, so fallback to psapi.dll */ #ifdef _MSC_VER -# define NTDDI_VERSION NTDDI_WIN7 +# define PSAPI_VERSION 2 # define epicsEnumProcessModules K32EnumProcessModules #else # define epicsEnumProcessModules EnumProcessModules