Merge commit '17efb0b82c4a3b07f8072d3f574d12d01e2435ec' into 7.0

* commit '17efb0b82c4a3b07f8072d3f574d12d01e2435ec':
  WIN32: osdFindSymbol.c use PSAPI_VERSION
  WIN32: epicsFindSymbol() clear error on success
  epicsLoadTest: avoid stdcall name mangling on WIN32
  epicsLoadTest: test expected failure
  WIN32: epicsFindSymbol() fix use of EnumProcessModules()
  fix epicsLoadError()
  WIN32: GetLastError() returns DWORD
  WIN32: osdFindSymbol() use psapi
  WIN32: epicsLoadError() strip trailing newlines
  add epicsLoadTest
  WIN32 fix epicsFindSymbol()
  WIN32 fix epicsFindSymbol() error propagation
  OSX fix osdFindSymbol
This commit is contained in:
Michael Davidsaver
2020-04-29 16:44:59 -07:00
6 changed files with 195 additions and 12 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -5,13 +5,33 @@
\*************************************************************************/
/* osi/os/WIN32/osdFindSymbol.c */
/* 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
*/
#ifdef _MSC_VER
# define PSAPI_VERSION 2
# define epicsEnumProcessModules K32EnumProcessModules
#else
# define epicsEnumProcessModules EnumProcessModules
#endif
#include <windows.h>
#include <psapi.h>
#define epicsExportSharedSymbols
#include "epicsStdio.h"
#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
DWORD epicsLoadErrorCode = 0;
epicsShareFunc void * epicsLoadLibrary(const char *name)
{
@@ -19,28 +39,78 @@ epicsShareFunc void * epicsLoadLibrary(const char *name)
epicsLoadErrorCode = 0;
lib = LoadLibrary(name);
if (lib == NULL)
{
epicsLoadErrorCode = GetLastError();
}
epicsLoadErrorCode = lib ? 0 : GetLastError();
return lib;
}
epicsShareFunc const char *epicsLoadError(void)
{
static char buffer[100];
STORE char buffer[100];
DWORD n;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM,
n = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
epicsLoadErrorCode,
0,
buffer,
sizeof(buffer)-1, NULL );
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;
}
epicsShareFunc void * epicsShareAPI epicsFindSymbol(const char *name)
{
return GetProcAddress(0, name);
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(proc, NULL, 0, &needed)) {
epicsLoadErrorCode = GetLastError();
return ret;
}
if(!(dlls = malloc(nalloc = needed))) {
epicsLoadErrorCode = ERROR_NOT_ENOUGH_MEMORY;
return ret;
}
if(epicsEnumProcessModules(proc, dlls, nalloc, &needed)) {
DWORD i, ndlls;
/* settle potential races w/o retry by iterating smaller of nalloc or needed */
if(nalloc > needed)
nalloc = needed;
for(i=0, ndlls = nalloc/sizeof(*dlls); !ret && i<ndlls; i++) {
ret = GetProcAddress(dlls[i], name);
if(!ret && GetLastError()!=ERROR_PROC_NOT_FOUND) {
break;
}
}
}
epicsLoadErrorCode = ret ? 0 : GetLastError();
free(dlls);
return ret;
}

View File

@@ -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);
}

View File

@@ -265,6 +265,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

View File

@@ -0,0 +1,97 @@
/*************************************************************************\
* 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 <sstream>
#include <stdlib.h>
#include "epicsUnitTest.h"
#include "testMain.h"
#include "envDefs.h"
#include "epicsFindSymbol.h"
#include "epicsThread.h"
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
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\\"<<envGetConfigParamPtr(&EPICS_BUILD_TARGET_ARCH)<<"\\ca.dll";
#else
strm<<"../../../../lib/"<<envGetConfigParamPtr(&EPICS_BUILD_TARGET_ARCH)<<"/";
# ifdef __APPLE__
strm<<"libca.dylib";
# else
strm<<"libca.so";
# endif
#endif
libname = strm.str();
}
testDiag("Loading %s", libname.c_str());
void *ptr = epicsLoadLibrary(libname.c_str());
testOk(!!ptr, "Loaded %p : %s", ptr, epicsLoadError());
ptr = epicsFindSymbol("dbf_text");
testOk(!!ptr, "dbf_text %p : %s", ptr, epicsLoadError());
}
} // namespace
MAIN(epicsLoadTest)
{
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
loadCom();
# if defined(BUILDING_SHARED_LIBRARIES)
loadCA();
# else
testSkip(2, "Shared libraries not built");
# endif
#endif
return testDone();
}