1*ba367c05Srobert /* $OpenBSD: library_subr.c,v 1.55 2023/04/27 12:27:56 robert Exp $ */
220e18be4Sdrahn
320e18be4Sdrahn /*
420e18be4Sdrahn * Copyright (c) 2002 Dale Rahn
520e18be4Sdrahn * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
620e18be4Sdrahn *
720e18be4Sdrahn * Redistribution and use in source and binary forms, with or without
820e18be4Sdrahn * modification, are permitted provided that the following conditions
920e18be4Sdrahn * are met:
1020e18be4Sdrahn * 1. Redistributions of source code must retain the above copyright
1120e18be4Sdrahn * notice, this list of conditions and the following disclaimer.
1220e18be4Sdrahn * 2. Redistributions in binary form must reproduce the above copyright
1320e18be4Sdrahn * notice, this list of conditions and the following disclaimer in the
1420e18be4Sdrahn * documentation and/or other materials provided with the distribution.
1520e18be4Sdrahn *
1620e18be4Sdrahn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1720e18be4Sdrahn * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1820e18be4Sdrahn * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1920e18be4Sdrahn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
2020e18be4Sdrahn * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2120e18be4Sdrahn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2220e18be4Sdrahn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2320e18be4Sdrahn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2420e18be4Sdrahn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2520e18be4Sdrahn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2620e18be4Sdrahn * SUCH DAMAGE.
2720e18be4Sdrahn *
2820e18be4Sdrahn */
2920e18be4Sdrahn
3020e18be4Sdrahn #define _DYN_LOADER
3120e18be4Sdrahn
3220e18be4Sdrahn #include <sys/types.h>
330acae5e5Sdrahn #include <sys/queue.h>
34d0c9fa7cSderaadt #include <limits.h>
3520e18be4Sdrahn #include <dirent.h>
3620e18be4Sdrahn
37b722ba42Sguenther #include "util.h"
3820e18be4Sdrahn #include "resolve.h"
3920e18be4Sdrahn #include "dir.h"
4020e18be4Sdrahn #include "sod.h"
4120e18be4Sdrahn
42c8dfd7a0Skurt char * _dl_default_path[2] = { "/usr/lib", NULL };
4320e18be4Sdrahn
44034b0143Sdrahn
45034b0143Sdrahn /* STATIC DATA */
460acae5e5Sdrahn struct dlochld _dlopened_child_list;
470acae5e5Sdrahn
480acae5e5Sdrahn
4920e18be4Sdrahn /*
5020e18be4Sdrahn * _dl_match_file()
5120e18be4Sdrahn *
528fc45048Smiod * This function determines if a given name matches what is specified
5320e18be4Sdrahn * in a struct sod. The major must match exactly, and the minor must
5420e18be4Sdrahn * be same or larger.
5520e18be4Sdrahn *
5620e18be4Sdrahn * sodp is updated with the minor if this matches.
5720e18be4Sdrahn */
5820e18be4Sdrahn
5920e18be4Sdrahn int
_dl_match_file(struct sod * sodp,const char * name,int namelen)600af06aafSkurt _dl_match_file(struct sod *sodp, const char *name, int namelen)
6120e18be4Sdrahn {
6220e18be4Sdrahn int match;
6320e18be4Sdrahn struct sod lsod;
640af06aafSkurt const char *lname;
6520e18be4Sdrahn
6620e18be4Sdrahn lname = name;
6720e18be4Sdrahn if (sodp->sod_library) {
6820e18be4Sdrahn if (_dl_strncmp(name, "lib", 3))
6920e18be4Sdrahn return 0;
7020e18be4Sdrahn lname += 3;
7120e18be4Sdrahn }
7220e18be4Sdrahn if (_dl_strncmp(lname, (char *)sodp->sod_name,
7320e18be4Sdrahn _dl_strlen((char *)sodp->sod_name)))
7420e18be4Sdrahn return 0;
7520e18be4Sdrahn
7620e18be4Sdrahn _dl_build_sod(name, &lsod);
7720e18be4Sdrahn
7820e18be4Sdrahn match = 0;
7920e18be4Sdrahn if ((_dl_strcmp((char *)lsod.sod_name, (char *)sodp->sod_name) == 0) &&
8020e18be4Sdrahn (lsod.sod_library == sodp->sod_library) &&
8120e18be4Sdrahn ((sodp->sod_major == -1) || (sodp->sod_major == lsod.sod_major)) &&
8220e18be4Sdrahn ((sodp->sod_minor == -1) ||
8320e18be4Sdrahn (lsod.sod_minor >= sodp->sod_minor))) {
8420e18be4Sdrahn match = 1;
8520e18be4Sdrahn
8620e18be4Sdrahn /* return version matched */
8720e18be4Sdrahn sodp->sod_major = lsod.sod_major;
8820e18be4Sdrahn sodp->sod_minor = lsod.sod_minor;
8920e18be4Sdrahn }
9020e18be4Sdrahn _dl_free((char *)lsod.sod_name);
9120e18be4Sdrahn return match;
9220e18be4Sdrahn }
9320e18be4Sdrahn
940af06aafSkurt /*
950af06aafSkurt * _dl_cmp_sod()
960af06aafSkurt *
978fc45048Smiod * This function compares sod structs. The major must match exactly,
980af06aafSkurt * and the minor must be same or larger.
990af06aafSkurt *
1000af06aafSkurt * sodp is updated with the minor if this matches.
1010af06aafSkurt */
1020af06aafSkurt
1032f86c0efSderaadt static int
_dl_cmp_sod(struct sod * sodp,const struct sod * lsod)1040af06aafSkurt _dl_cmp_sod(struct sod *sodp, const struct sod *lsod)
1050af06aafSkurt {
1060af06aafSkurt int match;
1070af06aafSkurt
1080af06aafSkurt match = 1;
1090af06aafSkurt if ((_dl_strcmp((char *)lsod->sod_name, (char *)sodp->sod_name) == 0) &&
1100af06aafSkurt (lsod->sod_library == sodp->sod_library) &&
1110af06aafSkurt ((sodp->sod_major == -1) || (sodp->sod_major == lsod->sod_major)) &&
1120af06aafSkurt ((sodp->sod_minor == -1) ||
1130af06aafSkurt (lsod->sod_minor >= sodp->sod_minor))) {
1140af06aafSkurt match = 0;
1150af06aafSkurt
1160af06aafSkurt /* return version matched */
1170af06aafSkurt sodp->sod_major = lsod->sod_major;
1180af06aafSkurt sodp->sod_minor = lsod->sod_minor;
1190af06aafSkurt }
1200af06aafSkurt return match;
1210af06aafSkurt }
1220af06aafSkurt
1235b40abcfSderaadt char _dl_hint_store[PATH_MAX];
12420e18be4Sdrahn
12520e18be4Sdrahn char *
_dl_find_shlib(struct sod * sodp,char ** searchpath,int nohints)126c8dfd7a0Skurt _dl_find_shlib(struct sod *sodp, char **searchpath, int nohints)
12720e18be4Sdrahn {
128c8dfd7a0Skurt char *hint, **pp;
12920e18be4Sdrahn struct dirent *dp;
13020e18be4Sdrahn int match, len;
1312367cb4fSmatthew _dl_DIR *dd;
13220e18be4Sdrahn struct sod tsod, bsod; /* transient and best sod */
13320e18be4Sdrahn
13420e18be4Sdrahn /* if we are to search default directories, and hints
13520e18be4Sdrahn * are not to be used, search the standard path from ldconfig
13620e18be4Sdrahn * (_dl_hint_search_path) or use the default path
13720e18be4Sdrahn */
13820e18be4Sdrahn if (nohints)
13920e18be4Sdrahn goto nohints;
14020e18be4Sdrahn
14120e18be4Sdrahn if (searchpath == NULL) {
14220e18be4Sdrahn /* search 'standard' locations, find any match in the hints */
14320e18be4Sdrahn hint = _dl_findhint((char *)sodp->sod_name, sodp->sod_major,
14420e18be4Sdrahn sodp->sod_minor, NULL);
14520e18be4Sdrahn if (hint)
14620e18be4Sdrahn return hint;
14720e18be4Sdrahn } else {
14820e18be4Sdrahn /* search hints requesting matches for only
14920e18be4Sdrahn * the searchpath directories,
15020e18be4Sdrahn */
151c8dfd7a0Skurt for (pp = searchpath; *pp != NULL; pp++) {
15220e18be4Sdrahn hint = _dl_findhint((char *)sodp->sod_name,
153c8dfd7a0Skurt sodp->sod_major, sodp->sod_minor, *pp);
15420e18be4Sdrahn if (hint != NULL)
15520e18be4Sdrahn return hint;
15620e18be4Sdrahn }
15720e18be4Sdrahn }
15820e18be4Sdrahn
15920e18be4Sdrahn /*
16020e18be4Sdrahn * For each directory in the searchpath, read the directory
16120e18be4Sdrahn * entries looking for a match to sod. filename compare is
16220e18be4Sdrahn * done by _dl_match_file()
16320e18be4Sdrahn */
16420e18be4Sdrahn nohints:
16520e18be4Sdrahn if (searchpath == NULL) {
16620e18be4Sdrahn if (_dl_hint_search_path != NULL)
16720e18be4Sdrahn searchpath = _dl_hint_search_path;
16820e18be4Sdrahn else
169c8dfd7a0Skurt searchpath = _dl_default_path;
17020e18be4Sdrahn }
1719a1975b9Smatthieu _dl_memset(&bsod, 0, sizeof(bsod));
172c8dfd7a0Skurt for (pp = searchpath; *pp != NULL; pp++) {
173c8dfd7a0Skurt if ((dd = _dl_opendir(*pp)) != NULL) {
17420e18be4Sdrahn match = 0;
17520e18be4Sdrahn while ((dp = _dl_readdir(dd)) != NULL) {
17620e18be4Sdrahn tsod = *sodp;
17720e18be4Sdrahn if (_dl_match_file(&tsod, dp->d_name,
17820e18be4Sdrahn dp->d_namlen)) {
17920e18be4Sdrahn /*
18020e18be4Sdrahn * When a match is found, tsod is
18120e18be4Sdrahn * updated with the major+minor found.
18220e18be4Sdrahn * This version is compared with the
18320e18be4Sdrahn * largest so far (kept in bsod),
18420e18be4Sdrahn * and saved if larger.
18520e18be4Sdrahn */
18620e18be4Sdrahn if (!match ||
18720e18be4Sdrahn tsod.sod_major == -1 ||
18820e18be4Sdrahn tsod.sod_major > bsod.sod_major ||
18920e18be4Sdrahn ((tsod.sod_major ==
19020e18be4Sdrahn bsod.sod_major) &&
19120e18be4Sdrahn tsod.sod_minor > bsod.sod_minor)) {
19220e18be4Sdrahn bsod = tsod;
19320e18be4Sdrahn match = 1;
19420e18be4Sdrahn len = _dl_strlcpy(
195c8dfd7a0Skurt _dl_hint_store, *pp,
1965b40abcfSderaadt PATH_MAX);
197c8dfd7a0Skurt if (pp[0][len-1] != '/') {
19820e18be4Sdrahn _dl_hint_store[len] =
19920e18be4Sdrahn '/';
20020e18be4Sdrahn len++;
20120e18be4Sdrahn }
20220e18be4Sdrahn _dl_strlcpy(
20320e18be4Sdrahn &_dl_hint_store[len],
20420e18be4Sdrahn dp->d_name,
2055b40abcfSderaadt PATH_MAX-len);
20620e18be4Sdrahn if (tsod.sod_major == -1)
20720e18be4Sdrahn break;
20820e18be4Sdrahn }
20920e18be4Sdrahn }
21020e18be4Sdrahn }
21120e18be4Sdrahn _dl_closedir(dd);
21220e18be4Sdrahn if (match) {
21320e18be4Sdrahn *sodp = bsod;
21420e18be4Sdrahn return (_dl_hint_store);
21520e18be4Sdrahn }
21620e18be4Sdrahn }
21720e18be4Sdrahn }
21820e18be4Sdrahn return NULL;
21920e18be4Sdrahn }
22020e18be4Sdrahn
2212f86c0efSderaadt static elf_object_t *
_dl_lookup_object(const char * req_name,struct sod * req_sod)2220af06aafSkurt _dl_lookup_object(const char *req_name, struct sod *req_sod)
2230af06aafSkurt {
2240af06aafSkurt elf_object_t *object = _dl_objects;
2250af06aafSkurt
2260af06aafSkurt while (object) {
2270af06aafSkurt char *soname;
2280af06aafSkurt
2290af06aafSkurt if (_dl_cmp_sod(req_sod, &object->sod) == 0)
2300af06aafSkurt return(object);
2310af06aafSkurt
2320af06aafSkurt soname = (char *)object->Dyn.info[DT_SONAME];
2330af06aafSkurt if (soname != NULL) {
2340af06aafSkurt if (_dl_strcmp(req_name, soname) == 0)
2350af06aafSkurt return(object);
2360af06aafSkurt }
2370af06aafSkurt
2380af06aafSkurt object = object->next;
2390af06aafSkurt }
2400af06aafSkurt
2410af06aafSkurt return(NULL);
2420af06aafSkurt }
2430af06aafSkurt
244ab4d5173Ssthen void
_dl_handle_already_loaded(elf_object_t * object,int flags)245ab4d5173Ssthen _dl_handle_already_loaded(elf_object_t *object, int flags)
246ab4d5173Ssthen {
247ab4d5173Ssthen object->obj_flags |= flags & DF_1_GLOBAL;
248ab4d5173Ssthen if (_dl_loading_object == NULL)
249ab4d5173Ssthen _dl_loading_object = object;
250ab4d5173Ssthen if (object->load_object != _dl_objects &&
251ab4d5173Ssthen object->load_object != _dl_loading_object) {
252ab4d5173Ssthen _dl_link_grpref(object->load_object, _dl_loading_object);
253ab4d5173Ssthen }
254ab4d5173Ssthen }
255ab4d5173Ssthen
2562f86c0efSderaadt static elf_object_t *
_dl_find_loaded_shlib(const char * req_name,struct sod req_sod,int flags)2570af06aafSkurt _dl_find_loaded_shlib(const char *req_name, struct sod req_sod, int flags)
2580af06aafSkurt {
2590af06aafSkurt elf_object_t *object;
2600af06aafSkurt
2610af06aafSkurt object = _dl_lookup_object(req_name, &req_sod);
2620af06aafSkurt
2630af06aafSkurt /* if not found retry with any minor */
2640af06aafSkurt if (object == NULL && req_sod.sod_library && req_sod.sod_minor != -1) {
2650af06aafSkurt short orig_minor = req_sod.sod_minor;
2660af06aafSkurt req_sod.sod_minor = -1;
2670af06aafSkurt object = _dl_lookup_object(req_name, &req_sod);
2680af06aafSkurt
2690af06aafSkurt if (object != NULL && req_sod.sod_minor < orig_minor)
2700af06aafSkurt _dl_printf("warning: lib%s.so.%d.%d: "
2710af06aafSkurt "minor version >= %d expected, "
2720af06aafSkurt "using it anyway\n",
2730af06aafSkurt req_sod.sod_name, req_sod.sod_major,
2740af06aafSkurt req_sod.sod_minor, orig_minor);
2750af06aafSkurt }
2760af06aafSkurt
277ab4d5173Ssthen if (object)
278ab4d5173Ssthen _dl_handle_already_loaded(object, flags);
2790af06aafSkurt
2800af06aafSkurt return (object);
2810af06aafSkurt }
2820af06aafSkurt
28320e18be4Sdrahn /*
28420e18be4Sdrahn * Load a shared object. Search order is:
2850af06aafSkurt * First check loaded objects for a matching shlib, otherwise:
2860af06aafSkurt *
287a1ce87d6Skrw * If the name contains a '/' use only the path preceding the
2880f3893b8Skurt * library name and do not continue on to other methods if not
2890f3893b8Skurt * found.
290a1ce87d6Skrw * search hints for match in path preceding library name
2910f3893b8Skurt * this will only match specific library version.
292a1ce87d6Skrw * search path preceding library name
2930f3893b8Skurt * this will find largest minor version in path provided
29482c4222eSguenther *
29582c4222eSguenther * Otherwise, the name doesn't contain a '/':
29682c4222eSguenther * search hints for the specific library version, trying in turn
29782c4222eSguenther * paths from the following:
29882c4222eSguenther * - the LD_LIBRARY_PATH environment variable (if set)
29982c4222eSguenther * - the library's own DT_RUNPATH
30082c4222eSguenther * - if DT_RUNPATH wasn't set, then:
30182c4222eSguenther * - the library's own DT_RPATH
30282c4222eSguenther * - the executable's own DT_RPATH
30382c4222eSguenther * - the default search path set by ldconfig, or /usr/lib if unset
30482c4222eSguenther *
30582c4222eSguenther * If the hints doesn't have an exact match, then we search
30682c4222eSguenther * that exact same list of directories again, looking for a
30782c4222eSguenther * lib with the correct major version. If we find a match on
30882c4222eSguenther * the major, then we take the match *in that directory* which
30982c4222eSguenther * has the largest minor version
31020e18be4Sdrahn */
31120e18be4Sdrahn
31220e18be4Sdrahn elf_object_t *
_dl_load_shlib(const char * libname,elf_object_t * parent,int type,int flags,int nodelete)31307cf23bbSderaadt _dl_load_shlib(const char *libname, elf_object_t *parent, int type, int flags,
31407cf23bbSderaadt int nodelete)
31520e18be4Sdrahn {
31620e18be4Sdrahn int try_any_minor, ignore_hints;
31720e18be4Sdrahn struct sod sod, req_sod;
3188d416f7aSdrahn elf_object_t *object = NULL;
319ccc0dd31Skurt char *hint;
32020e18be4Sdrahn
32120e18be4Sdrahn try_any_minor = 0;
32220e18be4Sdrahn ignore_hints = 0;
32320e18be4Sdrahn
32420e18be4Sdrahn if (_dl_strchr(libname, '/')) {
325c8dfd7a0Skurt char *paths[2];
3260f3893b8Skurt char *lpath, *lname;
3270f3893b8Skurt lpath = _dl_strdup(libname);
32867b06ea7Sotto if (lpath == NULL)
3293b50b772Sguenther _dl_oom();
3300f3893b8Skurt lname = _dl_strrchr(lpath, '/');
3310f3893b8Skurt if (lname == NULL) {
3320f3893b8Skurt _dl_free(lpath);
3330f3893b8Skurt _dl_errno = DL_NOT_FOUND;
3340f3893b8Skurt return (object);
3350f3893b8Skurt }
3360f3893b8Skurt *lname = '\0';
3370f3893b8Skurt lname++;
3380f3893b8Skurt if (*lname == '\0') {
3390f3893b8Skurt _dl_free(lpath);
3400f3893b8Skurt _dl_errno = DL_NOT_FOUND;
3410f3893b8Skurt return (object);
3420f3893b8Skurt }
3430f3893b8Skurt
3440f3893b8Skurt _dl_build_sod(lname, &sod);
3450f3893b8Skurt req_sod = sod;
3460f3893b8Skurt
347c8dfd7a0Skurt paths[0] = lpath;
348c8dfd7a0Skurt paths[1] = NULL;
3490f3893b8Skurt fullpathagain:
350c8dfd7a0Skurt hint = _dl_find_shlib(&req_sod, paths, ignore_hints);
351ccc0dd31Skurt if (hint != NULL)
3520f3893b8Skurt goto fullpathdone;
3530f3893b8Skurt
3540f3893b8Skurt if (try_any_minor == 0) {
3550f3893b8Skurt try_any_minor = 1;
3560f3893b8Skurt ignore_hints = 1;
3570f3893b8Skurt req_sod.sod_minor = -1;
3580f3893b8Skurt goto fullpathagain;
3590f3893b8Skurt }
3600f3893b8Skurt _dl_errno = DL_NOT_FOUND;
3610f3893b8Skurt fullpathdone:
3620f3893b8Skurt _dl_free(lpath);
363ccc0dd31Skurt goto done;
36420e18be4Sdrahn }
36520e18be4Sdrahn
36620e18be4Sdrahn _dl_build_sod(libname, &sod);
36720e18be4Sdrahn req_sod = sod;
36820e18be4Sdrahn
3690af06aafSkurt object = _dl_find_loaded_shlib(libname, req_sod, flags);
3700af06aafSkurt if (object) {
3710af06aafSkurt _dl_free((char *)sod.sod_name);
3720af06aafSkurt return (object);
3730af06aafSkurt }
3740af06aafSkurt
37520e18be4Sdrahn again:
3768d416f7aSdrahn /* No '/' in name. Scan the known places, LD_LIBRARY_PATH first. */
37720e18be4Sdrahn if (_dl_libpath != NULL) {
378ccc0dd31Skurt hint = _dl_find_shlib(&req_sod, _dl_libpath, ignore_hints);
379ccc0dd31Skurt if (hint != NULL)
3808d416f7aSdrahn goto done;
38120e18be4Sdrahn }
38220e18be4Sdrahn
38382c4222eSguenther /* Check DT_RUNPATH */
38482c4222eSguenther if (parent->runpath != NULL) {
38582c4222eSguenther hint = _dl_find_shlib(&req_sod, parent->runpath, ignore_hints);
38682c4222eSguenther if (hint != NULL)
38782c4222eSguenther goto done;
38882c4222eSguenther } else {
38982c4222eSguenther /*
39082c4222eSguenther * If DT_RUNPATH wasn't set then first check DT_RPATH,
39182c4222eSguenther * followed by the main program's DT_RPATH.
39282c4222eSguenther */
393c8dfd7a0Skurt if (parent->rpath != NULL) {
39482c4222eSguenther hint = _dl_find_shlib(&req_sod, parent->rpath,
39582c4222eSguenther ignore_hints);
396ccc0dd31Skurt if (hint != NULL)
3978d416f7aSdrahn goto done;
39820e18be4Sdrahn }
399c8dfd7a0Skurt if (parent != _dl_objects && _dl_objects->rpath != NULL) {
40082c4222eSguenther hint = _dl_find_shlib(&req_sod, _dl_objects->rpath,
40182c4222eSguenther ignore_hints);
402ccc0dd31Skurt if (hint != NULL)
4038d416f7aSdrahn goto done;
404095cd57dSdrahn }
40582c4222eSguenther }
40620e18be4Sdrahn
40720e18be4Sdrahn /* check 'standard' locations */
408ccc0dd31Skurt hint = _dl_find_shlib(&req_sod, NULL, ignore_hints);
409ccc0dd31Skurt if (hint != NULL)
4108d416f7aSdrahn goto done;
41120e18be4Sdrahn
41220e18be4Sdrahn if (try_any_minor == 0) {
41320e18be4Sdrahn try_any_minor = 1;
41420e18be4Sdrahn ignore_hints = 1;
41520e18be4Sdrahn req_sod.sod_minor = -1;
41620e18be4Sdrahn goto again;
41720e18be4Sdrahn }
41820e18be4Sdrahn _dl_errno = DL_NOT_FOUND;
4198d416f7aSdrahn done:
420ccc0dd31Skurt if (hint != NULL) {
421ccc0dd31Skurt if (req_sod.sod_minor < sod.sod_minor)
422ccc0dd31Skurt _dl_printf("warning: lib%s.so.%d.%d: "
423ccc0dd31Skurt "minor version >= %d expected, "
424ccc0dd31Skurt "using it anyway\n",
425ccc0dd31Skurt sod.sod_name, sod.sod_major,
426ccc0dd31Skurt req_sod.sod_minor, sod.sod_minor);
42707cf23bbSderaadt object = _dl_tryload_shlib(hint, type, flags, nodelete);
4280af06aafSkurt }
4290af06aafSkurt _dl_free((char *)sod.sod_name);
4308d416f7aSdrahn return(object);
43120e18be4Sdrahn }
43220e18be4Sdrahn
43320e18be4Sdrahn
43420e18be4Sdrahn void
_dl_link_dlopen(elf_object_t * dep)435034b0143Sdrahn _dl_link_dlopen(elf_object_t *dep)
436034b0143Sdrahn {
437034b0143Sdrahn struct dep_node *n;
438034b0143Sdrahn
439ef5c7deaSkurt dep->opencount++;
440ef5c7deaSkurt
441ef5c7deaSkurt if (OBJECT_DLREF_CNT(dep) > 1)
442f0cc64abSkurt return;
443f0cc64abSkurt
444034b0143Sdrahn n = _dl_malloc(sizeof *n);
445034b0143Sdrahn if (n == NULL)
4463b50b772Sguenther _dl_oom();
447034b0143Sdrahn
448034b0143Sdrahn n->data = dep;
4490acae5e5Sdrahn TAILQ_INSERT_TAIL(&_dlopened_child_list, n, next_sib);
450034b0143Sdrahn
451034b0143Sdrahn DL_DEB(("linking %s as dlopen()ed\n", dep->load_name));
452034b0143Sdrahn }
453034b0143Sdrahn
4542f86c0efSderaadt static void
_dl_child_refcnt_decrement(elf_object_t * object)4551a15fa31Skurt _dl_child_refcnt_decrement(elf_object_t *object)
4561a15fa31Skurt {
457d937a926Sguenther struct object_vector vec;
458d937a926Sguenther int i;
4591a15fa31Skurt
4601a15fa31Skurt object->refcount--;
4611a15fa31Skurt if (OBJECT_REF_CNT(object) == 0)
462d937a926Sguenther for (vec = object->child_vec, i = 0; i < vec.len; i++)
463d937a926Sguenther _dl_child_refcnt_decrement(vec.vec[i]);
4641a15fa31Skurt }
4651a15fa31Skurt
4661a15fa31Skurt void
_dl_notify_unload_shlib(elf_object_t * object)467a4baf06aSdrahn _dl_notify_unload_shlib(elf_object_t *object)
468a4baf06aSdrahn {
469d937a926Sguenther struct object_vector vec;
470a4baf06aSdrahn struct dep_node *n;
471d937a926Sguenther int i;
472a4baf06aSdrahn
4731a15fa31Skurt if (OBJECT_REF_CNT(object) == 0)
474d937a926Sguenther for (vec = object->child_vec, i = 0; i < vec.len; i++)
475d937a926Sguenther _dl_child_refcnt_decrement(vec.vec[i]);
4761a15fa31Skurt
477ca7a62b5Skurt if (OBJECT_DLREF_CNT(object) == 0) {
4780fd73922Sdrahn while ((n = TAILQ_FIRST(&object->grpref_list)) != NULL) {
4790fd73922Sdrahn TAILQ_REMOVE(&object->grpref_list, n, next_sib);
48050cabf59Skurt n->data->grprefcount--;
48150cabf59Skurt _dl_notify_unload_shlib(n->data);
4820fd73922Sdrahn _dl_free(n);
48350cabf59Skurt }
4848f55e5f1Skurt }
485a4baf06aSdrahn }
486a4baf06aSdrahn
487a4baf06aSdrahn void
_dl_unload_dlopen(void)488034b0143Sdrahn _dl_unload_dlopen(void)
489034b0143Sdrahn {
4900acae5e5Sdrahn struct dep_node *node;
491034b0143Sdrahn
4920acae5e5Sdrahn TAILQ_FOREACH_REVERSE(node, &_dlopened_child_list, dlochld, next_sib) {
4936fa405c3Sdrahn /* dont dlclose the main program */
4946fa405c3Sdrahn if (node->data == _dl_objects)
4956fa405c3Sdrahn continue;
4966fa405c3Sdrahn
49752257b47Skurt while (node->data->opencount > 0) {
49852257b47Skurt node->data->opencount--;
499034b0143Sdrahn _dl_notify_unload_shlib(node->data);
500034b0143Sdrahn _dl_run_all_dtors();
5018d2dd116Sdrahn }
502034b0143Sdrahn }
5030acae5e5Sdrahn }
504034b0143Sdrahn
505034b0143Sdrahn void
_dl_link_grpref(elf_object_t * load_group,elf_object_t * load_object)50650cabf59Skurt _dl_link_grpref(elf_object_t *load_group, elf_object_t *load_object)
50750cabf59Skurt {
50850cabf59Skurt struct dep_node *n;
50950cabf59Skurt
51050cabf59Skurt n = _dl_malloc(sizeof *n);
51150cabf59Skurt if (n == NULL)
5123b50b772Sguenther _dl_oom();
51350cabf59Skurt n->data = load_group;
51450cabf59Skurt TAILQ_INSERT_TAIL(&load_object->grpref_list, n, next_sib);
51550cabf59Skurt load_group->grprefcount++;
51650cabf59Skurt }
51750cabf59Skurt
51850cabf59Skurt void
_dl_link_child(elf_object_t * dep,elf_object_t * p)519ea03aff5Skurt _dl_link_child(elf_object_t *dep, elf_object_t *p)
52020e18be4Sdrahn {
521d937a926Sguenther int i;
52220e18be4Sdrahn
523d937a926Sguenther i = p->child_vec.len++;
524d937a926Sguenther if (i == p->child_vec.alloc)
525d937a926Sguenther _dl_die("child appeared %d > %d", p->child_vec.len,
526d937a926Sguenther p->child_vec.alloc);
527d937a926Sguenther p->child_vec.vec[i] = dep;
5280acae5e5Sdrahn
5291a15fa31Skurt dep->refcount++;
5301a15fa31Skurt
531ea03aff5Skurt DL_DEB(("linking dep %s as child of %s\n", dep->load_name,
532ea03aff5Skurt p->load_name));
533ea03aff5Skurt }
534ea03aff5Skurt
535bae526eeSguenther void
object_vec_grow(struct object_vector * vec,int more)536bae526eeSguenther object_vec_grow(struct object_vector *vec, int more)
537bae526eeSguenther {
538bae526eeSguenther vec->alloc += more;
539bae526eeSguenther vec->vec = _dl_reallocarray(vec->vec, vec->alloc, sizeof(*vec->vec));
540bae526eeSguenther if (vec->vec == NULL)
541bae526eeSguenther _dl_oom();
542bae526eeSguenther }
543bae526eeSguenther
544b6decd50Sguenther /* Generation number of the current grpsym insertion/caching */
545b6decd50Sguenther static unsigned int _dl_grpsym_gen = 0;
546b6decd50Sguenther
547ea03aff5Skurt void
_dl_link_grpsym(elf_object_t * object)548bae526eeSguenther _dl_link_grpsym(elf_object_t *object)
549ea03aff5Skurt {
550bae526eeSguenther struct object_vector *vec;
551bae526eeSguenther int len;
552ea03aff5Skurt
553bae526eeSguenther if (object->grpsym_gen == _dl_grpsym_gen)
554bae526eeSguenther return;
555b6decd50Sguenther object->grpsym_gen = _dl_grpsym_gen;
5560acae5e5Sdrahn
557bae526eeSguenther vec = &_dl_loading_object->grpsym_vec;
558bae526eeSguenther len = vec->len++;
559bae526eeSguenther if (len >= vec->alloc)
560bae526eeSguenther _dl_die("more grpsym than objects?! %d > %d", vec->len,
561bae526eeSguenther vec->alloc);
562bae526eeSguenther vec->vec[len] = object;
563ea03aff5Skurt }
564ea03aff5Skurt
565ea03aff5Skurt void
_dl_cache_grpsym_list_setup(elf_object_t * object)5661a53160bSdrahn _dl_cache_grpsym_list_setup(elf_object_t *object)
5671a53160bSdrahn {
568bae526eeSguenther struct object_vector *vec;
569bae526eeSguenther int next;
570bae526eeSguenther
571b6decd50Sguenther _dl_grpsym_gen += 1;
572b6decd50Sguenther
573b6decd50Sguenther if (_dl_grpsym_gen == 0) {
574b6decd50Sguenther /*
575b6decd50Sguenther * If the count rolls over, reset all counters so
576b6decd50Sguenther * we don't get accidental collision.
577b6decd50Sguenther */
578b6decd50Sguenther elf_object_t *walkobj;
579b6decd50Sguenther for (walkobj = _dl_objects;
580b6decd50Sguenther walkobj != NULL;
581b6decd50Sguenther walkobj = walkobj->next) {
582b6decd50Sguenther walkobj->grpsym_gen = 0;
583b6decd50Sguenther }
584b6decd50Sguenther _dl_grpsym_gen = 1;
585b6decd50Sguenther }
586ea03aff5Skurt
587ea03aff5Skurt /*
588bae526eeSguenther * grpsym_vec is a vector of all child libs of the
5898fc45048Smiod * _dl_loading_object with no dups. The order is equivalent
590c4bed0acSsthen * to a breadth-first traversal of the child list without dups.
591ea03aff5Skurt */
592ea03aff5Skurt
593bae526eeSguenther vec = &object->grpsym_vec;
594bae526eeSguenther object_vec_grow(vec, object_count);
595bae526eeSguenther next = 0;
596ea03aff5Skurt
597bae526eeSguenther /* add first object manually */
598bae526eeSguenther _dl_link_grpsym(object);
599bae526eeSguenther
600bae526eeSguenther while (next < vec->len) {
601d937a926Sguenther struct object_vector child_vec;
602d937a926Sguenther int i;
603bae526eeSguenther
604d937a926Sguenther child_vec = vec->vec[next++]->child_vec;
605d937a926Sguenther for (i = 0; i < child_vec.len; i++)
606d937a926Sguenther _dl_link_grpsym(child_vec.vec[i]);
607bae526eeSguenther }
60820e18be4Sdrahn }
609