#include "precompiled.h" #include "DllLoader.h" #include "lib/posix/posix_dlfcn.h" #include "ps/CStr.h" #include "ps/CLogger.h" void* const HANDLE_UNAVAILABLE = (void*)-1; // TODO Use path_util instead, get the actual path to the ps_dbg exe and append // the library name. // note: on Linux, lib is prepended to the SO file name and we need to add ./ // to make dlopen look in the current working directory #if OS_UNIX static const char* prefix = "./lib"; #else static const char* prefix = ""; #endif // since some of our SOs export a C++ interface, it is critical that // compiler options are the same between app and SO; therefore, // we need to go with the debug version in debug builds. // note: on Windows, the extension is replaced with .dll by dlopen. #ifndef NDEBUG static const char* suffix = "_dbg.so"; #else static const char* suffix = ".so"; #endif // (This class is currently only used by 'Collada' and 'AtlasUI' which follow // the naming/location convention above - it'll need to be changed if we want // to support other DLLs.) DllLoader::DllLoader(const char* name) : m_Name(name), m_Handle(0) { } DllLoader::~DllLoader() { if (IsLoaded()) dlclose(m_Handle); } bool DllLoader::IsLoaded() const { return (m_Handle != 0 && m_Handle != HANDLE_UNAVAILABLE); } bool DllLoader::LoadDLL() { // first time: try to open the shared object // postcondition: m_Handle valid or == HANDLE_UNAVAILABLE. if (m_Handle == 0) { CStr filename = CStr(prefix) + m_Name + suffix; // we don't really care when relocations take place, but one of // {RTLD_NOW, RTLD_LAZY} must be passed. go with the former because // it is safer and matches the Windows load behavior. const int flags = RTLD_LOCAL|RTLD_NOW; m_Handle = dlopen(filename, flags); // open failed (mostly likely SO not found) if (! m_Handle) { char* error = dlerror(); if (error) LOG(ERROR, "", "dlopen error: %s", error); m_Handle = HANDLE_UNAVAILABLE; } } return (m_Handle != HANDLE_UNAVAILABLE); } void DllLoader::Unload() { if (! IsLoaded()) return; dlclose(m_Handle); m_Handle = 0; } void DllLoader::LoadSymbolInternal(const char* name, void** fptr) const { if (! IsLoaded()) { debug_warn("Loading symbol from invalid DLL"); *fptr = NULL; throw PSERROR_DllLoader_DllNotLoaded(); } *fptr = dlsym(m_Handle, name); if (*fptr == NULL) throw PSERROR_DllLoader_SymbolNotFound(); }