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