aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bt.c57
1 files changed, 50 insertions, 7 deletions
diff --git a/bt.c b/bt.c
index d51d35c..7302799 100644
--- a/bt.c
+++ b/bt.c
@@ -24,6 +24,7 @@
#define _GNU_SOURCE
#include <dlfcn.h>
+#include <link.h>
#include <signal.h>
#include <assert.h>
@@ -169,11 +170,59 @@ static void* thread_entry(void* th_arg) {
return ret;
}
+static void resolve_next_pthread_create() {
+ if (NEXT_PTHREAD_CREATE) {
+ return;
+ }
+
+ // The following implements dlsym(RTLD_NEXT, "pthread_create") manually.
+ //
+ // In the past I have observed a case where dlsym(RTLD_NEXT) returned an
+ // address from a library earlier in the link map. This is problematic as
+ // calling the received function pointer ends in an infinite recursion.
+ //
+ // This may be a bug or I did not fully understand the case yet as I have
+ // only observed it in special occasions where there are other LD_PRELOAD
+ // libraries implementing the same wrapper function and invoking the wrapper
+ // before the static initializers of this library have been executed.
+ //
+ // So far this implementation yielded "better" results.
+
+ void* ret_addr = __builtin_return_address(0);
+ Dl_info _info;
+ memset(&_info, 0, sizeof(_info));
+ struct link_map* lmap;
+
+ if (dladdr1(ret_addr, &_info, (void**)&lmap, RTLD_DL_LINKMAP) == 0) {
+ FAIL("dladdr1 failed while resolving next pthread_create");
+ exit(1);
+ }
+
+ for (lmap = lmap->l_next; lmap && !NEXT_PTHREAD_CREATE; lmap = lmap->l_next) {
+ if (!lmap->l_name) {
+ continue;
+ }
+
+ void* dso = dlopen(lmap->l_name, RTLD_LOCAL | RTLD_LAZY);
+ if (!dso) {
+ WARN("failed to open %s, continue with next", lmap->l_name);
+ continue;
+ }
+ NEXT_PTHREAD_CREATE = dlsym(dso, "pthread_create");
+ dlclose(dso);
+ }
+
+ if (!NEXT_PTHREAD_CREATE) {
+ FAIL("failed to resolve next pthread_create function");
+ exit(1);
+ }
+}
+
int pthread_create(pthread_t* thread,
const pthread_attr_t* attr,
void* (*start_routine)(void*),
void* arg) {
- assert(NEXT_PTHREAD_CREATE);
+ resolve_next_pthread_create();
struct thread_arg* th_arg = malloc(sizeof(struct thread_arg));
th_arg->start_routine = start_routine;
@@ -184,12 +233,6 @@ int pthread_create(pthread_t* thread,
// -- GLOBAL INITIALIZATION ----------------------------------------------------
static void __attribute__((constructor)) init() {
- NEXT_PTHREAD_CREATE = dlsym(RTLD_NEXT, "pthread_create");
- if (NEXT_PTHREAD_CREATE == NULL) {
- FAIL("failed to get pthread_create");
- exit(1);
- }
-
if (libbt_install_sighandler() != 0) {
FAIL("failed to install signal handler");
return;