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