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/process.h>
27 #include <osl/file.h>
28 #include <rtl/string.hxx>
29 #include <rtl/ustring.hxx>
30 #include <assert.h>
31 #include "system.hxx"
32 #include "file_url.hxx"
33 
34 #ifdef AIX
35 #include <sys/ldr.h>
36 #endif
37 
38 #ifdef ANDROID
39 #include <osl/detail/android-bootstrap.h>
40 #endif
41 
getModulePathFromAddress(void * address,rtl_String ** path)42 static bool getModulePathFromAddress(void * address, rtl_String ** path) {
43     bool result = false;
44     // We do want to have this functionality also in the
45     // DISABLE_DYNLOADING case, I think?
46 #if defined(AIX)
47     int size = 4 * 1024;
48     char *buf, *filename=NULL;
49     struct ld_info *lp;
50 
51     if ((buf = (char*)malloc(size)) == NULL)
52         return false;
53 
54     //figure out how big a buffer we need
55     while (loadquery(L_GETINFO, buf, size) == -1 && errno == ENOMEM)
56     {
57         size += 4 * 1024;
58         free(buf);
59         if ((buf = (char*)malloc(size)) == NULL)
60             return false;
61     }
62 
63     lp = (struct ld_info*) buf;
64     while (lp)
65     {
66         unsigned long start = (unsigned long)lp->ldinfo_dataorg;
67         unsigned long end = start + lp->ldinfo_datasize;
68         if (start <= (unsigned long)address && end > (unsigned long)address)
69         {
70             filename = lp->ldinfo_filename;
71             break;
72         }
73         if (!lp->ldinfo_next)
74             break;
75         lp = (struct ld_info*) ((char *) lp + lp->ldinfo_next);
76     }
77 
78     if (filename)
79     {
80         rtl_string_newFromStr(path, filename);
81         result = sal_True;
82     }
83     else
84     {
85         result = sal_False;
86     }
87 
88     free(buf);
89 #else
90     Dl_info dl_info;
91 
92     result = dladdr(address, &dl_info) != 0;
93 
94     if (result)
95     {
96         rtl_string_newFromStr(path, dl_info.dli_fname);
97     }
98 #endif
99     return result;
100 }
101 
102 #ifndef DISABLE_DYNLOADING
103 
104 /*****************************************************************************/
105 /* osl_loadModule */
106 /*****************************************************************************/
107 
osl_loadModule(rtl_uString * ustrModuleName,sal_Int32 nRtldMode)108 oslModule SAL_CALL osl_loadModule(rtl_uString *ustrModuleName, sal_Int32 nRtldMode)
109 {
110     oslModule pModule=nullptr;
111     rtl_uString* ustrTmp = nullptr;
112 
113     SAL_WARN_IF(ustrModuleName == nullptr, "sal.osl", "string is not valid");
114 
115     /* ensure ustrTmp hold valid string */
116     if (osl_getSystemPathFromFileURL(ustrModuleName, &ustrTmp) != osl_File_E_None)
117         rtl_uString_assign(&ustrTmp, ustrModuleName);
118 
119     if (ustrTmp)
120     {
121         char buffer[PATH_MAX];
122 
123         if (UnicodeToText(buffer, PATH_MAX, ustrTmp->buffer, ustrTmp->length))
124             pModule = osl_loadModuleAscii(buffer, nRtldMode);
125         rtl_uString_release(ustrTmp);
126     }
127 
128     return pModule;
129 }
130 
131 /*****************************************************************************/
132 /* osl_loadModuleAscii */
133 /*****************************************************************************/
134 
osl_loadModuleAscii(const char * pModuleName,sal_Int32 nRtldMode)135 oslModule SAL_CALL osl_loadModuleAscii(const char *pModuleName, sal_Int32 nRtldMode)
136 {
137     SAL_WARN_IF(
138         ((nRtldMode & SAL_LOADMODULE_LAZY) != 0
139          && (nRtldMode & SAL_LOADMODULE_NOW) != 0),
140         "sal.osl", "only either LAZY or NOW");
141     if (pModuleName)
142     {
143 #ifdef ANDROID
144         (void) nRtldMode;
145         void *pLib = lo_dlopen(pModuleName);
146 #else
147         int rtld_mode =
148             ((nRtldMode & SAL_LOADMODULE_NOW) ? RTLD_NOW : RTLD_LAZY) |
149             ((nRtldMode & SAL_LOADMODULE_GLOBAL) ? RTLD_GLOBAL : RTLD_LOCAL);
150         void* pLib = dlopen(pModuleName, rtld_mode);
151 
152         SAL_WARN_IF(
153             pLib == nullptr, "sal.osl",
154             "dlopen(" << pModuleName << ", " << rtld_mode << "): "
155                 << dlerror());
156 #endif
157         return pLib;
158     }
159     return nullptr;
160 }
161 
osl_loadModuleRelativeAscii(oslGenericFunction baseModule,char const * relativePath,sal_Int32 mode)162 oslModule osl_loadModuleRelativeAscii(
163     oslGenericFunction baseModule, char const * relativePath, sal_Int32 mode)
164 {
165     assert(relativePath && "illegal argument");
166     if (relativePath[0] == '/') {
167         return osl_loadModuleAscii(relativePath, mode);
168     }
169     rtl_String * path = nullptr;
170     rtl_String * suffix = nullptr;
171     oslModule module;
172     if (!getModulePathFromAddress(
173             reinterpret_cast< void * >(baseModule), &path))
174     {
175         return nullptr;
176     }
177     rtl_string_newFromStr_WithLength(
178         &path, path->buffer,
179         (rtl_str_lastIndexOfChar_WithLength(path->buffer, path->length, '/')
180          + 1));
181         /* cut off everything after the last slash; should the original path
182            contain no slash, the resulting path is the empty string */
183     rtl_string_newFromStr(&suffix, relativePath);
184     rtl_string_newConcat(&path, path, suffix);
185     rtl_string_release(suffix);
186     module = osl_loadModuleAscii(path->buffer, mode);
187     rtl_string_release(path);
188     return module;
189 }
190 
191 #endif // !DISABLE_DYNLOADING
192 
193 /*****************************************************************************/
194 /* osl_getModuleHandle */
195 /*****************************************************************************/
196 
197 sal_Bool SAL_CALL
osl_getModuleHandle(rtl_uString *,oslModule * pResult)198 osl_getModuleHandle(rtl_uString *, oslModule *pResult)
199 {
200 #if !defined(DISABLE_DYNLOADING) || defined(IOS)
201     *pResult = static_cast<oslModule>(RTLD_DEFAULT);
202 #else
203     *pResult = nullptr;
204 #endif
205     return true;
206 }
207 
208 #ifndef DISABLE_DYNLOADING
209 
210 /*****************************************************************************/
211 /* osl_unloadModule */
212 /*****************************************************************************/
osl_unloadModule(oslModule hModule)213 void SAL_CALL osl_unloadModule(oslModule hModule)
214 {
215     if (hModule)
216     {
217 #ifdef ANDROID
218         int nRet = lo_dlclose(hModule);
219 #else
220         int nRet = dlclose(hModule);
221 #endif
222         SAL_INFO_IF(
223             nRet != 0, "sal.osl", "dlclose(" << hModule << "): " << dlerror());
224     }
225 }
226 
227 #endif // !DISABLE_DYNLOADING
228 
229 namespace {
230 
getSymbol(oslModule module,char const * symbol)231 void * getSymbol(oslModule module, char const * symbol) {
232     assert(symbol != nullptr);
233     // We do want to use dlsym() also in the DISABLE_DYNLOADING case
234     // just to look up symbols in the static executable, I think:
235     void * p = dlsym(module, symbol);
236     SAL_INFO_IF(
237         p == nullptr, "sal.osl",
238         "dlsym(" << module << ", " << symbol << "): " << dlerror());
239     return p;
240 }
241 
242 }
243 
244 /*****************************************************************************/
245 /* osl_getSymbol */
246 /*****************************************************************************/
247 void* SAL_CALL
osl_getSymbol(oslModule Module,rtl_uString * pSymbolName)248 osl_getSymbol(oslModule Module, rtl_uString* pSymbolName)
249 {
250     // Arbitrarily using UTF-8:
251     OString s;
252     if (!OUString::unacquired(&pSymbolName).convertToString(
253             &s, RTL_TEXTENCODING_UTF8,
254             (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
255              RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
256     {
257         SAL_INFO(
258             "sal.osl", "cannot convert \"" << OUString::unacquired(&pSymbolName)
259                 << "\" to UTF-8");
260         return nullptr;
261     }
262     if (s.indexOf('\0') != -1) {
263         SAL_INFO("sal.osl", "\"" << s << "\" contains embedded NUL");
264         return nullptr;
265     }
266     return getSymbol(Module, s.getStr());
267 }
268 
269 /*****************************************************************************/
270 /* osl_getAsciiFunctionSymbol */
271 /*****************************************************************************/
272 oslGenericFunction SAL_CALL
osl_getAsciiFunctionSymbol(oslModule Module,const char * pSymbol)273 osl_getAsciiFunctionSymbol(oslModule Module, const char *pSymbol)
274 {
275     return reinterpret_cast<oslGenericFunction>(getSymbol(Module, pSymbol));
276         // requires conditionally-supported conversion from void * to function
277         // pointer
278 }
279 
280 /*****************************************************************************/
281 /* osl_getFunctionSymbol */
282 /*****************************************************************************/
283 oslGenericFunction SAL_CALL
osl_getFunctionSymbol(oslModule module,rtl_uString * puFunctionSymbolName)284 osl_getFunctionSymbol(oslModule module, rtl_uString *puFunctionSymbolName)
285 {
286     return reinterpret_cast<oslGenericFunction>(
287         osl_getSymbol(module, puFunctionSymbolName));
288         // requires conditionally-supported conversion from void * to function
289         // pointer
290 }
291 
292 /*****************************************************************************/
293 /* osl_getModuleURLFromAddress */
294 /*****************************************************************************/
osl_getModuleURLFromAddress(void * addr,rtl_uString ** ppLibraryUrl)295 sal_Bool SAL_CALL osl_getModuleURLFromAddress(void * addr, rtl_uString ** ppLibraryUrl)
296 {
297     bool result = false;
298     rtl_String * path = nullptr;
299     if (getModulePathFromAddress(addr, &path))
300     {
301         rtl_string2UString(ppLibraryUrl,
302                            path->buffer,
303                            path->length,
304                            osl_getThreadTextEncoding(),
305                            OSTRING_TO_OUSTRING_CVTFLAGS);
306 
307         SAL_WARN_IF(
308             *ppLibraryUrl == nullptr, "sal.osl", "rtl_string2UString failed");
309         auto const e = osl_getFileURLFromSystemPath(*ppLibraryUrl, ppLibraryUrl);
310         if (e == osl_File_E_None)
311         {
312             SAL_INFO("sal.osl", "osl_getModuleURLFromAddress(" << addr << ") => " << OUString(*ppLibraryUrl));
313 
314             result = true;
315         }
316         else
317         {
318             SAL_WARN(
319                 "sal.osl",
320                 "osl_getModuleURLFromAddress(" << addr << "), osl_getFileURLFromSystemPath("
321                     << OUString::unacquired(ppLibraryUrl) << ") failed with " << e);
322             result = false;
323         }
324         rtl_string_release(path);
325     }
326     return result;
327 }
328 
329 /*****************************************************************************/
330 /* osl_getModuleURLFromFunctionAddress */
331 /*****************************************************************************/
osl_getModuleURLFromFunctionAddress(oslGenericFunction addr,rtl_uString ** ppLibraryUrl)332 sal_Bool SAL_CALL osl_getModuleURLFromFunctionAddress(oslGenericFunction addr, rtl_uString ** ppLibraryUrl)
333 {
334     return osl_getModuleURLFromAddress(
335         reinterpret_cast<void*>(addr), ppLibraryUrl);
336         // requires conditionally-supported conversion from function pointer to
337         // void *
338 }
339 
340 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
341