1 /** $MirOS: src/libexec/ld.so/dlfcn.c,v 1.8 2006/08/30 04:28:24 tg Exp $ */
2 /* $OpenBSD: dlfcn.c,v 1.73 2006/05/08 20:34:36 deraadt Exp $ */
3
4 /*
5 * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30 #define _DYN_LOADER
31
32 #include <sys/types.h>
33 #include <nlist.h>
34 #include <link.h>
35 #include <dlfcn.h>
36 #include <unistd.h>
37
38 #include "syscall.h"
39 #include "archdep.h"
40 #include "resolve.h"
41
42 __RCSID("$MirOS: src/libexec/ld.so/dlfcn.c,v 1.8 2006/08/30 04:28:24 tg Exp $");
43
44 int _dl_errno;
45
46 int _dl_real_close(void *handle);
47 void (*_dl_thread_fnc)(int) = NULL;
48 static elf_object_t *obj_from_addr(const void *addr);
49
50 void *
dlopen(const char * libname,int flags)51 dlopen(const char *libname, int flags)
52 {
53 elf_object_t *object;
54 int failed = 0;
55
56 if (libname == NULL)
57 return RTLD_DEFAULT;
58
59 if ((flags & RTLD_TRACE) == RTLD_TRACE)
60 _dl_traceld = true;
61
62 DL_DEB(("dlopen: loading: %s\n", libname));
63
64 _dl_thread_kern_stop();
65
66 if (_dl_debug_map->r_brk) {
67 _dl_debug_map->r_state = RT_ADD;
68 (*((void (*)(void))_dl_debug_map->r_brk))();
69 }
70
71 _dl_loading_object = NULL;
72
73 object = _dl_load_shlib(libname, _dl_objects, OBJTYPE_DLO, flags);
74 if (object == 0) {
75 DL_DEB(("dlopen: failed to open %s\n", libname));
76 failed = 1;
77 goto loaded;
78 }
79
80 _dl_link_dlopen(object);
81
82 if (OBJECT_REF_CNT(object) > 1) {
83 /* if opened but grpsym_list has not been created */
84 if (OBJECT_DLREF_CNT(object) == 1) {
85 /* add first object manually */
86 _dl_link_grpsym(object);
87 _dl_cache_grpsym_list(object);
88 }
89 goto loaded;
90 }
91
92 /* this add_object should not be here, XXX */
93 _dl_add_object(object);
94
95 DL_DEB(("head [%s]\n", object->load_name ));
96
97 if ((failed = _dl_load_dep_libs(object, flags, 0)) == 1) {
98 _dl_real_close(object);
99 object = NULL;
100 _dl_errno = DL_CANT_LOAD_OBJ;
101 } else {
102 int err;
103 DL_DEB(("tail %s\n", object->load_name ));
104 if (_dl_traceld) {
105 _dl_show_objects();
106 _dl_unload_shlib(object);
107 _dl_exit(0);
108 }
109 err = _dl_rtld(object);
110 if (err != 0) {
111 _dl_real_close(object);
112 _dl_errno = DL_CANT_LOAD_OBJ;
113 object = 0;
114 failed = 1;
115 } else {
116 _dl_call_init(object);
117 }
118 }
119
120 loaded:
121 _dl_loading_object = NULL;
122
123 if (_dl_debug_map->r_brk) {
124 _dl_debug_map->r_state = RT_CONSISTENT;
125 (*((void (*)(void))_dl_debug_map->r_brk))();
126 }
127
128 _dl_thread_kern_go();
129
130 DL_DEB(("dlopen: %s: done (%s).\n", libname,
131 failed ? "failed" : "success"));
132
133 return((void *)object);
134 }
135
136 void *
dlsym(void * handle,const char * name)137 dlsym(void *handle, const char *name)
138 {
139 elf_object_t *object;
140 elf_object_t *dynobj;
141 const elf_object_t *pobj;
142 void *retval;
143 const Elf_Sym *sym = NULL;
144 int flags;
145
146 if (handle == NULL || handle == RTLD_NEXT ||
147 handle == RTLD_SELF || handle == RTLD_DEFAULT) {
148 void *retaddr;
149
150 retaddr = __builtin_return_address(0); /* __GNUC__ only */
151
152 if ((object = obj_from_addr(retaddr)) == NULL) {
153 _dl_errno = DL_CANT_FIND_OBJ;
154 return(0);
155 }
156
157 if (handle == RTLD_NEXT)
158 flags = SYM_SEARCH_NEXT|SYM_PLT;
159 else if (handle == RTLD_SELF)
160 flags = SYM_SEARCH_SELF|SYM_PLT;
161 else if (handle == RTLD_DEFAULT)
162 flags = SYM_SEARCH_ALL|SYM_PLT;
163 else
164 flags = SYM_DLSYM|SYM_PLT;
165
166 } else {
167 object = (elf_object_t *)handle;
168 flags = SYM_DLSYM|SYM_PLT;
169
170 dynobj = _dl_objects;
171 while (dynobj && dynobj != object)
172 dynobj = dynobj->next;
173
174 if (!dynobj || object != dynobj) {
175 _dl_errno = DL_INVALID_HANDLE;
176 return(0);
177 }
178 }
179
180 retval = (void *)_dl_find_symbol(name, &sym,
181 flags|SYM_NOWARNNOTFOUND, NULL, object, &pobj);
182
183 if (sym != NULL) {
184 retval += sym->st_value;
185 #ifdef __hppa__
186 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC)
187 retval = (void *)_dl_md_plabel((Elf_Addr)retval,
188 pobj->dyn.pltgot);
189 #endif
190 DL_DEB(("dlsym: %s in %s: %p\n",
191 name, object->load_name, retval));
192 } else
193 _dl_errno = DL_NO_SYMBOL;
194 return (retval);
195 }
196
197 int
dlctl(void * handle,int command,void * data)198 dlctl(void *handle, int command, void *data)
199 {
200 int retval;
201
202 switch (command) {
203 case DL_SETTHREADLCK:
204 DL_DEB(("dlctl: _dl_thread_fnc set to %p\n", data));
205 _dl_thread_fnc = data;
206 retval = 0;
207 break;
208 case 0x20:
209 _dl_show_objects();
210 retval = 0;
211 break;
212 case 0x21:
213 {
214 struct dep_node *n, *m;
215 elf_object_t *obj;
216 _dl_printf("Load Groups:\n");
217
218 TAILQ_FOREACH(n, &_dlopened_child_list, next_sib) {
219 obj = n->data;
220 _dl_printf("%s\n", obj->load_name);
221
222 _dl_printf(" children\n");
223 TAILQ_FOREACH(m, &obj->child_list, next_sib)
224 _dl_printf("\t[%s]\n", m->data->load_name);
225
226 _dl_printf(" grpref\n");
227 TAILQ_FOREACH(m, &obj->grpref_list, next_sib)
228 _dl_printf("\t[%s]\n", m->data->load_name);
229 _dl_printf("\n");
230 }
231 retval = 0;
232 break;
233 }
234 default:
235 _dl_errno = DL_INVALID_CTL;
236 retval = -1;
237 break;
238 }
239 return (retval);
240 }
241
242 int
dlclose(void * handle)243 dlclose(void *handle)
244 {
245 int retval;
246
247 if (handle == RTLD_DEFAULT)
248 return 0;
249
250 _dl_thread_kern_stop();
251
252 if (_dl_debug_map->r_brk) {
253 _dl_debug_map->r_state = RT_DELETE;
254 (*((void (*)(void))_dl_debug_map->r_brk))();
255 }
256
257 retval = _dl_real_close(handle);
258
259
260 if (_dl_debug_map->r_brk) {
261 _dl_debug_map->r_state = RT_CONSISTENT;
262 (*((void (*)(void))_dl_debug_map->r_brk))();
263 }
264 _dl_thread_kern_go();
265 return (retval);
266 }
267
268 int
_dl_real_close(void * handle)269 _dl_real_close(void *handle)
270 {
271 elf_object_t *object;
272 elf_object_t *dynobj;
273
274 object = (elf_object_t *)handle;
275
276 dynobj = _dl_objects;
277 while (dynobj && dynobj != object)
278 dynobj = dynobj->next;
279
280 if (!dynobj || object != dynobj) {
281 _dl_errno = DL_INVALID_HANDLE;
282 return (1);
283 }
284
285 if (object->opencount == 0) {
286 _dl_errno = DL_INVALID_HANDLE;
287 return (1);
288 }
289
290 object->opencount--;
291 _dl_notify_unload_shlib(object);
292 _dl_run_all_dtors();
293 _dl_unload_shlib(object);
294 _dl_cleanup_objects();
295 return (0);
296 }
297
298
299 /*
300 * Return a character string describing the last dl... error occurred.
301 */
302 const char *
dlerror(void)303 dlerror(void)
304 {
305 const char *errmsg;
306
307 switch (_dl_errno) {
308 case 0: /* NO ERROR */
309 errmsg = NULL;
310 break;
311 case DL_NOT_FOUND:
312 errmsg = "File not found";
313 break;
314 case DL_CANT_OPEN:
315 errmsg = "Can't open file";
316 break;
317 case DL_NOT_ELF:
318 errmsg = "File not an ELF object";
319 break;
320 case DL_CANT_OPEN_REF:
321 errmsg = "Can't open referenced object";
322 break;
323 case DL_CANT_MMAP:
324 errmsg = "Can't map ELF object";
325 break;
326 case DL_INVALID_HANDLE:
327 errmsg = "Invalid handle";
328 break;
329 case DL_NO_SYMBOL:
330 errmsg = "Unable to resolve symbol";
331 break;
332 case DL_INVALID_CTL:
333 errmsg = "Invalid dlctl() command";
334 break;
335 case DL_NO_OBJECT:
336 errmsg = "No shared object contains address";
337 break;
338 case DL_CANT_FIND_OBJ:
339 errmsg = "Cannot determine caller's shared object";
340 break;
341 case DL_CANT_LOAD_OBJ:
342 errmsg = "Cannot load specified object";
343 break;
344 default:
345 errmsg = "Unknown error";
346 }
347
348 _dl_errno = 0;
349 return (errmsg);
350 }
351
352 void
_dl_show_objects(void)353 _dl_show_objects(void)
354 {
355 elf_object_t *object;
356 char *objtypename;
357 int outputfd;
358
359 object = _dl_objects;
360 outputfd = _dl_traceld ? STDOUT_FILENO : STDERR_FILENO;
361
362 if (sizeof(long) == 8)
363 _dl_fdprintf(outputfd, "\tStart End Type Open Ref GrpRef Name\n");
364 else
365 _dl_fdprintf(outputfd, "\tStart End Type Open Ref GrpRef Name\n");
366
367 while (object) {
368 switch (object->obj_type) {
369 case OBJTYPE_LDR:
370 objtypename = "rtld";
371 break;
372 case OBJTYPE_EXE:
373 if (!_dl_debug)
374 goto _dl_show_objects_skip;
375 objtypename = "exe ";
376 break;
377 case OBJTYPE_LIB:
378 objtypename = "rlib";
379 break;
380 case OBJTYPE_DLO:
381 if (!_dl_debug)
382 goto _dl_show_objects_skip;
383 objtypename = "dlib";
384 break;
385 default:
386 objtypename = "????";
387 break;
388 }
389 _dl_fdprintf(outputfd, "\t%lX %lX %s %d %d %d %s\n",
390 (void *)object->load_addr,
391 (void *)(object->load_addr + object->load_size),
392 objtypename, object->opencount, object->refcount,
393 object->grprefcount, object->load_name);
394 _dl_show_objects_skip:
395 object = object->next;
396 }
397
398 if (_dl_symcachestat_lookups != 0)
399 DL_DEB(("symcache lookups %d hits %d ratio %d% hits\n",
400 _dl_symcachestat_lookups, _dl_symcachestat_hits,
401 (_dl_symcachestat_hits * 100) /
402 _dl_symcachestat_lookups));
403 }
404
405 void
_dl_thread_kern_stop(void)406 _dl_thread_kern_stop(void)
407 {
408 if (_dl_thread_fnc != NULL)
409 (*_dl_thread_fnc)(0);
410 }
411
412 void
_dl_thread_kern_go(void)413 _dl_thread_kern_go(void)
414 {
415 if (_dl_thread_fnc != NULL)
416 (*_dl_thread_fnc)(1);
417 }
418
419 int
dl_iterate_phdr(int (* callback)(struct dl_phdr_info *,size_t,void * data),void * data)420 dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *data),
421 void *data)
422 {
423 elf_object_t *object;
424 Elf_Ehdr *ehdr;
425 struct dl_phdr_info info;
426 int retval = -1;
427
428 for (object = _dl_objects; object != NULL; object = object->next) {
429 ehdr = (Elf_Ehdr *)object->load_addr;
430 if (object->phdrp == NULL && ehdr == NULL)
431 continue;
432
433 info.dlpi_addr = object->load_addr;
434 info.dlpi_name = object->load_name;
435 info.dlpi_phdr = object->phdrp;
436 info.dlpi_phnum = object->phdrc;
437 if (info.dlpi_phdr == NULL) {
438 info.dlpi_phdr = (Elf_Phdr *)
439 ((char *)object->load_addr + ehdr->e_phoff);
440 info.dlpi_phnum = ehdr->e_phnum;
441 }
442 retval = callback(&info, sizeof (struct dl_phdr_info), data);
443 if (retval)
444 break;
445 }
446
447 return retval;
448 }
449
450 static elf_object_t *
obj_from_addr(const void * addr)451 obj_from_addr(const void *addr)
452 {
453 elf_object_t *dynobj;
454 Elf_Ehdr *ehdr;
455 Elf_Phdr *phdr;
456 Elf_Addr start;
457 Elf_Addr end;
458 u_int32_t symoffset;
459 const Elf_Sym *sym;
460 int i;
461
462 for (dynobj = _dl_objects; dynobj != NULL; dynobj = dynobj->next) {
463 ehdr = (Elf_Ehdr *)dynobj->load_addr;
464 if (ehdr == NULL)
465 continue;
466
467 phdr = (Elf_Phdr *)((char *)dynobj->load_addr + ehdr->e_phoff);
468
469 for (i = 0; i < ehdr->e_phnum; i++) {
470 switch (phdr[i].p_type) {
471 case PT_LOAD:
472 start = phdr[i].p_vaddr + dynobj->load_addr;
473 if ((Elf_Addr)addr >= start &&
474 (Elf_Addr)addr < start + phdr[i].p_memsz)
475 return dynobj;
476 break;
477 default:
478 break;
479 }
480 }
481 }
482
483 /* find the lowest & highest symbol address in the main exe */
484 start = -1;
485 end = 0;
486
487 for (symoffset = 0; symoffset < _dl_objects->nchains; symoffset++) {
488 sym = _dl_objects->dyn.symtab + symoffset;
489
490 /*
491 * For skip the symbol if st_shndx is either SHN_UNDEF or
492 * SHN_COMMON.
493 */
494 if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON)
495 continue;
496
497 if (sym->st_value < start)
498 start = sym->st_value;
499
500 if (sym->st_value > end)
501 end = sym->st_value;
502 }
503
504 if (end && (Elf_Addr) addr >= start && (Elf_Addr) addr <= end)
505 return _dl_objects;
506 else
507 return NULL;
508 }
509
510 int
dladdr(const void * addr,Dl_info * info)511 dladdr(const void *addr, Dl_info *info)
512 {
513 const elf_object_t *object;
514 const Elf_Sym *sym;
515 void *symbol_addr;
516 u_int32_t symoffset;
517
518 object = obj_from_addr(addr);
519
520 if (object == NULL) {
521 _dl_errno = DL_NO_OBJECT;
522 return 0;
523 }
524
525 info->dli_fname = (char *)object->load_name;
526 info->dli_fbase = (void *)object->load_addr;
527 info->dli_sname = NULL;
528 info->dli_saddr = (void *)0;
529
530 /*
531 * Walk the symbol list looking for the symbol whose address is
532 * closest to the address sent in.
533 */
534 for (symoffset = 0; symoffset < object->nchains; symoffset++) {
535 sym = object->dyn.symtab + symoffset;
536
537 /*
538 * For skip the symbol if st_shndx is either SHN_UNDEF or
539 * SHN_COMMON.
540 */
541 if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON)
542 continue;
543
544 /*
545 * If the symbol is greater than the specified address, or if
546 * it is further away from addr than the current nearest
547 * symbol, then reject it.
548 */
549 symbol_addr = (void *)(object->load_addr + sym->st_value);
550 if (symbol_addr > addr || symbol_addr < info->dli_saddr)
551 continue;
552
553 /* Update our idea of the nearest symbol. */
554 info->dli_sname = object->dyn.strtab + sym->st_name;
555 info->dli_saddr = symbol_addr;
556
557 /* Exact match? */
558 if (info->dli_saddr == addr)
559 break;
560 }
561
562 return 1;
563 }
564