1 : /* -*- Mode: C++; tab-width: 6; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla XPCOM.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Benjamin Smedberg <benjamin@smedbergs.us>
19 : *
20 : * Portions created by the Initial Developer are Copyright (C) 2005
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Mike Hommey <mh@glandium.org>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "nsGlueLinking.h"
41 : #include "nsXPCOMGlue.h"
42 : #include "nscore.h"
43 :
44 : #if defined(LINUX) && !defined(ANDROID)
45 : #define _GNU_SOURCE
46 : #include <fcntl.h>
47 : #include <unistd.h>
48 : #include <elf.h>
49 : #include <limits.h>
50 : #endif
51 :
52 : #include <errno.h>
53 : #include <dlfcn.h>
54 : #include <stdlib.h>
55 : #include <string.h>
56 : #include <stdio.h>
57 :
58 : #if defined(SUNOS4) || defined(NEXTSTEP) || \
59 : (defined(OPENBSD) || defined(NETBSD)) && !defined(__ELF__)
60 : #define LEADING_UNDERSCORE "_"
61 : #else
62 : #define LEADING_UNDERSCORE
63 : #endif
64 :
65 : #if defined(MOZ_LINKER) && !defined(ANDROID)
66 : extern "C" {
67 : NS_HIDDEN __typeof(dlopen) __wrap_dlopen;
68 : NS_HIDDEN __typeof(dlsym) __wrap_dlsym;
69 : NS_HIDDEN __typeof(dlclose) __wrap_dlclose;
70 : }
71 :
72 : #define dlopen __wrap_dlopen
73 : #define dlsym __wrap_dlsym
74 : #define dlclose __wrap_dlclose
75 : #endif
76 :
77 : #ifdef NS_TRACE_MALLOC
78 : extern "C" {
79 : NS_EXPORT_(__ptr_t) __libc_malloc(size_t);
80 : NS_EXPORT_(__ptr_t) __libc_calloc(size_t, size_t);
81 : NS_EXPORT_(__ptr_t) __libc_realloc(__ptr_t, size_t);
82 : NS_EXPORT_(void) __libc_free(__ptr_t);
83 : NS_EXPORT_(__ptr_t) __libc_memalign(size_t, size_t);
84 : NS_EXPORT_(__ptr_t) __libc_valloc(size_t);
85 : }
86 :
87 : static __ptr_t (*_malloc)(size_t) = __libc_malloc;
88 : static __ptr_t (*_calloc)(size_t, size_t) = __libc_calloc;
89 : static __ptr_t (*_realloc)(__ptr_t, size_t) = __libc_realloc;
90 : static void (*_free)(__ptr_t) = __libc_free;
91 : static __ptr_t (*_memalign)(size_t, size_t) = __libc_memalign;
92 : static __ptr_t (*_valloc)(size_t) = __libc_valloc;
93 :
94 : NS_EXPORT_(__ptr_t) malloc(size_t size)
95 : {
96 : return _malloc(size);
97 : }
98 :
99 : NS_EXPORT_(__ptr_t) calloc(size_t nmemb, size_t size)
100 : {
101 : return _calloc(nmemb, size);
102 : }
103 :
104 : NS_EXPORT_(__ptr_t) realloc(__ptr_t ptr, size_t size)
105 : {
106 : return _realloc(ptr, size);
107 : }
108 :
109 : NS_EXPORT_(void) free(__ptr_t ptr)
110 : {
111 : _free(ptr);
112 : }
113 :
114 : NS_EXPORT_(void) cfree(__ptr_t ptr)
115 : {
116 : _free(ptr);
117 : }
118 :
119 : NS_EXPORT_(__ptr_t) memalign(size_t boundary, size_t size)
120 : {
121 : return _memalign(boundary, size);
122 : }
123 :
124 : NS_EXPORT_(int)
125 : posix_memalign(void **memptr, size_t alignment, size_t size)
126 : {
127 : __ptr_t ptr = _memalign(alignment, size);
128 : if (!ptr)
129 : return ENOMEM;
130 : *memptr = ptr;
131 : return 0;
132 : }
133 :
134 : NS_EXPORT_(__ptr_t) valloc(size_t size)
135 : {
136 : return _valloc(size);
137 : }
138 : #endif /* NS_TRACE_MALLOC */
139 :
140 : struct DependentLib
141 : {
142 : void *libHandle;
143 : DependentLib *next;
144 : };
145 :
146 : static DependentLib *sTop;
147 : static void* sXULLibHandle;
148 :
149 : static void
150 552 : AppendDependentLib(void *libHandle)
151 : {
152 552 : DependentLib *d = new DependentLib;
153 552 : if (!d)
154 0 : return;
155 :
156 552 : d->next = sTop;
157 552 : d->libHandle = libHandle;
158 :
159 552 : sTop = d;
160 : }
161 :
162 : #if defined(LINUX) && !defined(ANDROID)
163 : static const unsigned int bufsize = 4096;
164 :
165 : #ifdef HAVE_64BIT_OS
166 : typedef Elf64_Ehdr Elf_Ehdr;
167 : typedef Elf64_Phdr Elf_Phdr;
168 : static const unsigned char ELFCLASS = ELFCLASS64;
169 : typedef Elf64_Off Elf_Off;
170 : #else
171 : typedef Elf32_Ehdr Elf_Ehdr;
172 : typedef Elf32_Phdr Elf_Phdr;
173 : static const unsigned char ELFCLASS = ELFCLASS32;
174 : typedef Elf32_Off Elf_Off;
175 : #endif
176 :
177 : static void
178 506 : preload(const char *file)
179 : {
180 : union {
181 : char buf[bufsize];
182 : Elf_Ehdr ehdr;
183 : } elf;
184 506 : int fd = open(file, O_RDONLY);
185 506 : if (fd < 0)
186 0 : return;
187 : // Read ELF header (ehdr) and program header table (phdr).
188 : // We check that the ELF magic is found, that the ELF class matches
189 : // our own, and that the program header table as defined in the ELF
190 : // headers fits in the buffer we read.
191 1518 : if ((read(fd, elf.buf, bufsize) <= 0) ||
192 506 : (memcmp(elf.buf, ELFMAG, 4)) ||
193 506 : (elf.ehdr.e_ident[EI_CLASS] != ELFCLASS) ||
194 : (elf.ehdr.e_phoff + elf.ehdr.e_phentsize * elf.ehdr.e_phnum >= bufsize)) {
195 0 : close(fd);
196 0 : return;
197 : }
198 : // The program header table contains segment definitions. One such
199 : // segment type is PT_LOAD, which describes how the dynamic loader
200 : // is going to map the file in memory. We use that information to
201 : // find the biggest offset from the library that will be mapped in
202 : // memory.
203 506 : Elf_Phdr *phdr = (Elf_Phdr *)&elf.buf[elf.ehdr.e_phoff];
204 506 : Elf_Off end = 0;
205 2898 : for (int phnum = elf.ehdr.e_phnum; phnum; phdr++, phnum--)
206 2392 : if ((phdr->p_type == PT_LOAD) &&
207 : (end < phdr->p_offset + phdr->p_filesz))
208 1150 : end = phdr->p_offset + phdr->p_filesz;
209 : // Let the kernel read ahead what the dynamic loader is going to
210 : // map in memory soon after.
211 506 : if (end > 0) {
212 506 : readahead(fd, 0, end);
213 : }
214 506 : close(fd);
215 : }
216 : #endif
217 :
218 : static void
219 506 : ReadDependentCB(const char *aDependentLib, bool do_preload)
220 : {
221 : #if defined(LINUX) && !defined(ANDROID)
222 506 : if (do_preload)
223 506 : preload(aDependentLib);
224 : #endif
225 506 : void *libHandle = dlopen(aDependentLib, RTLD_GLOBAL | RTLD_LAZY);
226 506 : if (!libHandle)
227 0 : return;
228 :
229 506 : AppendDependentLib(libHandle);
230 : }
231 :
232 : nsresult
233 46 : XPCOMGlueLoad(const char *xpcomFile, GetFrozenFunctionsFunc *func)
234 : {
235 : char xpcomDir[MAXPATHLEN];
236 46 : if (realpath(xpcomFile, xpcomDir)) {
237 46 : char *lastSlash = strrchr(xpcomDir, '/');
238 46 : if (lastSlash) {
239 46 : *lastSlash = '\0';
240 :
241 46 : XPCOMGlueLoadDependentLibs(xpcomDir, ReadDependentCB);
242 :
243 : #ifdef __GLIBC__
244 : // XUL_DLL is already loaded by XPCOMGlueLoadDependentLibs, so
245 : // dlopening without the full path will return that one.
246 46 : sXULLibHandle = dlopen(XUL_DLL, RTLD_GLOBAL | RTLD_LAZY);
247 : #else
248 : snprintf(lastSlash, MAXPATHLEN - strlen(xpcomDir), "/" XUL_DLL);
249 :
250 : sXULLibHandle = dlopen(xpcomDir, RTLD_GLOBAL | RTLD_LAZY);
251 : #endif
252 :
253 : #ifdef NS_TRACE_MALLOC
254 : _malloc = (__ptr_t(*)(size_t)) dlsym(sXULLibHandle, "malloc");
255 : _calloc = (__ptr_t(*)(size_t, size_t)) dlsym(sXULLibHandle, "calloc");
256 : _realloc = (__ptr_t(*)(__ptr_t, size_t)) dlsym(sXULLibHandle, "realloc");
257 : _free = (void(*)(__ptr_t)) dlsym(sXULLibHandle, "free");
258 : _memalign = (__ptr_t(*)(size_t, size_t)) dlsym(sXULLibHandle, "memalign");
259 : _valloc = (__ptr_t(*)(size_t)) dlsym(sXULLibHandle, "valloc");
260 : #endif
261 : }
262 : }
263 :
264 : // RTLD_DEFAULT is not defined in non-GNU toolchains, and it is
265 : // (void*) 0 in any case.
266 :
267 46 : void *libHandle = nsnull;
268 :
269 46 : if (xpcomFile[0] != '.' || xpcomFile[1] != '\0') {
270 46 : libHandle = dlopen(xpcomFile, RTLD_GLOBAL | RTLD_LAZY);
271 46 : if (libHandle) {
272 46 : AppendDependentLib(libHandle);
273 : } else {
274 : fprintf(stderr, "XPCOMGlueLoad error for file %s:\n%s\n", xpcomFile,
275 0 : dlerror());
276 : }
277 : }
278 :
279 : GetFrozenFunctionsFunc sym =
280 : (GetFrozenFunctionsFunc) dlsym(libHandle,
281 46 : LEADING_UNDERSCORE "NS_GetFrozenFunctions");
282 :
283 46 : if (!sym) { // No symbol found.
284 0 : XPCOMGlueUnload();
285 0 : return NS_ERROR_NOT_AVAILABLE;
286 : }
287 :
288 46 : *func = sym;
289 :
290 46 : return NS_OK;
291 : }
292 :
293 : void
294 23 : XPCOMGlueUnload()
295 : {
296 322 : while (sTop) {
297 276 : dlclose(sTop->libHandle);
298 :
299 276 : DependentLib *temp = sTop;
300 276 : sTop = sTop->next;
301 :
302 276 : delete temp;
303 : }
304 :
305 23 : if (sXULLibHandle) {
306 : #ifdef NS_TRACE_MALLOC
307 : _malloc = __libc_malloc;
308 : _calloc = __libc_calloc;
309 : _realloc = __libc_realloc;
310 : _free = __libc_free;
311 : _memalign = __libc_memalign;
312 : _valloc = __libc_valloc;
313 : #endif
314 23 : dlclose(sXULLibHandle);
315 23 : sXULLibHandle = nsnull;
316 : }
317 23 : }
318 :
319 : nsresult
320 46 : XPCOMGlueLoadXULFunctions(const nsDynamicFunctionLoad *symbols)
321 : {
322 : // We don't null-check sXULLibHandle because this might work even
323 : // if it is null (same as RTLD_DEFAULT)
324 :
325 46 : nsresult rv = NS_OK;
326 322 : while (symbols->functionName) {
327 : char buffer[512];
328 : snprintf(buffer, sizeof(buffer),
329 230 : LEADING_UNDERSCORE "%s", symbols->functionName);
330 :
331 230 : *symbols->function = (NSFuncPtr) dlsym(sXULLibHandle, buffer);
332 230 : if (!*symbols->function)
333 0 : rv = NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
334 :
335 230 : ++symbols;
336 : }
337 46 : return rv;
338 : }
|