xref: /core/sal/osl/unx/module.cxx (revision 252132d9)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <sal/log.hxx>
23 #include <sal/types.h>
24 #include <osl/module.h>
25 #include <osl/thread.h>
26 #include <osl/file.h>
27 #include <rtl/string.hxx>
28 #include <rtl/ustring.hxx>
29 #include <assert.h>
30 #include <dlfcn.h>
31 #include <limits.h>
32 #include "file_url.hxx"
33 
getModulePathFromAddress(void * address,rtl_String ** path)34 static bool getModulePathFromAddress(void * address, rtl_String ** path)
35 {
36     bool result = false;
37 #if HAVE_UNIX_DLAPI
38     Dl_info dl_info;
39 
40     result = dladdr(address, &dl_info) != 0;
41 
42     if (result)
43     {
44         rtl_string_newFromStr(path, dl_info.dli_fname);
45     }
46 #else
47     (void) address;
48     (void) path;
49 #endif
50     return result;
51 }
52 
53 #ifndef DISABLE_DYNLOADING
54 
55 /*****************************************************************************/
56 /* osl_loadModule */
57 /*****************************************************************************/
58 
osl_loadModule(rtl_uString * ustrModuleName,sal_Int32 nRtldMode)59 oslModule SAL_CALL osl_loadModule(rtl_uString *ustrModuleName, sal_Int32 nRtldMode)
60 {
61     oslModule pModule=nullptr;
62     rtl_uString* ustrTmp = nullptr;
63 
64     SAL_WARN_IF(ustrModuleName == nullptr, "sal.osl", "string is not valid");
65 
66     /* ensure ustrTmp hold valid string */
67     if (osl_getSystemPathFromFileURL(ustrModuleName, &ustrTmp) != osl_File_E_None)
68         rtl_uString_assign(&ustrTmp, ustrModuleName);
69 
70     if (ustrTmp)
71     {
72         char buffer[PATH_MAX];
73 
74         if (UnicodeToText(buffer, PATH_MAX, ustrTmp->buffer, ustrTmp->length))
75             pModule = osl_loadModuleAscii(buffer, nRtldMode);
76         rtl_uString_release(ustrTmp);
77     }
78 
79     return pModule;
80 }
81 
82 /*****************************************************************************/
83 /* osl_loadModuleAscii */
84 /*****************************************************************************/
85 
osl_loadModuleAscii(const char * pModuleName,sal_Int32 nRtldMode)86 oslModule SAL_CALL osl_loadModuleAscii(const char *pModuleName, sal_Int32 nRtldMode)
87 {
88 #if HAVE_UNIX_DLAPI
89     SAL_WARN_IF(
90         ((nRtldMode & SAL_LOADMODULE_LAZY) != 0
91          && (nRtldMode & SAL_LOADMODULE_NOW) != 0),
92         "sal.osl", "only either LAZY or NOW");
93     if (pModuleName)
94     {
95         int rtld_mode =
96             ((nRtldMode & SAL_LOADMODULE_NOW) ? RTLD_NOW : RTLD_LAZY) |
97             ((nRtldMode & SAL_LOADMODULE_GLOBAL) ? RTLD_GLOBAL : RTLD_LOCAL);
98         void* pLib = dlopen(pModuleName, rtld_mode);
99 
100         SAL_WARN_IF(
101             pLib == nullptr, "sal.osl",
102             "dlopen(" << pModuleName << ", " << rtld_mode << "): "
103                 << dlerror());
104         return pLib;
105     }
106 #else
107     (void) pModuleName;
108     (void) nRtldMode;
109 #endif
110     return nullptr;
111 }
112 
osl_loadModuleRelativeAscii(oslGenericFunction baseModule,char const * relativePath,sal_Int32 mode)113 oslModule osl_loadModuleRelativeAscii(
114     oslGenericFunction baseModule, char const * relativePath, sal_Int32 mode)
115 {
116     assert(relativePath && "illegal argument");
117     if (relativePath[0] == '/') {
118         return osl_loadModuleAscii(relativePath, mode);
119     }
120     rtl_String * path = nullptr;
121     rtl_String * suffix = nullptr;
122     oslModule module;
123     if (!getModulePathFromAddress(
124             reinterpret_cast< void * >(baseModule), &path))
125     {
126         return nullptr;
127     }
128     rtl_string_newFromStr_WithLength(
129         &path, path->buffer,
130         (rtl_str_lastIndexOfChar_WithLength(path->buffer, path->length, '/')
131          + 1));
132         /* cut off everything after the last slash; should the original path
133            contain no slash, the resulting path is the empty string */
134     rtl_string_newFromStr(&suffix, relativePath);
135     rtl_string_newConcat(&path, path, suffix);
136     rtl_string_release(suffix);
137     module = osl_loadModuleAscii(path->buffer, mode);
138     rtl_string_release(path);
139     return module;
140 }
141 
142 #endif // !DISABLE_DYNLOADING
143 
144 /*****************************************************************************/
145 /* osl_getModuleHandle */
146 /*****************************************************************************/
147 
148 sal_Bool SAL_CALL
osl_getModuleHandle(rtl_uString *,oslModule * pResult)149 osl_getModuleHandle(rtl_uString *, oslModule *pResult)
150 {
151 #if HAVE_UNIX_DLAPI
152     *pResult = static_cast<oslModule>(RTLD_DEFAULT);
153     return true;
154 #else
155     *pResult = nullptr;
156     return false;
157 #endif
158 }
159 
160 /*****************************************************************************/
161 /* osl_unloadModule */
162 /*****************************************************************************/
osl_unloadModule(oslModule hModule)163 void SAL_CALL osl_unloadModule(oslModule hModule)
164 {
165 #if !defined(DISABLE_DYNLOADING) && HAVE_UNIX_DLAPI
166     if (hModule)
167     {
168         int nRet = dlclose(hModule);
169         SAL_INFO_IF(
170             nRet != 0, "sal.osl", "dlclose(" << hModule << "): " << dlerror());
171     }
172 #else
173     (void) hModule;
174 #endif
175 }
176 
177 namespace {
178 
getSymbol(oslModule module,char const * symbol)179 void * getSymbol(oslModule module, char const * symbol)
180 {
181     assert(symbol != nullptr);
182 #if HAVE_UNIX_DLAPI
183     // We do want to use dlsym() also in the DISABLE_DYNLOADING case
184     // just to look up symbols in the static executable, I think:
185     void * p = dlsym(module, symbol);
186     SAL_INFO_IF(
187         p == nullptr, "sal.osl",
188         "dlsym(" << module << ", " << symbol << "): " << dlerror());
189 #else
190     (void) module;
191     (void) symbol;
192     void *p = nullptr;
193 #endif
194     return p;
195 }
196 
197 }
198 
199 /*****************************************************************************/
200 /* osl_getSymbol */
201 /*****************************************************************************/
202 void* SAL_CALL
osl_getSymbol(oslModule Module,rtl_uString * pSymbolName)203 osl_getSymbol(oslModule Module, rtl_uString* pSymbolName)
204 {
205     // Arbitrarily using UTF-8:
206     OString s;
207     if (!OUString::unacquired(&pSymbolName).convertToString(
208             &s, RTL_TEXTENCODING_UTF8,
209             (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
210              RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
211     {
212         SAL_INFO(
213             "sal.osl", "cannot convert \"" << OUString::unacquired(&pSymbolName)
214                 << "\" to UTF-8");
215         return nullptr;
216     }
217     if (s.indexOf('\0') != -1) {
218         SAL_INFO("sal.osl", "\"" << s << "\" contains embedded NUL");
219         return nullptr;
220     }
221     return getSymbol(Module, s.getStr());
222 }
223 
224 /*****************************************************************************/
225 /* osl_getAsciiFunctionSymbol */
226 /*****************************************************************************/
227 oslGenericFunction SAL_CALL
osl_getAsciiFunctionSymbol(oslModule Module,const char * pSymbol)228 osl_getAsciiFunctionSymbol(oslModule Module, const char *pSymbol)
229 {
230     return reinterpret_cast<oslGenericFunction>(getSymbol(Module, pSymbol));
231         // requires conditionally-supported conversion from void * to function
232         // pointer
233 }
234 
235 /*****************************************************************************/
236 /* osl_getFunctionSymbol */
237 /*****************************************************************************/
238 oslGenericFunction SAL_CALL
osl_getFunctionSymbol(oslModule module,rtl_uString * puFunctionSymbolName)239 osl_getFunctionSymbol(oslModule module, rtl_uString *puFunctionSymbolName)
240 {
241     return reinterpret_cast<oslGenericFunction>(
242         osl_getSymbol(module, puFunctionSymbolName));
243         // requires conditionally-supported conversion from void * to function
244         // pointer
245 }
246 
247 /*****************************************************************************/
248 /* osl_getModuleURLFromAddress */
249 /*****************************************************************************/
osl_getModuleURLFromAddress(void * addr,rtl_uString ** ppLibraryUrl)250 sal_Bool SAL_CALL osl_getModuleURLFromAddress(void * addr, rtl_uString ** ppLibraryUrl)
251 {
252     bool result = false;
253     rtl_String * path = nullptr;
254     if (getModulePathFromAddress(addr, &path))
255     {
256         rtl_string2UString(ppLibraryUrl,
257                            path->buffer,
258                            path->length,
259                            osl_getThreadTextEncoding(),
260                            OSTRING_TO_OUSTRING_CVTFLAGS);
261 
262         SAL_WARN_IF(
263             *ppLibraryUrl == nullptr, "sal.osl", "rtl_string2UString failed");
264         auto const e = osl_getFileURLFromSystemPath(*ppLibraryUrl, ppLibraryUrl);
265         if (e == osl_File_E_None)
266         {
267             SAL_INFO("sal.osl", "osl_getModuleURLFromAddress(" << addr << ") => " << OUString(*ppLibraryUrl));
268 
269             result = true;
270         }
271         else
272         {
273             SAL_WARN(
274                 "sal.osl",
275                 "osl_getModuleURLFromAddress(" << addr << "), osl_getFileURLFromSystemPath("
276                     << OUString::unacquired(ppLibraryUrl) << ") failed with " << e);
277             result = false;
278         }
279         rtl_string_release(path);
280     }
281     return result;
282 }
283 
284 /*****************************************************************************/
285 /* osl_getModuleURLFromFunctionAddress */
286 /*****************************************************************************/
osl_getModuleURLFromFunctionAddress(oslGenericFunction addr,rtl_uString ** ppLibraryUrl)287 sal_Bool SAL_CALL osl_getModuleURLFromFunctionAddress(oslGenericFunction addr, rtl_uString ** ppLibraryUrl)
288 {
289     return osl_getModuleURLFromAddress(
290         reinterpret_cast<void*>(addr), ppLibraryUrl);
291         // requires conditionally-supported conversion from function pointer to
292         // void *
293 }
294 
295 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
296