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