/* * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. This file is offered as-is, * without any warranty. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "@LOADER_H@" #if defined(@ENABLE_DLOPEN@) && @ENABLE_DLOPEN@ #include #include #include #include /* If @LIBRARY_SONAME@ is defined, dlopen handle can be automatically * set; otherwise, the caller needs to call * @LIBRARY_PREFIX@_ensure_library with soname determined at run time. */ #ifdef @LIBRARY_SONAME@ static void ensure_library (void) { if (@LIBRARY_PREFIX@_ensure_library (@LIBRARY_SONAME@, RTLD_LAZY | RTLD_LOCAL) < 0) abort (); } #if defined(@ENABLE_PTHREAD@) && @ENABLE_PTHREAD@ #include static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT; #define ENSURE_LIBRARY pthread_once(&dlopen_once, ensure_library) #else /* @ENABLE_PTHREAD@ */ #define ENSURE_LIBRARY do { \ if (!@LIBRARY_PREFIX@_dlhandle) \ ensure_library(); \ } while (0) #endif /* !@ENABLE_PTHREAD@ */ #else /* @LIBRARY_SONAME@ */ #define ENSURE_LIBRARY do {} while (0) #endif /* !@LIBRARY_SONAME@ */ static void *@LIBRARY_PREFIX@_dlhandle; /* Define redirection symbols */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-macros" #if (2 <= __GNUC__ || (4 <= __clang_major__)) #define FUNC(ret, name, args, cargs) \ static __typeof__(name)(*@SYMBOL_PREFIX@_##name); #else #define FUNC(ret, name, args, cargs) \ static ret(*@SYMBOL_PREFIX@_##name)args; #endif #define VOID_FUNC FUNC #include "@FUNCTIONS_H@" #undef VOID_FUNC #undef FUNC #pragma GCC diagnostic pop /* Define redirection wrapper functions */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-macros" #define FUNC(ret, name, args, cargs) \ ret @FUNCTION_PREFIX@_##name args \ { \ ENSURE_LIBRARY; \ assert (@SYMBOL_PREFIX@_##name); \ return @SYMBOL_PREFIX@_##name cargs; \ } #define VOID_FUNC(ret, name, args, cargs) \ ret @FUNCTION_PREFIX@_##name args \ { \ ENSURE_LIBRARY; \ assert (@SYMBOL_PREFIX@_##name); \ @SYMBOL_PREFIX@_##name cargs; \ } #include "@FUNCTIONS_H@" #undef VOID_FUNC #undef FUNC #pragma GCC diagnostic pop static int ensure_symbol (const char *name, void **symp) { if (!*symp) { void *sym = dlsym (@LIBRARY_PREFIX@_dlhandle, name); if (!sym) return -EINVAL; *symp = sym; } return 0; } int @LIBRARY_PREFIX@_ensure_library (const char *soname, int flags) { int err; if (!@LIBRARY_PREFIX@_dlhandle) { @LIBRARY_PREFIX@_dlhandle = dlopen (soname, flags); if (!@LIBRARY_PREFIX@_dlhandle) return -EINVAL; } #define ENSURE_SYMBOL(name) \ ensure_symbol(#name, (void **)&@SYMBOL_PREFIX@_##name) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-macros" #define FUNC(ret, name, args, cargs) \ err = ENSURE_SYMBOL(name); \ if (err < 0) \ { \ @LIBRARY_PREFIX@_dlhandle = NULL; \ return err; \ } #define VOID_FUNC FUNC #include "@FUNCTIONS_H@" #undef VOID_FUNC #undef FUNC #pragma GCC diagnostic pop #undef ENSURE_SYMBOL return 0; } void @LIBRARY_PREFIX@_unload_library (void) { if (@LIBRARY_PREFIX@_dlhandle) { dlclose (@LIBRARY_PREFIX@_dlhandle); @LIBRARY_PREFIX@_dlhandle = NULL; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-macros" #define FUNC(ret, name, args, cargs) \ @SYMBOL_PREFIX@_##name = NULL; #define VOID_FUNC FUNC #include "@FUNCTIONS_H@" #undef VOID_FUNC #undef FUNC #pragma GCC diagnostic pop } unsigned @LIBRARY_PREFIX@_is_usable (void) { return @LIBRARY_PREFIX@_dlhandle != NULL; } #else /* @ENABLE_DLOPEN@ */ int @LIBRARY_PREFIX@_ensure_library (const char *soname, int flags) { (void) soname; (void) flags; return 0; } void @LIBRARY_PREFIX@_unload_library (void) { } unsigned @LIBRARY_PREFIX@_is_usable (void) { /* The library is linked at build time, thus always usable */ return 1; } #endif /* !@ENABLE_DLOPEN@ */