Allow ldd(1) be used on shared libraries in addition to executables.

This commit is contained in:
Maxim Sobolev 2002-02-04 10:33:48 +00:00
parent fc41545e4e
commit c6de4ce791
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=90172
5 changed files with 57 additions and 12 deletions

View File

@ -45,6 +45,7 @@
#define RTLD_MODEMASK 0x3
#define RTLD_GLOBAL 0x100 /* Make symbols globally available */
#define RTLD_LOCAL 0 /* Opposite of RTLD_GLOBAL, and the default */
#define RTLD_TRACE 0x200 /* Trace loaded objects and exit */
/*
* Special handle arguments for dlsym().

View File

@ -123,6 +123,13 @@ Symbols in this shared object and its DAG of needed objects will be
available for resolving undefined references only from other objects
in the same DAG. This is the default, but it may be specified
explicitly with this flag.
.It Dv RTLD_TRACE
When set, causes dynamic linker to exit after loading all objects
needed by this shared object and printing a summary which includes
the absolute pathnames of all objects, to standard output.
With this flag
.Fn dlopen
will return to the caller only in the case of error.
.El
.Pp
If

View File

@ -107,6 +107,7 @@ static void objlist_remove_unref(Objlist *);
static int relocate_objects(Obj_Entry *, bool);
static void rtld_exit(void);
static char *search_library_path(const char *, const char *);
static const void **get_program_var_addr(const char *name);
static void set_program_var(const char *, const void *);
static const Elf_Sym *symlook_default(const char *, unsigned long hash,
const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt);
@ -1556,6 +1557,11 @@ dlopen(const char *name, int mode)
Obj_Entry **old_obj_tail;
Obj_Entry *obj;
Objlist initlist;
int result;
ld_tracing = (mode & RTLD_TRACE) == 0 ? NULL : "1";
if (ld_tracing != NULL)
environ = (char **)*get_program_var_addr("environ");
objlist_init(&initlist);
@ -1581,7 +1587,14 @@ dlopen(const char *name, int mode)
if (*old_obj_tail != NULL) { /* We loaded something new. */
assert(*old_obj_tail == obj);
if (load_needed_objects(obj) == -1 ||
result = load_needed_objects(obj);
if (result != -1 && ld_tracing) {
trace_loaded_objects(obj);
wlock_release();
exit(0);
}
if (result == -1 ||
(init_dag(obj), relocate_objects(obj, mode == RTLD_NOW)) == -1) {
obj->dl_refcount--;
unref_dag(obj);
@ -1812,12 +1825,10 @@ r_debug_state(struct r_debug* rd, struct link_map *m)
}
/*
* Set a pointer variable in the main program to the given value. This
* is used to set key variables such as "environ" before any of the
* init functions are called.
* Get address of the pointer variable in the main program.
*/
static void
set_program_var(const char *name, const void *value)
static const void **
get_program_var_addr(const char *name)
{
const Obj_Entry *obj;
unsigned long hash;
@ -1830,11 +1841,26 @@ set_program_var(const char *name, const void *value)
const void **addr;
addr = (const void **)(obj->relocbase + def->st_value);
dbg("\"%s\": *%p <-- %p", name, addr, value);
*addr = value;
break;
return addr;
}
}
return NULL;
}
/*
* Set a pointer variable in the main program to the given value. This
* is used to set key variables such as "environ" before any of the
* init functions are called.
*/
static void
set_program_var(const char *name, const void *value)
{
const void **addr;
if ((addr = get_program_var_addr(name)) != NULL) {
dbg("\"%s\": *%p <-- %p", name, addr, value);
*addr = value;
}
}
/*

View File

@ -13,7 +13,8 @@
.Ar program ...
.Sh DESCRIPTION
.Nm
displays all shared objects that are needed to run the given program.
displays all shared objects that are needed to run the given program or
to load the given shared object.
Contrary to
.Xr nm 1 ,
the list includes

View File

@ -36,6 +36,7 @@ static const char rcsid[] =
#include <sys/wait.h>
#include <machine/elf.h>
#include <a.out.h>
#include <dlfcn.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
@ -116,6 +117,7 @@ char *argv[];
int n;
int status;
int file_ok;
int is_shlib;
if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
warn("%s", *argv);
@ -130,6 +132,7 @@ char *argv[];
}
file_ok = 1;
is_shlib = 0;
if (n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) {
/* a.out file */
if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
@ -167,6 +170,8 @@ char *argv[];
if (!dynamic) {
warnx("%s: not a dynamic executable", *argv);
file_ok = 0;
} else if (hdr.elf.e_type == ET_DYN) {
is_shlib = 1;
}
} else {
warnx("%s: not a dynamic executable", *argv);
@ -204,8 +209,13 @@ char *argv[];
}
break;
case 0:
execl(*argv, *argv, (char *)NULL);
warn("%s", *argv);
if (is_shlib == 0) {
execl(*argv, *argv, (char *)NULL);
warn("%s", *argv);
} else {
dlopen(*argv, RTLD_TRACE);
warnx("%s: %s", *argv, dlerror());
}
_exit(1);
}
}