summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2007-01-09 17:50:05 +0000
committerjhb <jhb@FreeBSD.org>2007-01-09 17:50:05 +0000
commit6952dd37724ec9f0f9e4375539e42b951f7ab934 (patch)
tree0fa5cd70b668b21da1aad4c6450b427ed7c2d58d
parent0f316bc65f504702265cc9bf8bea3ad73a18455e (diff)
downloadFreeBSD-src-6952dd37724ec9f0f9e4375539e42b951f7ab934.zip
FreeBSD-src-6952dd37724ec9f0f9e4375539e42b951f7ab934.tar.gz
Add various utrace's for use with ktrace to the ELF runtime linker. To
activate the traces, set the LD_UTRACE (or LD_32_UTRACE) environment variable. This also includes code in kdump(8) to parse the traces. Reviewed by: kan, jdp MFC after: 2 weeks
-rw-r--r--libexec/rtld-elf/rtld.c67
-rw-r--r--usr.bin/kdump/kdump.c107
2 files changed, 174 insertions, 0 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 448a3e3..e8e31c5 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -40,6 +40,8 @@
#include <sys/mount.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/ktrace.h>
#include <dlfcn.h>
#include <err.h>
@@ -136,6 +138,7 @@ static int rtld_verify_versions(const Objlist *);
static int rtld_verify_object_versions(Obj_Entry *);
static void object_add_name(Obj_Entry *, const char *);
static int object_match_name(const Obj_Entry *, const char *);
+static void ld_utrace_log(int, void *, void *, size_t, int, const char *);
void r_debug_state(struct r_debug *, struct link_map *);
@@ -155,6 +158,7 @@ static char *ld_library_path; /* Environment variable for search path */
static char *ld_preload; /* Environment variable for libraries to
load first */
static char *ld_tracing; /* Called from ldd to print libs */
+static char *ld_utrace; /* Use utrace() to log events. */
static Obj_Entry *obj_list; /* Head of linked list of shared objects */
static Obj_Entry **obj_tail; /* Link field of last object in list */
static Obj_Entry *obj_main; /* The main program shared object */
@@ -230,6 +234,53 @@ int tls_max_index = 1; /* Largest module index allocated */
(dlp)->num_alloc = obj_count, \
(dlp)->num_used = 0)
+#define UTRACE_DLOPEN_START 1
+#define UTRACE_DLOPEN_STOP 2
+#define UTRACE_DLCLOSE_START 3
+#define UTRACE_DLCLOSE_STOP 4
+#define UTRACE_LOAD_OBJECT 5
+#define UTRACE_UNLOAD_OBJECT 6
+#define UTRACE_ADD_RUNDEP 7
+#define UTRACE_PRELOAD_FINISHED 8
+#define UTRACE_INIT_CALL 9
+#define UTRACE_FINI_CALL 10
+
+struct utrace_rtld {
+ char sig[4]; /* 'RTLD' */
+ int event;
+ void *handle;
+ void *mapbase; /* Used for 'parent' and 'init/fini' */
+ size_t mapsize;
+ int refcnt; /* Used for 'mode' */
+ char name[MAXPATHLEN];
+};
+
+#define LD_UTRACE(e, h, mb, ms, r, n) do { \
+ if (ld_utrace != NULL) \
+ ld_utrace_log(e, h, mb, ms, r, n); \
+} while (0)
+
+static void
+ld_utrace_log(int event, void *handle, void *mapbase, size_t mapsize,
+ int refcnt, const char *name)
+{
+ struct utrace_rtld ut;
+
+ ut.sig[0] = 'R';
+ ut.sig[1] = 'T';
+ ut.sig[2] = 'L';
+ ut.sig[3] = 'D';
+ ut.event = event;
+ ut.handle = handle;
+ ut.mapbase = mapbase;
+ ut.mapsize = mapsize;
+ ut.refcnt = refcnt;
+ bzero(ut.name, sizeof(ut.name));
+ if (name)
+ strlcpy(ut.name, name, sizeof(ut.name));
+ utrace(&ut, sizeof(ut));
+}
+
/*
* Main entry point for dynamic linking. The first argument is the
* stack pointer. The stack is expected to be laid out as described
@@ -309,6 +360,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
} else
dangerous_ld_env = 0;
ld_tracing = getenv(LD_ "TRACE_LOADED_OBJECTS");
+ ld_utrace = getenv(LD_ "UTRACE");
if (ld_debug != NULL && *ld_debug != '\0')
debug = 1;
@@ -1236,6 +1288,7 @@ load_preload_objects(void)
p += len;
p += strspn(p, delim);
}
+ LD_UTRACE(UTRACE_PRELOAD_FINISHED, NULL, NULL, 0, 0, NULL);
return 0;
}
@@ -1340,6 +1393,8 @@ do_load_object(int fd, const char *name, char *path, struct stat *sbp)
obj->mapbase + obj->mapsize - 1, obj->path);
if (obj->textrel)
dbg(" WARNING: %s has impure text", obj->path);
+ LD_UTRACE(UTRACE_LOAD_OBJECT, obj, obj->mapbase, obj->mapsize, 0,
+ obj->path);
return obj;
}
@@ -1378,6 +1433,8 @@ objlist_call_fini(Objlist *list)
if (elm->obj->refcount == 0) {
dbg("calling fini function for %s at %p", elm->obj->path,
(void *)elm->obj->fini);
+ LD_UTRACE(UTRACE_FINI_CALL, elm->obj, (void *)elm->obj->fini, 0, 0,
+ elm->obj->path);
call_initfini_pointer(elm->obj, elm->obj->fini);
}
}
@@ -1403,6 +1460,8 @@ objlist_call_init(Objlist *list)
STAILQ_FOREACH(elm, list, link) {
dbg("calling init function for %s at %p", elm->obj->path,
(void *)elm->obj->init);
+ LD_UTRACE(UTRACE_INIT_CALL, elm->obj, (void *)elm->obj->init, 0, 0,
+ elm->obj->path);
call_initfini_pointer(elm->obj, elm->obj->init);
}
errmsg_restore(saved_msg);
@@ -1676,6 +1735,8 @@ dlclose(void *handle)
wlock_release(rtld_bind_lock, lockstate);
return -1;
}
+ LD_UTRACE(UTRACE_DLCLOSE_START, handle, NULL, 0, root->dl_refcount,
+ root->path);
/* Unreference the object and its dependencies. */
root->dl_refcount--;
@@ -1697,6 +1758,7 @@ dlclose(void *handle)
unload_object(root);
GDB_STATE(RT_CONSISTENT,NULL);
}
+ LD_UTRACE(UTRACE_DLCLOSE_STOP, handle, NULL, 0, 0, NULL);
wlock_release(rtld_bind_lock, lockstate);
return 0;
}
@@ -1739,6 +1801,7 @@ dlopen(const char *name, int mode)
Objlist initlist;
int result, lockstate;
+ LD_UTRACE(UTRACE_DLOPEN_START, NULL, NULL, 0, mode, name);
ld_tracing = (mode & RTLD_TRACE) == 0 ? NULL : "1";
if (ld_tracing != NULL)
environ = (char **)*get_program_var_addr("environ");
@@ -1791,6 +1854,8 @@ dlopen(const char *name, int mode)
}
}
+ LD_UTRACE(UTRACE_DLOPEN_STOP, obj, NULL, 0, obj ? obj->dl_refcount : 0,
+ name);
GDB_STATE(RT_CONSISTENT,obj ? &obj->linkmap : NULL);
/* Call the init functions with no locks held. */
@@ -2655,6 +2720,8 @@ unload_object(Obj_Entry *root)
linkp = &obj_list->next;
while ((obj = *linkp) != NULL) {
if (obj->refcount == 0) {
+ LD_UTRACE(UTRACE_UNLOAD_OBJECT, obj, obj->mapbase, obj->mapsize, 0,
+ obj->path);
dbg("unloading \"%s\"", obj->path);
munmap(obj->mapbase, obj->mapsize);
linkmap_delete(obj);
diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c
index 5854ba8..24979d9 100644
--- a/usr.bin/kdump/kdump.c
+++ b/usr.bin/kdump/kdump.c
@@ -59,6 +59,7 @@ extern int errno;
#include <sys/ioctl.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
+#include <dlfcn.h>
#include <err.h>
#include <locale.h>
#include <stdio.h>
@@ -975,6 +976,107 @@ ktrcsw(struct ktr_csw *cs)
cs->user ? "user" : "kernel");
}
+#define UTRACE_DLOPEN_START 1
+#define UTRACE_DLOPEN_STOP 2
+#define UTRACE_DLCLOSE_START 3
+#define UTRACE_DLCLOSE_STOP 4
+#define UTRACE_LOAD_OBJECT 5
+#define UTRACE_UNLOAD_OBJECT 6
+#define UTRACE_ADD_RUNDEP 7
+#define UTRACE_PRELOAD_FINISHED 8
+#define UTRACE_INIT_CALL 9
+#define UTRACE_FINI_CALL 10
+
+struct utrace_rtld {
+ char sig[4]; /* 'RTLD' */
+ int event;
+ void *handle;
+ void *mapbase;
+ size_t mapsize;
+ int refcnt;
+ char name[MAXPATHLEN];
+};
+
+void
+ktruser_rtld(int len, unsigned char *p)
+{
+ struct utrace_rtld *ut = (struct utrace_rtld *)p;
+ void *parent;
+ int mode;
+
+ switch (ut->event) {
+ case UTRACE_DLOPEN_START:
+ mode = ut->refcnt;
+ printf("dlopen(%s, ", ut->name);
+ switch (mode & RTLD_MODEMASK) {
+ case RTLD_NOW:
+ printf("RTLD_NOW");
+ break;
+ case RTLD_LAZY:
+ printf("RTLD_LAZY");
+ break;
+ default:
+ printf("%#x", mode & RTLD_MODEMASK);
+ }
+ if (mode & RTLD_GLOBAL)
+ printf(" | RTLD_GLOBAL");
+ if (mode & RTLD_TRACE)
+ printf(" | RTLD_TRACE");
+ if (mode & ~(RTLD_MODEMASK | RTLD_GLOBAL | RTLD_TRACE))
+ printf(" | %#x", mode &
+ ~(RTLD_MODEMASK | RTLD_GLOBAL | RTLD_TRACE));
+ printf(")\n");
+ break;
+ case UTRACE_DLOPEN_STOP:
+ printf("%p = dlopen(%s) ref %d\n", ut->handle, ut->name,
+ ut->refcnt);
+ break;
+ case UTRACE_DLCLOSE_START:
+ printf("dlclose(%p) (%s, %d)\n", ut->handle, ut->name,
+ ut->refcnt);
+ break;
+ case UTRACE_DLCLOSE_STOP:
+ printf("dlclose(%p) finished\n", ut->handle);
+ break;
+ case UTRACE_LOAD_OBJECT:
+ printf("RTLD: loaded %p @ %p - %p (%s)\n", ut->handle,
+ ut->mapbase, (char *)ut->mapbase + ut->mapsize - 1,
+ ut->name);
+ break;
+ case UTRACE_UNLOAD_OBJECT:
+ printf("RTLD: unloaded %p @ %p - %p (%s)\n", ut->handle,
+ ut->mapbase, (char *)ut->mapbase + ut->mapsize - 1,
+ ut->name);
+ break;
+ case UTRACE_ADD_RUNDEP:
+ parent = ut->mapbase;
+ printf("RTLD: %p now depends on %p (%s, %d)\n", parent,
+ ut->handle, ut->name, ut->refcnt);
+ break;
+ case UTRACE_PRELOAD_FINISHED:
+ printf("RTLD: LD_PRELOAD finished\n");
+ break;
+ case UTRACE_INIT_CALL:
+ printf("RTLD: init %p for %p (%s)\n", ut->mapbase, ut->handle,
+ ut->name);
+ break;
+ case UTRACE_FINI_CALL:
+ printf("RTLD: fini %p for %p (%s)\n", ut->mapbase, ut->handle,
+ ut->name);
+ break;
+ default:
+ p += 4;
+ len -= 4;
+ printf("RTLD: %d ", len);
+ while (len--)
+ if (decimal)
+ printf(" %d", *p++);
+ else
+ printf(" %02x", *p++);
+ printf("\n");
+ }
+}
+
struct utrace_malloc {
void *p;
size_t s;
@@ -1003,6 +1105,11 @@ void
ktruser(int len, unsigned char *p)
{
+ if (len >= 8 && bcmp(p, "RTLD", 4) == 0) {
+ ktruser_rtld(len, p);
+ return;
+ }
+
if (len == sizeof(struct utrace_malloc)) {
ktruser_malloc(len, p);
return;
OpenPOWER on IntegriCloud