diff options
Diffstat (limited to 'sal/osl/unx/module.cxx')
-rw-r--r-- | sal/osl/unx/module.cxx | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/sal/osl/unx/module.cxx b/sal/osl/unx/module.cxx new file mode 100644 index 000000000..606c8fa47 --- /dev/null +++ b/sal/osl/unx/module.cxx @@ -0,0 +1,344 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <sal/log.hxx> +#include <sal/types.h> +#include <osl/module.h> +#include <osl/thread.h> +#include <osl/process.h> +#include <osl/file.h> +#include <rtl/string.hxx> +#include <rtl/ustring.hxx> +#include <assert.h> +#include "system.hxx" +#include "file_url.hxx" + +#ifdef AIX +#include <sys/ldr.h> +#endif + +static bool getModulePathFromAddress(void * address, rtl_String ** path) +{ + bool result = false; +#if defined(AIX) + int size = 4 * 1024; + char *buf, *filename=NULL; + struct ld_info *lp; + + if ((buf = (char*)malloc(size)) == NULL) + return false; + + //figure out how big a buffer we need + while (loadquery(L_GETINFO, buf, size) == -1 && errno == ENOMEM) + { + size += 4 * 1024; + free(buf); + if ((buf = (char*)malloc(size)) == NULL) + return false; + } + + lp = (struct ld_info*) buf; + while (lp) + { + unsigned long start = (unsigned long)lp->ldinfo_dataorg; + unsigned long end = start + lp->ldinfo_datasize; + if (start <= (unsigned long)address && end > (unsigned long)address) + { + filename = lp->ldinfo_filename; + break; + } + if (!lp->ldinfo_next) + break; + lp = (struct ld_info*) ((char *) lp + lp->ldinfo_next); + } + + if (filename) + { + rtl_string_newFromStr(path, filename); + result = sal_True; + } + else + { + result = sal_False; + } + + free(buf); +#else +#if HAVE_UNIX_DLAPI + Dl_info dl_info; + + result = dladdr(address, &dl_info) != 0; + + if (result) + { + rtl_string_newFromStr(path, dl_info.dli_fname); + } +#else + (void) address; + (void) path; +#endif +#endif + return result; +} + +#ifndef DISABLE_DYNLOADING + +/*****************************************************************************/ +/* osl_loadModule */ +/*****************************************************************************/ + +oslModule SAL_CALL osl_loadModule(rtl_uString *ustrModuleName, sal_Int32 nRtldMode) +{ + oslModule pModule=nullptr; + rtl_uString* ustrTmp = nullptr; + + SAL_WARN_IF(ustrModuleName == nullptr, "sal.osl", "string is not valid"); + + /* ensure ustrTmp hold valid string */ + if (osl_getSystemPathFromFileURL(ustrModuleName, &ustrTmp) != osl_File_E_None) + rtl_uString_assign(&ustrTmp, ustrModuleName); + + if (ustrTmp) + { + char buffer[PATH_MAX]; + + if (UnicodeToText(buffer, PATH_MAX, ustrTmp->buffer, ustrTmp->length)) + pModule = osl_loadModuleAscii(buffer, nRtldMode); + rtl_uString_release(ustrTmp); + } + + return pModule; +} + +/*****************************************************************************/ +/* osl_loadModuleAscii */ +/*****************************************************************************/ + +oslModule SAL_CALL osl_loadModuleAscii(const char *pModuleName, sal_Int32 nRtldMode) +{ +#if HAVE_UNIX_DLAPI + SAL_WARN_IF( + ((nRtldMode & SAL_LOADMODULE_LAZY) != 0 + && (nRtldMode & SAL_LOADMODULE_NOW) != 0), + "sal.osl", "only either LAZY or NOW"); + if (pModuleName) + { + int rtld_mode = + ((nRtldMode & SAL_LOADMODULE_NOW) ? RTLD_NOW : RTLD_LAZY) | + ((nRtldMode & SAL_LOADMODULE_GLOBAL) ? RTLD_GLOBAL : RTLD_LOCAL); + void* pLib = dlopen(pModuleName, rtld_mode); + + SAL_WARN_IF( + pLib == nullptr, "sal.osl", + "dlopen(" << pModuleName << ", " << rtld_mode << "): " + << dlerror()); + return pLib; + } +#else + (void) pModuleName; + (void) nRtldMode; +#endif + return nullptr; +} + +oslModule osl_loadModuleRelativeAscii( + oslGenericFunction baseModule, char const * relativePath, sal_Int32 mode) +{ + assert(relativePath && "illegal argument"); + if (relativePath[0] == '/') { + return osl_loadModuleAscii(relativePath, mode); + } + rtl_String * path = nullptr; + rtl_String * suffix = nullptr; + oslModule module; + if (!getModulePathFromAddress( + reinterpret_cast< void * >(baseModule), &path)) + { + return nullptr; + } + rtl_string_newFromStr_WithLength( + &path, path->buffer, + (rtl_str_lastIndexOfChar_WithLength(path->buffer, path->length, '/') + + 1)); + /* cut off everything after the last slash; should the original path + contain no slash, the resulting path is the empty string */ + rtl_string_newFromStr(&suffix, relativePath); + rtl_string_newConcat(&path, path, suffix); + rtl_string_release(suffix); + module = osl_loadModuleAscii(path->buffer, mode); + rtl_string_release(path); + return module; +} + +#endif // !DISABLE_DYNLOADING + +/*****************************************************************************/ +/* osl_getModuleHandle */ +/*****************************************************************************/ + +sal_Bool SAL_CALL +osl_getModuleHandle(rtl_uString *, oslModule *pResult) +{ +#if HAVE_UNIX_DLAPI + *pResult = static_cast<oslModule>(RTLD_DEFAULT); + return true; +#else + *pResult = nullptr; + return false; +#endif +} + +/*****************************************************************************/ +/* osl_unloadModule */ +/*****************************************************************************/ +void SAL_CALL osl_unloadModule(oslModule hModule) +{ +#if !defined(DISABLE_DYNLOADING) && HAVE_UNIX_DLAPI + if (hModule) + { + int nRet = dlclose(hModule); + SAL_INFO_IF( + nRet != 0, "sal.osl", "dlclose(" << hModule << "): " << dlerror()); + } +#else + (void) hModule; +#endif +} + +namespace { + +void * getSymbol(oslModule module, char const * symbol) +{ + assert(symbol != nullptr); +#if HAVE_UNIX_DLAPI + // We do want to use dlsym() also in the DISABLE_DYNLOADING case + // just to look up symbols in the static executable, I think: + void * p = dlsym(module, symbol); + SAL_INFO_IF( + p == nullptr, "sal.osl", + "dlsym(" << module << ", " << symbol << "): " << dlerror()); +#else + (void) module; + (void) symbol; + void *p = nullptr; +#endif + return p; +} + +} + +/*****************************************************************************/ +/* osl_getSymbol */ +/*****************************************************************************/ +void* SAL_CALL +osl_getSymbol(oslModule Module, rtl_uString* pSymbolName) +{ + // Arbitrarily using UTF-8: + OString s; + if (!OUString::unacquired(&pSymbolName).convertToString( + &s, RTL_TEXTENCODING_UTF8, + (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | + RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))) + { + SAL_INFO( + "sal.osl", "cannot convert \"" << OUString::unacquired(&pSymbolName) + << "\" to UTF-8"); + return nullptr; + } + if (s.indexOf('\0') != -1) { + SAL_INFO("sal.osl", "\"" << s << "\" contains embedded NUL"); + return nullptr; + } + return getSymbol(Module, s.getStr()); +} + +/*****************************************************************************/ +/* osl_getAsciiFunctionSymbol */ +/*****************************************************************************/ +oslGenericFunction SAL_CALL +osl_getAsciiFunctionSymbol(oslModule Module, const char *pSymbol) +{ + return reinterpret_cast<oslGenericFunction>(getSymbol(Module, pSymbol)); + // requires conditionally-supported conversion from void * to function + // pointer +} + +/*****************************************************************************/ +/* osl_getFunctionSymbol */ +/*****************************************************************************/ +oslGenericFunction SAL_CALL +osl_getFunctionSymbol(oslModule module, rtl_uString *puFunctionSymbolName) +{ + return reinterpret_cast<oslGenericFunction>( + osl_getSymbol(module, puFunctionSymbolName)); + // requires conditionally-supported conversion from void * to function + // pointer +} + +/*****************************************************************************/ +/* osl_getModuleURLFromAddress */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_getModuleURLFromAddress(void * addr, rtl_uString ** ppLibraryUrl) +{ + bool result = false; + rtl_String * path = nullptr; + if (getModulePathFromAddress(addr, &path)) + { + rtl_string2UString(ppLibraryUrl, + path->buffer, + path->length, + osl_getThreadTextEncoding(), + OSTRING_TO_OUSTRING_CVTFLAGS); + + SAL_WARN_IF( + *ppLibraryUrl == nullptr, "sal.osl", "rtl_string2UString failed"); + auto const e = osl_getFileURLFromSystemPath(*ppLibraryUrl, ppLibraryUrl); + if (e == osl_File_E_None) + { + SAL_INFO("sal.osl", "osl_getModuleURLFromAddress(" << addr << ") => " << OUString(*ppLibraryUrl)); + + result = true; + } + else + { + SAL_WARN( + "sal.osl", + "osl_getModuleURLFromAddress(" << addr << "), osl_getFileURLFromSystemPath(" + << OUString::unacquired(ppLibraryUrl) << ") failed with " << e); + result = false; + } + rtl_string_release(path); + } + return result; +} + +/*****************************************************************************/ +/* osl_getModuleURLFromFunctionAddress */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_getModuleURLFromFunctionAddress(oslGenericFunction addr, rtl_uString ** ppLibraryUrl) +{ + return osl_getModuleURLFromAddress( + reinterpret_cast<void*>(addr), ppLibraryUrl); + // requires conditionally-supported conversion from function pointer to + // void * +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |