Allow ldd(1) be used on shared libraries in addition to executables.
This commit is contained in:
parent
fc41545e4e
commit
c6de4ce791
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=90172
@ -45,6 +45,7 @@
|
|||||||
#define RTLD_MODEMASK 0x3
|
#define RTLD_MODEMASK 0x3
|
||||||
#define RTLD_GLOBAL 0x100 /* Make symbols globally available */
|
#define RTLD_GLOBAL 0x100 /* Make symbols globally available */
|
||||||
#define RTLD_LOCAL 0 /* Opposite of RTLD_GLOBAL, and the default */
|
#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().
|
* Special handle arguments for dlsym().
|
||||||
|
@ -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
|
available for resolving undefined references only from other objects
|
||||||
in the same DAG. This is the default, but it may be specified
|
in the same DAG. This is the default, but it may be specified
|
||||||
explicitly with this flag.
|
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
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
If
|
If
|
||||||
|
@ -107,6 +107,7 @@ static void objlist_remove_unref(Objlist *);
|
|||||||
static int relocate_objects(Obj_Entry *, bool);
|
static int relocate_objects(Obj_Entry *, bool);
|
||||||
static void rtld_exit(void);
|
static void rtld_exit(void);
|
||||||
static char *search_library_path(const char *, const char *);
|
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 void set_program_var(const char *, const void *);
|
||||||
static const Elf_Sym *symlook_default(const char *, unsigned long hash,
|
static const Elf_Sym *symlook_default(const char *, unsigned long hash,
|
||||||
const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt);
|
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 **old_obj_tail;
|
||||||
Obj_Entry *obj;
|
Obj_Entry *obj;
|
||||||
Objlist initlist;
|
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);
|
objlist_init(&initlist);
|
||||||
|
|
||||||
@ -1581,7 +1587,14 @@ dlopen(const char *name, int mode)
|
|||||||
if (*old_obj_tail != NULL) { /* We loaded something new. */
|
if (*old_obj_tail != NULL) { /* We loaded something new. */
|
||||||
assert(*old_obj_tail == obj);
|
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) {
|
(init_dag(obj), relocate_objects(obj, mode == RTLD_NOW)) == -1) {
|
||||||
obj->dl_refcount--;
|
obj->dl_refcount--;
|
||||||
unref_dag(obj);
|
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
|
* Get address of the pointer variable in the main program.
|
||||||
* is used to set key variables such as "environ" before any of the
|
|
||||||
* init functions are called.
|
|
||||||
*/
|
*/
|
||||||
static void
|
static const void **
|
||||||
set_program_var(const char *name, const void *value)
|
get_program_var_addr(const char *name)
|
||||||
{
|
{
|
||||||
const Obj_Entry *obj;
|
const Obj_Entry *obj;
|
||||||
unsigned long hash;
|
unsigned long hash;
|
||||||
@ -1830,11 +1841,26 @@ set_program_var(const char *name, const void *value)
|
|||||||
const void **addr;
|
const void **addr;
|
||||||
|
|
||||||
addr = (const void **)(obj->relocbase + def->st_value);
|
addr = (const void **)(obj->relocbase + def->st_value);
|
||||||
dbg("\"%s\": *%p <-- %p", name, addr, value);
|
return addr;
|
||||||
*addr = value;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -13,7 +13,8 @@
|
|||||||
.Ar program ...
|
.Ar program ...
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm
|
.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
|
Contrary to
|
||||||
.Xr nm 1 ,
|
.Xr nm 1 ,
|
||||||
the list includes
|
the list includes
|
||||||
|
@ -36,6 +36,7 @@ static const char rcsid[] =
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <machine/elf.h>
|
#include <machine/elf.h>
|
||||||
#include <a.out.h>
|
#include <a.out.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -116,6 +117,7 @@ char *argv[];
|
|||||||
int n;
|
int n;
|
||||||
int status;
|
int status;
|
||||||
int file_ok;
|
int file_ok;
|
||||||
|
int is_shlib;
|
||||||
|
|
||||||
if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
|
if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
|
||||||
warn("%s", *argv);
|
warn("%s", *argv);
|
||||||
@ -130,6 +132,7 @@ char *argv[];
|
|||||||
}
|
}
|
||||||
|
|
||||||
file_ok = 1;
|
file_ok = 1;
|
||||||
|
is_shlib = 0;
|
||||||
if (n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) {
|
if (n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) {
|
||||||
/* a.out file */
|
/* a.out file */
|
||||||
if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
|
if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
|
||||||
@ -167,6 +170,8 @@ char *argv[];
|
|||||||
if (!dynamic) {
|
if (!dynamic) {
|
||||||
warnx("%s: not a dynamic executable", *argv);
|
warnx("%s: not a dynamic executable", *argv);
|
||||||
file_ok = 0;
|
file_ok = 0;
|
||||||
|
} else if (hdr.elf.e_type == ET_DYN) {
|
||||||
|
is_shlib = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warnx("%s: not a dynamic executable", *argv);
|
warnx("%s: not a dynamic executable", *argv);
|
||||||
@ -204,8 +209,13 @@ char *argv[];
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
execl(*argv, *argv, (char *)NULL);
|
if (is_shlib == 0) {
|
||||||
warn("%s", *argv);
|
execl(*argv, *argv, (char *)NULL);
|
||||||
|
warn("%s", *argv);
|
||||||
|
} else {
|
||||||
|
dlopen(*argv, RTLD_TRACE);
|
||||||
|
warnx("%s: %s", *argv, dlerror());
|
||||||
|
}
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user