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