📄 dl-deps.c
字号:
/* Load the dependencies of a mapped object. Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */#include <assert.h>#include <dlfcn.h>#include <errno.h>#include <libintl.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/param.h>#include <ldsodefs.h>#include <dl-dst.h>/* Whether an shared object references one or more auxiliary objects is signaled by the AUXTAG entry in l_info. */#define AUXTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ + DT_EXTRATAGIDX (DT_AUXILIARY))/* Whether an shared object references one or more auxiliary objects is signaled by the AUXTAG entry in l_info. */#define FILTERTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ + DT_EXTRATAGIDX (DT_FILTER))/* This is zero at program start to signal that the global scope map is allocated by rtld. Later it keeps the size of the map. It might be reset if in _dl_close if the last global object is removed. */size_t _dl_global_scope_alloc;extern size_t _dl_platformlen;/* When loading auxiliary objects we must ignore errors. It's ok if an object is missing. */struct openaux_args { /* The arguments to openaux. */ struct link_map *map; int trace_mode; const char *strtab; const char *name; /* The return value of openaux. */ struct link_map *aux; };static voidopenaux (void *a){ struct openaux_args *args = (struct openaux_args *) a; args->aux = _dl_map_object (args->map, args->name, 0, (args->map->l_type == lt_executable ? lt_library : args->map->l_type), args->trace_mode, 0);}/* We use a very special kind of list to track the path through the list of loaded shared objects. We have to produce a flat list with unique members of all involved objects.*/struct list { int done; /* Nonzero if this map was processed. */ struct link_map *map; /* The data. */ struct list *next; /* Elements for normal list. */ };/* Macro to expand DST. It is an macro since we use `alloca'. */#define expand_dst(l, str, fatal) \ ({ \ const char *__str = (str); \ const char *__result = __str; \ size_t __cnt = DL_DST_COUNT(__str, 0); \ \ if (__cnt != 0) \ { \ char *__newp; \ \ __newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str), \ __cnt)); \ \ __result = DL_DST_SUBSTITUTE (l, __str, __newp, 0); \ \ if (*__result == '\0') \ { \ /* The replacement for the DST is not known. We can't \ processed. */ \ if (fatal) \ _dl_signal_error (0, __str, NULL, N_("\empty dynamics string token substitution")); \ else \ { \ /* This is for DT_AUXILIARY. */ \ if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) \ _dl_debug_printf ("cannot load auxiliary `%s' because of" \ "empty dynamic string token " \ "substitution\n", __str); \ continue; \ } \ } \ } \ \ __result; })voidinternal_function_dl_map_object_deps (struct link_map *map, struct link_map **preloads, unsigned int npreloads, int trace_mode){ struct list known[1 + npreloads + 1]; struct list *runp, *tail; unsigned int nlist, i; /* Object name. */ const char *name; int errno_saved; int errno_reason; const char *errstring; const char *objname; auto inline void preload (struct link_map *map); inline void preload (struct link_map *map) { known[nlist].done = 0; known[nlist].map = map; known[nlist].next = &known[nlist + 1]; ++nlist; /* We use `l_reserved' as a mark bit to detect objects we have already put in the search list and avoid adding duplicate elements later in the list. */ map->l_reserved = 1; } /* No loaded object so far. */ nlist = 0; /* First load MAP itself. */ preload (map); /* Add the preloaded items after MAP but before any of its dependencies. */ for (i = 0; i < npreloads; ++i) preload (preloads[i]); /* Terminate the lists. */ known[nlist - 1].next = NULL; /* Pointer to last unique object. */ tail = &known[nlist - 1]; /* Process each element of the search list, loading each of its auxiliary objects and immediate dependencies. Auxiliary objects will be added in the list before the object itself and dependencies will be appended to the list as we step through it. This produces a flat, ordered list that represents a breadth-first search of the dependency tree. The whole process is complicated by the fact that we better should use alloca for the temporary list elements. But using alloca means we cannot use recursive function calls. */ errno_saved = errno; errno_reason = 0; errstring = NULL; errno = 0; name = NULL; for (runp = known; runp; ) { struct link_map *l = runp->map; struct link_map **needed = NULL; unsigned int nneeded = 0; /* Unless otherwise stated, this object is handled. */ runp->done = 1; /* Allocate a temporary record to contain the references to the dependencies of this object. */ if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL && l != map && l->l_ldnum > 0) needed = (struct link_map **) alloca (l->l_ldnum * sizeof (struct link_map *)); if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG]) { const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); struct openaux_args args; struct list *orig; const ElfW(Dyn) *d; args.strtab = strtab; args.map = l; args.trace_mode = trace_mode; orig = runp; for (d = l->l_ld; d->d_tag != DT_NULL; ++d) if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED) { /* Map in the needed object. */ struct link_map *dep; int err; /* Recognize DSTs. */ name = expand_dst (l, strtab + d->d_un.d_val, 0); /* Store the tag in the argument structure. */ args.name = name; err = _dl_catch_error (&objname, &errstring, openaux, &args); if (__builtin_expect (errstring != NULL, 0)) { if (err) errno_reason = err; else errno_reason = -1; goto out; } else dep = args.aux; if (! dep->l_reserved) { /* Allocate new entry. */ struct list *newp; newp = alloca (sizeof (struct list)); /* Append DEP to the list. */ newp->map = dep; newp->done = 0; newp->next = NULL; tail->next = newp; tail = newp; ++nlist; /* Set the mark bit that says it's already in the list. */ dep->l_reserved = 1; } /* Remember this dependency. */ if (needed != NULL) needed[nneeded++] = dep; } else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER) { struct list *newp; /* Recognize DSTs. */ name = expand_dst (l, strtab + d->d_un.d_val, d->d_tag == DT_AUXILIARY); /* Store the tag in the argument structure. */ args.name = name; if (d->d_tag == DT_AUXILIARY) { int err; /* Say that we are about to load an auxiliary library. */ if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) _dl_debug_printf ("load auxiliary object=%s" " requested by file=%s\n", name, l->l_name[0] ? l->l_name : _dl_argv[0]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -