diff options
-rw-r--r-- | bt.c | 57 |
1 files changed, 50 insertions, 7 deletions
@@ -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; |