1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
|
/*
* Copyright (c) 2015, Charlie Curtsinger and Emery Berger,
* University of Massachusetts Amherst
* This file is part of the Coz project. See LICENSE.md file at the top-level
* directory of this distribution and at http://github.com/plasma-umass/coz.
*/
#include "real.h"
#include <dlfcn.h>
#include <dlfcn.h>
#include <stdint.h>
#include <string.h>
static bool resolving = false; //< Set to true while symbol resolution is in progress
static bool in_dlopen = false; //< Set to true while dlopen is running
static void* pthread_handle = NULL; //< The `dlopen` handle to libpthread
#define GET_SYMBOL_HANDLE(name, handle) \
decltype(::name)* real_##name = nullptr; \
while(!__atomic_exchange_n(&resolving, true, __ATOMIC_ACQ_REL)) {} \
uintptr_t addr = reinterpret_cast<uintptr_t>(dlsym(handle, #name)); \
memcpy(&real_##name, &addr, sizeof(uintptr_t)); \
if(real_##name) { \
memcpy(&real::name, &addr, sizeof(uintptr_t)); \
} \
__atomic_store_n(&resolving, false, __ATOMIC_RELEASE);
#define GET_SYMBOL(name) GET_SYMBOL_HANDLE(name, RTLD_NEXT)
#define NORETURN __attribute__((noreturn))
/**
* Get the `dlopen` handle for libpthread
*/
static void* get_pthread_handle() {
if(pthread_handle == NULL && !__atomic_exchange_n(&in_dlopen, true, __ATOMIC_ACQ_REL)) {
pthread_handle = dlopen("libpthread.so.0", RTLD_NOW | RTLD_GLOBAL | RTLD_NOLOAD);
__atomic_store_n(&in_dlopen, false, __ATOMIC_RELEASE);
}
return pthread_handle;
}
/*
* Resolver functions attempt to locate the requested function. Resolution will fail if
* it is invoked recursively, or if the symbol is not found. If resolution fails, most
* cases an error code of -1 is returned. Synchronization options will fail silently to
* accommodate synchronization operations during startup. If resolution succeeds, the
* located function is called.
*/
static NORETURN void resolve_exit(int status) throw() {
GET_SYMBOL(exit);
if(real_exit) real_exit(status);
abort();
}
static NORETURN void resolve__exit(int status) throw() {
GET_SYMBOL(_exit);
if(real__exit) real__exit(status);
abort();
}
static NORETURN void resolve__Exit(int status) throw() {
GET_SYMBOL(_Exit);
if(real__Exit) real__Exit(status);
abort();
}
static int resolve_fork() throw() {
GET_SYMBOL(fork);
if(real_fork) return real_fork();
else return -1;
}
static int resolve_sigaction(int signum, const struct sigaction* act, struct sigaction* old_act) throw() {
GET_SYMBOL(sigaction);
if(real_sigaction) return real_sigaction(signum, act, old_act);
else return -1;
}
static sighandler_t resolve_signal(int signum, sighandler_t handler) throw() {
GET_SYMBOL(signal);
if(real_signal) return real_signal(signum, handler);
else return SIG_ERR;
}
static int resolve_kill(pid_t pid, int sig) throw() {
GET_SYMBOL(kill);
if(real_kill) return real_kill(pid, sig);
else return -1;
}
static int resolve_sigprocmask(int how, const sigset_t* set, sigset_t* oldset) throw() {
GET_SYMBOL(sigprocmask);
if(real_sigprocmask) return real_sigprocmask(how, set, oldset);
else return -1;
}
static int resolve_sigwait(const sigset_t* set, int* sig) {
GET_SYMBOL(sigwait);
if(real_sigwait) return real_sigwait(set, sig);
else return -1;
}
static int resolve_sigwaitinfo(const sigset_t* set, siginfo_t* info) {
GET_SYMBOL(sigwaitinfo);
if(real_sigwaitinfo) return real_sigwaitinfo(set, info);
else return -1;
}
static int resolve_sigtimedwait(const sigset_t* set, siginfo_t* info, const struct timespec* timeout) {
GET_SYMBOL(sigtimedwait);
if(real_sigtimedwait) return real_sigtimedwait(set, info, timeout);
else return -1;
}
static int resolve_pthread_create(pthread_t* t, const pthread_attr_t* attr, void* (*fn)(void*), void* arg) throw() {
GET_SYMBOL_HANDLE(pthread_create, get_pthread_handle());
if(real_pthread_create) return real_pthread_create(t, attr, fn, arg);
else return -1;
}
static NORETURN void resolve_pthread_exit(void* retval) {
GET_SYMBOL_HANDLE(pthread_exit, get_pthread_handle());
if(real_pthread_exit) real_pthread_exit(retval);
abort();
}
static int resolve_pthread_join(pthread_t t, void** ret) {
GET_SYMBOL_HANDLE(pthread_join, get_pthread_handle());
if(real_pthread_join) return real_pthread_join(t, ret);
else return -1;
}
static int resolve_pthread_tryjoin_np(pthread_t t, void** ret) throw() {
GET_SYMBOL_HANDLE(pthread_tryjoin_np, get_pthread_handle());
if(real_pthread_tryjoin_np) return real_pthread_tryjoin_np(t, ret);
else return -1;
}
static int resolve_pthread_timedjoin_np(pthread_t t, void** ret, const struct timespec* abstime) {
GET_SYMBOL_HANDLE(pthread_timedjoin_np, get_pthread_handle());
if(real_pthread_timedjoin_np) return real_pthread_timedjoin_np(t, ret, abstime);
else return -1;
}
static int resolve_pthread_kill(pthread_t t, int sig) throw() {
GET_SYMBOL_HANDLE(pthread_kill, get_pthread_handle());
if(real_pthread_kill) return real_pthread_kill(t, sig);
else return -1;
}
static int resolve_pthread_sigqueue(pthread_t t, int sig, const union sigval val) throw() {
GET_SYMBOL_HANDLE(pthread_sigqueue, get_pthread_handle());
if(real_pthread_sigqueue) return real_pthread_sigqueue(t, sig, val);
else return -1;
}
static int resolve_pthread_sigmask(int how, const sigset_t* set, sigset_t* oldset) throw() {
GET_SYMBOL_HANDLE(pthread_sigmask, get_pthread_handle());
if(real_pthread_sigmask) return real_pthread_sigmask(how, set, oldset);
else return -1;
}
static int resolve_pthread_mutex_lock(pthread_mutex_t* mutex) throw() {
GET_SYMBOL_HANDLE(pthread_mutex_lock, get_pthread_handle());
if(real_pthread_mutex_lock) return real_pthread_mutex_lock(mutex);
else return 0; // Silently elide locks during linking
}
static int resolve_pthread_mutex_trylock(pthread_mutex_t* mutex) throw() {
GET_SYMBOL_HANDLE(pthread_mutex_trylock, get_pthread_handle());
if(real_pthread_mutex_trylock) return real_pthread_mutex_trylock(mutex);
else return 0; // Silently elide locks during linking
}
static int resolve_pthread_mutex_unlock(pthread_mutex_t* mutex) throw() {
GET_SYMBOL_HANDLE(pthread_mutex_unlock, get_pthread_handle());
if(real_pthread_mutex_unlock) return real_pthread_mutex_unlock(mutex);
else return 0; // Silently elide locks during linking
}
static int resolve_pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) throw() {
GET_SYMBOL_HANDLE(pthread_cond_wait, get_pthread_handle());
if(real_pthread_cond_wait) return real_pthread_cond_wait(cond, mutex);
else return 0; // Silently elide synchronization during linking
}
static int resolve_pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const struct timespec* abstime) throw() {
GET_SYMBOL_HANDLE(pthread_cond_timedwait, get_pthread_handle());
if(real_pthread_cond_timedwait) return real_pthread_cond_timedwait(cond, mutex, abstime);
else return 0; // Silently elide synchronization during linking
}
static int resolve_pthread_cond_signal(pthread_cond_t* cond) throw() {
GET_SYMBOL_HANDLE(pthread_cond_signal, get_pthread_handle());
if(real_pthread_cond_signal) return real_pthread_cond_signal(cond);
else return 0; // Silently elide synchronization during linking
}
static int resolve_pthread_cond_broadcast(pthread_cond_t* cond) throw() {
GET_SYMBOL_HANDLE(pthread_cond_broadcast, get_pthread_handle());
if(real_pthread_cond_broadcast) return real_pthread_cond_broadcast(cond);
else return 0; // Silently elide synchronization during linking
}
static int resolve_pthread_barrier_wait(pthread_barrier_t* barr) throw() {
GET_SYMBOL_HANDLE(pthread_barrier_wait, get_pthread_handle());
if(real_pthread_barrier_wait) return real_pthread_barrier_wait(barr);
else return 0; // Silently elide synchronization during linking
}
static int resolve_pthread_rwlock_rdlock(pthread_rwlock_t* rwlock) throw() {
GET_SYMBOL_HANDLE(pthread_rwlock_rdlock, get_pthread_handle());
if(real_pthread_rwlock_rdlock) return real_pthread_rwlock_rdlock(rwlock);
else return 0; // Silently elide synchronization during linking
}
static int resolve_pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock) throw() {
GET_SYMBOL_HANDLE(pthread_rwlock_tryrdlock, get_pthread_handle());
if(real_pthread_rwlock_tryrdlock) return real_pthread_rwlock_tryrdlock(rwlock);
else return 0; // Silently elide synchronization during linking
}
static int resolve_pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock, const struct timespec* abstime) throw() {
GET_SYMBOL_HANDLE(pthread_rwlock_timedrdlock, get_pthread_handle());
if(real_pthread_rwlock_timedrdlock) return real_pthread_rwlock_timedrdlock(rwlock, abstime);
else return 0; // Silently elide synchronization during linking
}
static int resolve_pthread_rwlock_wrlock(pthread_rwlock_t* rwlock) throw() {
GET_SYMBOL_HANDLE(pthread_rwlock_wrlock, get_pthread_handle());
if(real_pthread_rwlock_wrlock) return real_pthread_rwlock_wrlock(rwlock);
else return 0; // Silently elide synchronization during linking
}
static int resolve_pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock) throw() {
GET_SYMBOL_HANDLE(pthread_rwlock_trywrlock, get_pthread_handle());
if(real_pthread_rwlock_trywrlock) return real_pthread_rwlock_trywrlock(rwlock);
else return 0; // Silently elide synchronization during linking
}
static int resolve_pthread_rwlock_timedwrlock(pthread_rwlock_t* rwlock, const struct timespec* abstime) throw() {
GET_SYMBOL_HANDLE(pthread_rwlock_timedwrlock, get_pthread_handle());
if(real_pthread_rwlock_timedwrlock) return real_pthread_rwlock_timedwrlock(rwlock, abstime);
else return 0; // Silently elide synchronization during linking
}
static int resolve_pthread_rwlock_unlock(pthread_rwlock_t* rwlock) throw() {
GET_SYMBOL_HANDLE(pthread_rwlock_unlock, get_pthread_handle());
if(real_pthread_rwlock_unlock) return real_pthread_rwlock_unlock(rwlock);
else return 0; // Silently elide synchronization during linking
}
#define DEFINE_WRAPPER(name) decltype(::name)* name = &resolve_##name;
/**
* Define all wrapper symbols in the `real` namespace. Initialize all wrappers to the
* corresponding resolver function.
*/
namespace real {
DEFINE_WRAPPER(exit);
DEFINE_WRAPPER(_exit);
DEFINE_WRAPPER(_Exit);
DEFINE_WRAPPER(fork);
DEFINE_WRAPPER(sigaction);
DEFINE_WRAPPER(signal);
DEFINE_WRAPPER(kill);
DEFINE_WRAPPER(sigprocmask);
DEFINE_WRAPPER(sigwait);
DEFINE_WRAPPER(sigwaitinfo);
DEFINE_WRAPPER(sigtimedwait);
DEFINE_WRAPPER(pthread_create);
DEFINE_WRAPPER(pthread_exit);
DEFINE_WRAPPER(pthread_join);
DEFINE_WRAPPER(pthread_tryjoin_np);
DEFINE_WRAPPER(pthread_timedjoin_np);
DEFINE_WRAPPER(pthread_sigmask);
DEFINE_WRAPPER(pthread_kill);
DEFINE_WRAPPER(pthread_sigqueue);
DEFINE_WRAPPER(pthread_mutex_lock);
DEFINE_WRAPPER(pthread_mutex_trylock);
DEFINE_WRAPPER(pthread_mutex_unlock);
DEFINE_WRAPPER(pthread_cond_wait);
DEFINE_WRAPPER(pthread_cond_timedwait);
DEFINE_WRAPPER(pthread_cond_signal);
DEFINE_WRAPPER(pthread_cond_broadcast);
DEFINE_WRAPPER(pthread_barrier_wait);
DEFINE_WRAPPER(pthread_rwlock_rdlock);
DEFINE_WRAPPER(pthread_rwlock_tryrdlock);
DEFINE_WRAPPER(pthread_rwlock_timedrdlock);
DEFINE_WRAPPER(pthread_rwlock_wrlock);
DEFINE_WRAPPER(pthread_rwlock_trywrlock);
DEFINE_WRAPPER(pthread_rwlock_timedwrlock);
DEFINE_WRAPPER(pthread_rwlock_unlock);
}
|