xref: /openbsd-src/libexec/ld.so/dlfcn.c (revision 210cc31ee7e6dd0fb4a22aeade973d93c561e538)
1*210cc31eSderaadt /*	$OpenBSD: dlfcn.c,v 1.117 2024/01/22 02:08:31 deraadt Exp $ */
24d11faf9Srahnds 
34d11faf9Srahnds /*
44d11faf9Srahnds  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
54d11faf9Srahnds  *
64d11faf9Srahnds  * Redistribution and use in source and binary forms, with or without
74d11faf9Srahnds  * modification, are permitted provided that the following conditions
84d11faf9Srahnds  * are met:
94d11faf9Srahnds  * 1. Redistributions of source code must retain the above copyright
104d11faf9Srahnds  *    notice, this list of conditions and the following disclaimer.
114d11faf9Srahnds  * 2. Redistributions in binary form must reproduce the above copyright
124d11faf9Srahnds  *    notice, this list of conditions and the following disclaimer in the
134d11faf9Srahnds  *    documentation and/or other materials provided with the distribution.
144d11faf9Srahnds  *
154d11faf9Srahnds  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
164d11faf9Srahnds  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
174d11faf9Srahnds  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
184d11faf9Srahnds  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
194d11faf9Srahnds  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
204d11faf9Srahnds  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
214d11faf9Srahnds  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
224d11faf9Srahnds  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
234d11faf9Srahnds  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
244d11faf9Srahnds  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
254d11faf9Srahnds  * SUCH DAMAGE.
264d11faf9Srahnds  *
274d11faf9Srahnds  */
284d11faf9Srahnds 
294d11faf9Srahnds #define _DYN_LOADER
304d11faf9Srahnds 
314d11faf9Srahnds #include <sys/types.h>
324d11faf9Srahnds #include <link.h>
334d11faf9Srahnds #include <dlfcn.h>
34921d95f2Sdrahn #include <unistd.h>
354d11faf9Srahnds 
364d11faf9Srahnds #include "syscall.h"
37b722ba42Sguenther #include "util.h"
384d11faf9Srahnds #include "resolve.h"
39fa1e3a20Sderaadt #include "archdep.h"
404d11faf9Srahnds 
414d11faf9Srahnds int _dl_errno;
424d11faf9Srahnds 
43bfc90735Sguenther static int _dl_real_close(void *handle);
4497e4ddacSguenther static lock_cb *_dl_thread_fnc = NULL;
45a4baf06aSdrahn static elf_object_t *obj_from_addr(const void *addr);
464d11faf9Srahnds 
47ab4d5173Ssthen #define OK_FLAGS	(0 \
48ab4d5173Ssthen 	| RTLD_TRACE	\
49ab4d5173Ssthen 	| RTLD_LAZY	\
50ab4d5173Ssthen 	| RTLD_NOW	\
51ab4d5173Ssthen 	| RTLD_GLOBAL	\
52ab4d5173Ssthen 	| RTLD_NODELETE	\
53ab4d5173Ssthen 	| RTLD_NOLOAD	\
54ab4d5173Ssthen 	)
55ab4d5173Ssthen 
564d11faf9Srahnds void *
dlopen(const char * libname,int flags)5750f3e86fSdrahn dlopen(const char *libname, int flags)
584d11faf9Srahnds {
5967939fc6Skurt 	elf_object_t *object;
6097e4ddacSguenther 	lock_cb *cb;
6183b41cf4Sdrahn 	int failed = 0;
620fdecfd0Sguenther 	int obj_flags;
630fdecfd0Sguenther 
64ab4d5173Ssthen 	if (flags & ~OK_FLAGS) {
650fdecfd0Sguenther 		_dl_errno = DL_INVALID_MODE;
660fdecfd0Sguenther 		return NULL;
670fdecfd0Sguenther 	}
684d11faf9Srahnds 
6939b7d201Sderaadt 	if (libname == NULL)
70744baae2Skurt 		return RTLD_DEFAULT;
7139b7d201Sderaadt 
722e10aa31Sjason 	if ((flags & RTLD_TRACE) == RTLD_TRACE) {
7310200827Sguenther 		_dl_traceld = 1;
742e10aa31Sjason 	}
752e10aa31Sjason 
765071ef9aSart 	DL_DEB(("dlopen: loading: %s\n", libname));
779c8de590Sart 
7897e4ddacSguenther 	cb = _dl_thread_kern_stop();
790acae5e5Sdrahn 
80d016b249Skettenis 	if (_dl_debug_map && _dl_debug_map->r_brk) {
81b17edb7aSdrahn 		_dl_debug_map->r_state = RT_ADD;
82b17edb7aSdrahn 		(*((void (*)(void))_dl_debug_map->r_brk))();
83b17edb7aSdrahn 	}
84b17edb7aSdrahn 
8597ba1a81Skurt 	_dl_loading_object = NULL;
8697ba1a81Skurt 
870fdecfd0Sguenther 	obj_flags = (flags & RTLD_NOW ? DF_1_NOW : 0)
88ab4d5173Ssthen 	    | (flags & RTLD_GLOBAL ? DF_1_GLOBAL : 0)
89ab4d5173Ssthen 	    | (flags & RTLD_NOLOAD ? DF_1_NOOPEN : 0)
90ab4d5173Ssthen 	    ;
9107cf23bbSderaadt 	object = _dl_load_shlib(libname, _dl_objects, OBJTYPE_DLO, obj_flags, 0);
9270be5820Sdrahn 	if (object == 0) {
9383b41cf4Sdrahn 		DL_DEB(("dlopen: failed to open %s\n", libname));
9461632685Sdrahn 		failed = 1;
9561632685Sdrahn 		goto loaded;
9670be5820Sdrahn 	}
972c5b63afSdrahn 
98b75fe819Sderaadt 	if (flags & RTLD_NODELETE) {
99296fbf9fSsemarie 		object->obj_flags |= DF_1_NODELETE;
100b75fe819Sderaadt 		object->nodelete = 1;
101b75fe819Sderaadt 	}
102296fbf9fSsemarie 
1032c5b63afSdrahn 	_dl_link_dlopen(object);
1042c5b63afSdrahn 
105ea03aff5Skurt 	if (OBJECT_REF_CNT(object) > 1) {
106296fbf9fSsemarie 		_dl_handle_nodelete(object);
107296fbf9fSsemarie 
108bae526eeSguenther 		/* if opened but grpsym_vec has not been filled in */
109bae526eeSguenther 		if (object->grpsym_vec.len == 0)
110bae526eeSguenther 			_dl_cache_grpsym_list_setup(object);
111ac42b3c8Sguenther 		if (_dl_traceld) {
112ac42b3c8Sguenther 			_dl_show_objects(object);
113ac42b3c8Sguenther 			_dl_unload_shlib(object);
114ac42b3c8Sguenther 			_dl_exit(0);
115ac42b3c8Sguenther 		}
11661632685Sdrahn 		goto loaded;
117ea03aff5Skurt 	}
1184d11faf9Srahnds 
1190acae5e5Sdrahn 	/* this add_object should not be here, XXX */
1200acae5e5Sdrahn 	_dl_add_object(object);
1210acae5e5Sdrahn 
1220acae5e5Sdrahn 	DL_DEB(("head [%s]\n", object->load_name));
1230acae5e5Sdrahn 
1240fdecfd0Sguenther 	if ((failed = _dl_load_dep_libs(object, obj_flags, 0)) == 1) {
12583b41cf4Sdrahn 		_dl_real_close(object);
12683b41cf4Sdrahn 		object = NULL;
12783b41cf4Sdrahn 		_dl_errno = DL_CANT_LOAD_OBJ;
12883b41cf4Sdrahn 	} else {
12961632685Sdrahn 		int err;
13083b41cf4Sdrahn 		DL_DEB(("tail %s\n", object->load_name));
1312e10aa31Sjason 		if (_dl_traceld) {
132ac42b3c8Sguenther 			_dl_show_objects(object);
1332e10aa31Sjason 			_dl_unload_shlib(object);
1342e10aa31Sjason 			_dl_exit(0);
1352e10aa31Sjason 		}
13661632685Sdrahn 		err = _dl_rtld(object);
13761632685Sdrahn 		if (err != 0) {
13861632685Sdrahn 			_dl_real_close(object);
13961632685Sdrahn 			_dl_errno = DL_CANT_LOAD_OBJ;
140d64ca068Smmcc 			object = NULL;
14161632685Sdrahn 			failed = 1;
14261632685Sdrahn 		} else {
1434d11faf9Srahnds 			_dl_call_init(object);
14483b41cf4Sdrahn 		}
14561632685Sdrahn 	}
146034b0143Sdrahn 
14761632685Sdrahn loaded:
1482c5b63afSdrahn 	_dl_loading_object = NULL;
1492c5b63afSdrahn 
150d016b249Skettenis 	if (_dl_debug_map && _dl_debug_map->r_brk) {
1514d11faf9Srahnds 		_dl_debug_map->r_state = RT_CONSISTENT;
152c258a5d6Sderaadt 		(*((void (*)(void))_dl_debug_map->r_brk))();
1534d11faf9Srahnds 	}
154e0ddfd1bSmickey 
15597e4ddacSguenther 	_dl_thread_kern_go(cb);
1560acae5e5Sdrahn 
15783b41cf4Sdrahn 	DL_DEB(("dlopen: %s: done (%s).\n", libname,
15883b41cf4Sdrahn 	    failed ? "failed" : "success"));
159e0ddfd1bSmickey 
1604d11faf9Srahnds 	return((void *)object);
1614d11faf9Srahnds }
1624d11faf9Srahnds 
1634d11faf9Srahnds void *
dlsym(void * handle,const char * name)1644d11faf9Srahnds dlsym(void *handle, const char *name)
1654d11faf9Srahnds {
1664d11faf9Srahnds 	elf_object_t	*object;
1674d11faf9Srahnds 	elf_object_t	*dynobj;
168143e5accSguenther 	struct sym_res	sr;
1697be38e1cSdrahn 	int		flags;
170143e5accSguenther 	Elf_Addr	addr;
1714d11faf9Srahnds 
1727be38e1cSdrahn 	if (handle == NULL || handle == RTLD_NEXT ||
1730ebcf49dSkurt 	    handle == RTLD_SELF || handle == RTLD_DEFAULT) {
1747be38e1cSdrahn 		void *retaddr;
1757be38e1cSdrahn 
1767be38e1cSdrahn 		retaddr = __builtin_return_address(0);	/* __GNUC__ only */
1777be38e1cSdrahn 
1787be38e1cSdrahn 		if ((object = obj_from_addr(retaddr)) == NULL) {
1797be38e1cSdrahn 			_dl_errno = DL_CANT_FIND_OBJ;
1807be38e1cSdrahn 			return(0);
1817be38e1cSdrahn 		}
1827be38e1cSdrahn 
1830acae5e5Sdrahn 		if (handle == RTLD_NEXT)
1840acae5e5Sdrahn 			flags = SYM_SEARCH_NEXT|SYM_PLT;
1850acae5e5Sdrahn 		else if (handle == RTLD_SELF)
1867be38e1cSdrahn 			flags = SYM_SEARCH_SELF|SYM_PLT;
1870ebcf49dSkurt 		else if (handle == RTLD_DEFAULT)
1880ebcf49dSkurt 			flags = SYM_SEARCH_ALL|SYM_PLT;
1897be38e1cSdrahn 		else
1900acae5e5Sdrahn 			flags = SYM_DLSYM|SYM_PLT;
1917be38e1cSdrahn 
1927be38e1cSdrahn 	} else {
1934d11faf9Srahnds 		object = (elf_object_t *)handle;
1940acae5e5Sdrahn 		flags = SYM_DLSYM|SYM_PLT;
1957be38e1cSdrahn 
1964d11faf9Srahnds 		dynobj = _dl_objects;
19739b7d201Sderaadt 		while (dynobj && dynobj != object)
1984d11faf9Srahnds 			dynobj = dynobj->next;
19939b7d201Sderaadt 
2004d11faf9Srahnds 		if (!dynobj || object != dynobj) {
2014d11faf9Srahnds 			_dl_errno = DL_INVALID_HANDLE;
2024d11faf9Srahnds 			return(0);
2034d11faf9Srahnds 		}
2047be38e1cSdrahn 	}
2054d11faf9Srahnds 
206143e5accSguenther 	sr = _dl_find_symbol(name, flags|SYM_NOWARNNOTFOUND, NULL, object);
207143e5accSguenther 	if (sr.sym == NULL) {
208052aa85fSjcs 		DL_DEB(("dlsym: failed to find symbol %s\n", name));
209143e5accSguenther 		_dl_errno = DL_NO_SYMBOL;
210143e5accSguenther 		return NULL;
211143e5accSguenther 	}
2127be38e1cSdrahn 
213143e5accSguenther 	addr = sr.obj->obj_base + sr.sym->st_value;
214f865bc82Smickey #ifdef __hppa__
215143e5accSguenther 	if (ELF_ST_TYPE(sr.sym->st_info) == STT_FUNC)
216143e5accSguenther 		addr = _dl_md_plabel(addr, sr.obj->dyn.pltgot);
217f865bc82Smickey #endif
218f865bc82Smickey 	DL_DEB(("dlsym: %s in %s: %p\n",
219143e5accSguenther 	    name, object->load_name, (void *)addr));
220143e5accSguenther 	return (void *)addr;
2214d11faf9Srahnds }
2224d11faf9Srahnds 
2234d11faf9Srahnds int
dlctl(void * handle,int command,void * data)2244d11faf9Srahnds dlctl(void *handle, int command, void *data)
2254d11faf9Srahnds {
226a2a95eaeSmarc 	int retval;
227a2a95eaeSmarc 
2284d11faf9Srahnds 	switch (command) {
229a2a95eaeSmarc 	case DL_SETTHREADLCK:
230a2a95eaeSmarc 		DL_DEB(("dlctl: _dl_thread_fnc set to %p\n", data));
231a2a95eaeSmarc 		_dl_thread_fnc = data;
232a2a95eaeSmarc 		retval = 0;
233a2a95eaeSmarc 		break;
2341e440e15Sdrahn 	case DL_SETBINDLCK:
235af5c7238Sguenther 		/* made superfluous by kbind */
2361e440e15Sdrahn 		retval = 0;
2371e440e15Sdrahn 		break;
238a0d792cdSkettenis 	case DL_REFERENCE:
239a0d792cdSkettenis 	{
240a0d792cdSkettenis 		elf_object_t *obj;
241a0d792cdSkettenis 
242a0d792cdSkettenis 		obj = obj_from_addr(data);
243a0d792cdSkettenis 		if (obj == NULL) {
244a0d792cdSkettenis 			_dl_errno = DL_CANT_FIND_OBJ;
245a0d792cdSkettenis 			retval = -1;
246a0d792cdSkettenis 			break;
247a0d792cdSkettenis 		}
248a0d792cdSkettenis 		if ((obj->status & STAT_NODELETE) == 0) {
249a0d792cdSkettenis 			obj->opencount++;
250a0d792cdSkettenis 			obj->status |= STAT_NODELETE;
251a0d792cdSkettenis 		}
252a0d792cdSkettenis 		retval = 0;
253a0d792cdSkettenis 		break;
254a0d792cdSkettenis 	}
2559454ede3Sdrahn 	case 0x20:
256ac42b3c8Sguenther 		_dl_show_objects(NULL);
2579454ede3Sdrahn 		retval = 0;
2589454ede3Sdrahn 		break;
2599454ede3Sdrahn 	case 0x21:
2609454ede3Sdrahn 	{
261d937a926Sguenther 		struct object_vector vec;
2629454ede3Sdrahn 		struct dep_node *n, *m;
2639454ede3Sdrahn 		elf_object_t *obj;
264d937a926Sguenther 		int i;
265d937a926Sguenther 
2669454ede3Sdrahn 		_dl_printf("Load Groups:\n");
2679454ede3Sdrahn 
2689454ede3Sdrahn 		TAILQ_FOREACH(n, &_dlopened_child_list, next_sib) {
2699454ede3Sdrahn 			obj = n->data;
2709454ede3Sdrahn 			_dl_printf("%s\n", obj->load_name);
2719454ede3Sdrahn 
2729454ede3Sdrahn 			_dl_printf("  children\n");
273d937a926Sguenther 			for (vec = obj->child_vec, i = 0; i < vec.len; i++)
274d937a926Sguenther 				_dl_printf("\t[%s]\n", vec.vec[i]->load_name);
2759454ede3Sdrahn 
2769454ede3Sdrahn 			_dl_printf("  grpref\n");
2779454ede3Sdrahn 			TAILQ_FOREACH(m, &obj->grpref_list, next_sib)
2789454ede3Sdrahn 				_dl_printf("\t[%s]\n", m->data->load_name);
2799454ede3Sdrahn 			_dl_printf("\n");
2809454ede3Sdrahn 		}
2819454ede3Sdrahn 		retval = 0;
2829454ede3Sdrahn 		break;
2839454ede3Sdrahn 	}
2844d11faf9Srahnds 	default:
2854d11faf9Srahnds 		_dl_errno = DL_INVALID_CTL;
286a2a95eaeSmarc 		retval = -1;
2874d11faf9Srahnds 		break;
2884d11faf9Srahnds 	}
289a2a95eaeSmarc 	return (retval);
2904d11faf9Srahnds }
29111ee7b6eSguenther __strong_alias(_dlctl,dlctl);
2924d11faf9Srahnds 
2934d11faf9Srahnds int
dlclose(void * handle)2944d11faf9Srahnds dlclose(void *handle)
2954d11faf9Srahnds {
29697e4ddacSguenther 	lock_cb *cb;
2974d11faf9Srahnds 	int retval;
2984d11faf9Srahnds 
299744baae2Skurt 	if (handle == RTLD_DEFAULT)
300166b3c7fSdrahn 		return 0;
30139b7d201Sderaadt 
30297e4ddacSguenther 	cb = _dl_thread_kern_stop();
3030acae5e5Sdrahn 
304d016b249Skettenis 	if (_dl_debug_map && _dl_debug_map->r_brk) {
3054d11faf9Srahnds 		_dl_debug_map->r_state = RT_DELETE;
306c258a5d6Sderaadt 		(*((void (*)(void))_dl_debug_map->r_brk))();
307b17edb7aSdrahn 	}
308b17edb7aSdrahn 
309b17edb7aSdrahn 	retval = _dl_real_close(handle);
310b17edb7aSdrahn 
311d016b249Skettenis 	if (_dl_debug_map && _dl_debug_map->r_brk) {
3124d11faf9Srahnds 		_dl_debug_map->r_state = RT_CONSISTENT;
313c258a5d6Sderaadt 		(*((void (*)(void))_dl_debug_map->r_brk))();
3144d11faf9Srahnds 	}
31597e4ddacSguenther 	_dl_thread_kern_go(cb);
3164d11faf9Srahnds 	return (retval);
3174d11faf9Srahnds }
3184d11faf9Srahnds 
319034b0143Sdrahn int
_dl_real_close(void * handle)3204d11faf9Srahnds _dl_real_close(void *handle)
3214d11faf9Srahnds {
3224d11faf9Srahnds 	elf_object_t	*object;
3234d11faf9Srahnds 	elf_object_t	*dynobj;
3244d11faf9Srahnds 
3254d11faf9Srahnds 	object = (elf_object_t *)handle;
326eefddc0cSkurt 
3274d11faf9Srahnds 	dynobj = _dl_objects;
32839b7d201Sderaadt 	while (dynobj && dynobj != object)
3294d11faf9Srahnds 		dynobj = dynobj->next;
33039b7d201Sderaadt 
3314d11faf9Srahnds 	if (!dynobj || object != dynobj) {
3324d11faf9Srahnds 		_dl_errno = DL_INVALID_HANDLE;
3334d11faf9Srahnds 		return (1);
3344d11faf9Srahnds 	}
3354d11faf9Srahnds 
336b0ad12a1Skurt 	if (object->opencount == 0) {
337b0ad12a1Skurt 		_dl_errno = DL_INVALID_HANDLE;
338b0ad12a1Skurt 		return (1);
339b0ad12a1Skurt 	}
340b0ad12a1Skurt 
34150cabf59Skurt 	object->opencount--;
342a4baf06aSdrahn 	_dl_notify_unload_shlib(object);
343a4baf06aSdrahn 	_dl_run_all_dtors();
3444d11faf9Srahnds 	_dl_unload_shlib(object);
3458a1e31c9Sdrahn 	_dl_cleanup_objects();
3464d11faf9Srahnds 	return (0);
3474d11faf9Srahnds }
3484d11faf9Srahnds 
3494d11faf9Srahnds 
3504d11faf9Srahnds /*
35161e6c220Smpech  * Return a character string describing the last dl... error occurred.
3524d11faf9Srahnds  */
353ca229a5cSderaadt char *
dlerror(void)354896cf611Sderaadt dlerror(void)
3554d11faf9Srahnds {
356ca229a5cSderaadt 	char *errmsg;
357376d5f5bSmillert 
3584d11faf9Srahnds 	switch (_dl_errno) {
359eef1d0e7Sdrahn 	case 0:	/* NO ERROR */
360376d5f5bSmillert 		errmsg = NULL;
361384956ccSmillert 		break;
3624d11faf9Srahnds 	case DL_NOT_FOUND:
363376d5f5bSmillert 		errmsg = "File not found";
364384956ccSmillert 		break;
3654d11faf9Srahnds 	case DL_CANT_OPEN:
366376d5f5bSmillert 		errmsg = "Can't open file";
367384956ccSmillert 		break;
3684d11faf9Srahnds 	case DL_NOT_ELF:
369376d5f5bSmillert 		errmsg = "File not an ELF object";
370384956ccSmillert 		break;
3714d11faf9Srahnds 	case DL_CANT_OPEN_REF:
372376d5f5bSmillert 		errmsg = "Can't open referenced object";
373384956ccSmillert 		break;
3744d11faf9Srahnds 	case DL_CANT_MMAP:
375376d5f5bSmillert 		errmsg = "Can't map ELF object";
376384956ccSmillert 		break;
3774d11faf9Srahnds 	case DL_INVALID_HANDLE:
378376d5f5bSmillert 		errmsg = "Invalid handle";
379384956ccSmillert 		break;
3804d11faf9Srahnds 	case DL_NO_SYMBOL:
381376d5f5bSmillert 		errmsg = "Unable to resolve symbol";
382384956ccSmillert 		break;
3834d11faf9Srahnds 	case DL_INVALID_CTL:
384376d5f5bSmillert 		errmsg = "Invalid dlctl() command";
385384956ccSmillert 		break;
3867be38e1cSdrahn 	case DL_NO_OBJECT:
3877be38e1cSdrahn 		errmsg = "No shared object contains address";
3887be38e1cSdrahn 		break;
3897be38e1cSdrahn 	case DL_CANT_FIND_OBJ:
3907be38e1cSdrahn 		errmsg = "Cannot determine caller's shared object";
3917be38e1cSdrahn 		break;
39283b41cf4Sdrahn 	case DL_CANT_LOAD_OBJ:
39383b41cf4Sdrahn 		errmsg = "Cannot load specified object";
39483b41cf4Sdrahn 		break;
3950fdecfd0Sguenther 	case DL_INVALID_MODE:
3960fdecfd0Sguenther 		errmsg = "Invalid mode";
3970fdecfd0Sguenther 		break;
3984d11faf9Srahnds 	default:
399376d5f5bSmillert 		errmsg = "Unknown error";
4004d11faf9Srahnds 	}
401376d5f5bSmillert 
402376d5f5bSmillert 	_dl_errno = 0;
403376d5f5bSmillert 	return (errmsg);
4044d11faf9Srahnds }
4054d11faf9Srahnds 
4062f86c0efSderaadt static void
_dl_tracefmt(int fd,elf_object_t * object,const char * fmt1,const char * fmt2,const char * objtypename)407c28b164bSjason _dl_tracefmt(int fd, elf_object_t *object, const char *fmt1, const char *fmt2,
408c28b164bSjason     const char *objtypename)
409c28b164bSjason {
410c28b164bSjason 	const char *fmt;
411c28b164bSjason 	int i;
412c28b164bSjason 
4131331cca4Smatthew 	fmt = object->sod.sod_library ? fmt1 : fmt2;
414c28b164bSjason 
415c28b164bSjason 	for (i = 0; fmt[i]; i++) {
416c28b164bSjason 		if (fmt[i] != '%' && fmt[i] != '\\') {
4174ce84164Sderaadt 			_dl_dprintf(fd, "%c", fmt[i]);
418c28b164bSjason 			continue;
419c28b164bSjason 		}
420c28b164bSjason 		if (fmt[i] == '%') {
421c28b164bSjason 			i++;
422c28b164bSjason 			switch (fmt[i]) {
423c28b164bSjason 			case '\0':
424c28b164bSjason 				return;
425c28b164bSjason 			case '%':
4264ce84164Sderaadt 				_dl_dprintf(fd, "%c", '%');
427c28b164bSjason 				break;
428c28b164bSjason 			case 'A':
4294ce84164Sderaadt 				_dl_dprintf(fd, "%s", _dl_traceprog ?
430c28b164bSjason 				    _dl_traceprog : "");
431c28b164bSjason 				break;
432c28b164bSjason 			case 'a':
4334ce84164Sderaadt 				_dl_dprintf(fd, "%s", __progname);
434c28b164bSjason 				break;
435c28b164bSjason 			case 'e':
4364ce84164Sderaadt 				_dl_dprintf(fd, "%lX",
437ce11e090Skurt 				    (void *)(object->load_base +
438c28b164bSjason 				    object->load_size));
439c28b164bSjason 				break;
440c28b164bSjason 			case 'g':
4414ce84164Sderaadt 				_dl_dprintf(fd, "%d", object->grprefcount);
442c28b164bSjason 				break;
443c28b164bSjason 			case 'm':
4444ce84164Sderaadt 				_dl_dprintf(fd, "%d", object->sod.sod_major);
445c28b164bSjason 				break;
446c28b164bSjason 			case 'n':
4474ce84164Sderaadt 				_dl_dprintf(fd, "%d", object->sod.sod_minor);
448c28b164bSjason 				break;
449c28b164bSjason 			case 'O':
4504ce84164Sderaadt 				_dl_dprintf(fd, "%d", object->opencount);
451c28b164bSjason 				break;
452c28b164bSjason 			case 'o':
4534ce84164Sderaadt 				_dl_dprintf(fd, "%s", object->sod.sod_name);
454c28b164bSjason 				break;
455c28b164bSjason 			case 'p':
4564ce84164Sderaadt 				_dl_dprintf(fd, "%s", object->load_name);
457c28b164bSjason 				break;
458c28b164bSjason 			case 'r':
4594ce84164Sderaadt 				_dl_dprintf(fd, "%d", object->refcount);
460c28b164bSjason 				break;
461c28b164bSjason 			case 't':
4624ce84164Sderaadt 				_dl_dprintf(fd, "%s", objtypename);
463c28b164bSjason 				break;
464c28b164bSjason 			case 'x':
4654ce84164Sderaadt 				_dl_dprintf(fd, "%lX", object->load_base);
466c28b164bSjason 				break;
467c28b164bSjason 			}
468c28b164bSjason 		}
469c28b164bSjason 		if (fmt[i] == '\\') {
470c28b164bSjason 			i++;
471c28b164bSjason 			switch (fmt[i]) {
472c28b164bSjason 			case '\0':
473c28b164bSjason 				return;
474c28b164bSjason 			case 'n':
4754ce84164Sderaadt 				_dl_dprintf(fd, "%c", '\n');
476c28b164bSjason 				break;
477c28b164bSjason 			case 'r':
4784ce84164Sderaadt 				_dl_dprintf(fd, "%c", '\r');
479c28b164bSjason 				break;
480c28b164bSjason 			case 't':
4814ce84164Sderaadt 				_dl_dprintf(fd, "%c", '\t');
482c28b164bSjason 				break;
483c28b164bSjason 			default:
4844ce84164Sderaadt 				_dl_dprintf(fd, "%c", fmt[i]);
485c28b164bSjason 				break;
486c28b164bSjason 			}
487c28b164bSjason 		}
488c28b164bSjason 	}
489c28b164bSjason }
490c28b164bSjason 
491c28b164bSjason void
_dl_show_objects(elf_object_t * trace)492ac42b3c8Sguenther _dl_show_objects(elf_object_t *trace)
4934d11faf9Srahnds {
4944d11faf9Srahnds 	elf_object_t *object;
495340a5990Sdrahn 	char *objtypename;
496921d95f2Sdrahn 	int outputfd;
4978963033cSdrahn 	char *pad;
498c28b164bSjason 	const char *fmt1, *fmt2;
4994d11faf9Srahnds 
5004d11faf9Srahnds 	object = _dl_objects;
501921d95f2Sdrahn 	if (_dl_traceld)
502921d95f2Sdrahn 		outputfd = STDOUT_FILENO;
503921d95f2Sdrahn 	else
504921d95f2Sdrahn 		outputfd = STDERR_FILENO;
5054d11faf9Srahnds 
5068963033cSdrahn 	if (sizeof(long) == 8)
5078963033cSdrahn 		pad = "        ";
5088963033cSdrahn 	else
5098963033cSdrahn 		pad = "";
510c28b164bSjason 
511c28b164bSjason 	fmt1 = _dl_tracefmt1 ? _dl_tracefmt1 :
512c28b164bSjason 	    "\t%x %e %t %O    %r   %g      %p\n";
513c28b164bSjason 	fmt2 = _dl_tracefmt2 ? _dl_tracefmt2 :
514c28b164bSjason 	    "\t%x %e %t %O    %r   %g      %p\n";
515c28b164bSjason 
516c28b164bSjason 	if (_dl_tracefmt1 == NULL && _dl_tracefmt2 == NULL)
5174ce84164Sderaadt 		_dl_dprintf(outputfd, "\tStart   %s End     %s Type  Open Ref GrpRef Name\n",
5188963033cSdrahn 		    pad, pad);
5194d11faf9Srahnds 
520ac42b3c8Sguenther 	if (trace != NULL) {
521ac42b3c8Sguenther 		for (; object != NULL; object = object->next) {
522ac42b3c8Sguenther 			if (object == trace)
523ac42b3c8Sguenther 				break;
5242e10aa31Sjason 			if (object->obj_type == OBJTYPE_LDR) {
5252e10aa31Sjason 				object = object->next;
5262e10aa31Sjason 				break;
5272e10aa31Sjason 			}
5282e10aa31Sjason 		}
529ac42b3c8Sguenther 	}
5302e10aa31Sjason 
531c28b164bSjason 	for (; object != NULL; object = object->next) {
532340a5990Sdrahn 		switch (object->obj_type) {
533340a5990Sdrahn 		case OBJTYPE_LDR:
534998f22c3Sderaadt 			objtypename = "ld.so";
535340a5990Sdrahn 			break;
536340a5990Sdrahn 		case OBJTYPE_EXE:
537340a5990Sdrahn 			objtypename = "exe  ";
538340a5990Sdrahn 			break;
539340a5990Sdrahn 		case OBJTYPE_LIB:
540340a5990Sdrahn 			objtypename = "rlib ";
541340a5990Sdrahn 			break;
542340a5990Sdrahn 		case OBJTYPE_DLO:
543340a5990Sdrahn 			objtypename = "dlib ";
544340a5990Sdrahn 			break;
545340a5990Sdrahn 		default:
5469777ac55Sderaadt 			objtypename = "?????";
547340a5990Sdrahn 			break;
548340a5990Sdrahn 		}
549c28b164bSjason 		_dl_tracefmt(outputfd, object, fmt1, fmt2, objtypename);
5504d11faf9Srahnds 	}
551c9cd759cSdrahn }
552a2a95eaeSmarc 
55397e4ddacSguenther lock_cb *
_dl_thread_kern_stop(void)554a2a95eaeSmarc _dl_thread_kern_stop(void)
555a2a95eaeSmarc {
55697e4ddacSguenther 	lock_cb *cb = _dl_thread_fnc;
55797e4ddacSguenther 
55897e4ddacSguenther 	if (cb != NULL)
55997e4ddacSguenther 		(*cb)(0);
56097e4ddacSguenther 	return cb;
561a2a95eaeSmarc }
562a2a95eaeSmarc 
563034b0143Sdrahn void
_dl_thread_kern_go(lock_cb * cb)56497e4ddacSguenther _dl_thread_kern_go(lock_cb *cb)
565a2a95eaeSmarc {
56697e4ddacSguenther 	if (cb != NULL)
56797e4ddacSguenther 		(*cb)(1);
568a2a95eaeSmarc }
569a2a95eaeSmarc 
5709b86939fSkettenis int
dl_iterate_phdr(int (* callback)(struct dl_phdr_info *,size_t,void * data),void * data)5719b86939fSkettenis dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *data),
5729b86939fSkettenis 	void *data)
5739b86939fSkettenis {
5749b86939fSkettenis 	elf_object_t *object;
5759b86939fSkettenis 	struct dl_phdr_info info;
5769b86939fSkettenis 	int retval = -1;
5779b86939fSkettenis 
5789b86939fSkettenis 	for (object = _dl_objects; object != NULL; object = object->next) {
5799f6c3316Skurt 		if (object->phdrp == NULL)
5809b86939fSkettenis 			continue;
5819b86939fSkettenis 
582b86e5b18Skurt 		info.dlpi_addr = object->obj_base;
5839b86939fSkettenis 		info.dlpi_name = object->load_name;
5845c0214c7Skettenis 		info.dlpi_phdr = object->phdrp;
5855c0214c7Skettenis 		info.dlpi_phnum = object->phdrc;
5869b86939fSkettenis 		retval = callback(&info, sizeof (struct dl_phdr_info), data);
5879b86939fSkettenis 		if (retval)
5889b86939fSkettenis 			break;
5899b86939fSkettenis 	}
5909b86939fSkettenis 
5919b86939fSkettenis 	return retval;
5929b86939fSkettenis }
5939b86939fSkettenis 
5947be38e1cSdrahn static elf_object_t *
obj_from_addr(const void * addr)5957be38e1cSdrahn obj_from_addr(const void *addr)
5967be38e1cSdrahn {
5977be38e1cSdrahn 	elf_object_t *dynobj;
5989f6c3316Skurt 	Elf_Phdr *phdrp;
5999d153ba8Skurt 	int phdrc;
6007be38e1cSdrahn 	Elf_Addr start;
6017be38e1cSdrahn 	int i;
6027be38e1cSdrahn 
6037be38e1cSdrahn 	for (dynobj = _dl_objects; dynobj != NULL; dynobj = dynobj->next) {
6049f6c3316Skurt 		if (dynobj->phdrp == NULL)
6057be38e1cSdrahn 			continue;
6067be38e1cSdrahn 
6079f6c3316Skurt 		phdrp = dynobj->phdrp;
6089f6c3316Skurt 		phdrc = dynobj->phdrc;
6099f6c3316Skurt 
6109f6c3316Skurt 		for (i = 0; i < phdrc; i++, phdrp++) {
6119f6c3316Skurt 			if (phdrp->p_type == PT_LOAD) {
6129f6c3316Skurt 				start = dynobj->obj_base + phdrp->p_vaddr;
6137be38e1cSdrahn 				if ((Elf_Addr)addr >= start &&
6149f6c3316Skurt 				    (Elf_Addr)addr < start + phdrp->p_memsz)
6157be38e1cSdrahn 					return dynobj;
6167be38e1cSdrahn 			}
6177be38e1cSdrahn 		}
6187be38e1cSdrahn 	}
6197be38e1cSdrahn 
6207be38e1cSdrahn 	return NULL;
6217be38e1cSdrahn }
6227be38e1cSdrahn 
6237be38e1cSdrahn int
dladdr(const void * addr,Dl_info * info)6247be38e1cSdrahn dladdr(const void *addr, Dl_info *info)
6257be38e1cSdrahn {
6267be38e1cSdrahn 	const elf_object_t *object;
6277be38e1cSdrahn 	const Elf_Sym *sym;
6287be38e1cSdrahn 	void *symbol_addr;
6297be38e1cSdrahn 	u_int32_t symoffset;
6307be38e1cSdrahn 
6317be38e1cSdrahn 	object = obj_from_addr(addr);
6327be38e1cSdrahn 
6337be38e1cSdrahn 	if (object == NULL) {
6347be38e1cSdrahn 		_dl_errno = DL_NO_OBJECT;
6357be38e1cSdrahn 		return 0;
6367be38e1cSdrahn 	}
6377be38e1cSdrahn 
6387be38e1cSdrahn 	info->dli_fname = (char *)object->load_name;
639ce11e090Skurt 	info->dli_fbase = (void *)object->load_base;
6407be38e1cSdrahn 	info->dli_sname = NULL;
641c9899b11Skrw 	info->dli_saddr = NULL;
6427be38e1cSdrahn 
6437be38e1cSdrahn 	/*
6447be38e1cSdrahn 	 * Walk the symbol list looking for the symbol whose address is
6457be38e1cSdrahn 	 * closest to the address sent in.
6467be38e1cSdrahn 	 */
6477be38e1cSdrahn 	for (symoffset = 0; symoffset < object->nchains; symoffset++) {
6487be38e1cSdrahn 		sym = object->dyn.symtab + symoffset;
6497be38e1cSdrahn 
6507be38e1cSdrahn 		/*
6517be38e1cSdrahn 		 * For skip the symbol if st_shndx is either SHN_UNDEF or
6527be38e1cSdrahn 		 * SHN_COMMON.
6537be38e1cSdrahn 		 */
6547be38e1cSdrahn 		if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON)
6557be38e1cSdrahn 			continue;
6567be38e1cSdrahn 
6577be38e1cSdrahn 		/*
6587be38e1cSdrahn 		 * If the symbol is greater than the specified address, or if
6597be38e1cSdrahn 		 * it is further away from addr than the current nearest
6607be38e1cSdrahn 		 * symbol, then reject it.
6617be38e1cSdrahn 		 */
662ce11e090Skurt 		symbol_addr = (void *)(object->obj_base + sym->st_value);
6637be38e1cSdrahn 		if (symbol_addr > addr || symbol_addr < info->dli_saddr)
6647be38e1cSdrahn 			continue;
6657be38e1cSdrahn 
6667be38e1cSdrahn 		/* Update our idea of the nearest symbol. */
6677be38e1cSdrahn 		info->dli_sname = object->dyn.strtab + sym->st_name;
6687be38e1cSdrahn 		info->dli_saddr = symbol_addr;
6697be38e1cSdrahn 
6707be38e1cSdrahn 		/* Exact match? */
6717be38e1cSdrahn 		if (info->dli_saddr == addr)
6727be38e1cSdrahn 			break;
6737be38e1cSdrahn 	}
6747be38e1cSdrahn 
6757be38e1cSdrahn 	return 1;
6767be38e1cSdrahn }
677