1//===-- dd_interceptors.cc ------------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "dd_rtl.h" 11#include "interception/interception.h" 12#include "sanitizer_common/sanitizer_procmaps.h" 13#include <pthread.h> 14#include <stdlib.h> 15 16using namespace __dsan; 17 18extern "C" void *__libc_malloc(uptr size); 19extern "C" void __libc_free(void *ptr); 20 21__attribute__((tls_model("initial-exec"))) 22static __thread Thread *thr; 23__attribute__((tls_model("initial-exec"))) 24static __thread volatile int initing; 25static bool inited; 26static uptr g_data_start; 27static uptr g_data_end; 28 29static bool InitThread() { 30 if (initing) 31 return false; 32 if (thr != 0) 33 return true; 34 initing = true; 35 if (!inited) { 36 inited = true; 37 Initialize(); 38 } 39 thr = (Thread*)InternalAlloc(sizeof(*thr)); 40 internal_memset(thr, 0, sizeof(*thr)); 41 ThreadInit(thr); 42 initing = false; 43 return true; 44} 45 46INTERCEPTOR(int, pthread_mutex_destroy, pthread_mutex_t *m) { 47 InitThread(); 48 MutexDestroy(thr, (uptr)m); 49 return REAL(pthread_mutex_destroy)(m); 50} 51 52INTERCEPTOR(int, pthread_mutex_lock, pthread_mutex_t *m) { 53 InitThread(); 54 MutexBeforeLock(thr, (uptr)m, true); 55 int res = REAL(pthread_mutex_lock)(m); 56 MutexAfterLock(thr, (uptr)m, true, false); 57 return res; 58} 59 60INTERCEPTOR(int, pthread_mutex_trylock, pthread_mutex_t *m) { 61 InitThread(); 62 int res = REAL(pthread_mutex_trylock)(m); 63 if (res == 0) 64 MutexAfterLock(thr, (uptr)m, true, true); 65 return res; 66} 67 68INTERCEPTOR(int, pthread_mutex_unlock, pthread_mutex_t *m) { 69 InitThread(); 70 MutexBeforeUnlock(thr, (uptr)m, true); 71 return REAL(pthread_mutex_unlock)(m); 72} 73 74INTERCEPTOR(int, pthread_spin_destroy, pthread_spinlock_t *m) { 75 InitThread(); 76 int res = REAL(pthread_spin_destroy)(m); 77 MutexDestroy(thr, (uptr)m); 78 return res; 79} 80 81INTERCEPTOR(int, pthread_spin_lock, pthread_spinlock_t *m) { 82 InitThread(); 83 MutexBeforeLock(thr, (uptr)m, true); 84 int res = REAL(pthread_spin_lock)(m); 85 MutexAfterLock(thr, (uptr)m, true, false); 86 return res; 87} 88 89INTERCEPTOR(int, pthread_spin_trylock, pthread_spinlock_t *m) { 90 InitThread(); 91 int res = REAL(pthread_spin_trylock)(m); 92 if (res == 0) 93 MutexAfterLock(thr, (uptr)m, true, true); 94 return res; 95} 96 97INTERCEPTOR(int, pthread_spin_unlock, pthread_spinlock_t *m) { 98 InitThread(); 99 MutexBeforeUnlock(thr, (uptr)m, true); 100 return REAL(pthread_spin_unlock)(m); 101} 102 103INTERCEPTOR(int, pthread_rwlock_destroy, pthread_rwlock_t *m) { 104 InitThread(); 105 MutexDestroy(thr, (uptr)m); 106 return REAL(pthread_rwlock_destroy)(m); 107} 108 109INTERCEPTOR(int, pthread_rwlock_rdlock, pthread_rwlock_t *m) { 110 InitThread(); 111 MutexBeforeLock(thr, (uptr)m, false); 112 int res = REAL(pthread_rwlock_rdlock)(m); 113 MutexAfterLock(thr, (uptr)m, false, false); 114 return res; 115} 116 117INTERCEPTOR(int, pthread_rwlock_tryrdlock, pthread_rwlock_t *m) { 118 InitThread(); 119 int res = REAL(pthread_rwlock_tryrdlock)(m); 120 if (res == 0) 121 MutexAfterLock(thr, (uptr)m, false, true); 122 return res; 123} 124 125INTERCEPTOR(int, pthread_rwlock_timedrdlock, pthread_rwlock_t *m, 126 const timespec *abstime) { 127 InitThread(); 128 int res = REAL(pthread_rwlock_timedrdlock)(m, abstime); 129 if (res == 0) 130 MutexAfterLock(thr, (uptr)m, false, true); 131 return res; 132} 133 134INTERCEPTOR(int, pthread_rwlock_wrlock, pthread_rwlock_t *m) { 135 InitThread(); 136 MutexBeforeLock(thr, (uptr)m, true); 137 int res = REAL(pthread_rwlock_wrlock)(m); 138 MutexAfterLock(thr, (uptr)m, true, false); 139 return res; 140} 141 142INTERCEPTOR(int, pthread_rwlock_trywrlock, pthread_rwlock_t *m) { 143 InitThread(); 144 int res = REAL(pthread_rwlock_trywrlock)(m); 145 if (res == 0) 146 MutexAfterLock(thr, (uptr)m, true, true); 147 return res; 148} 149 150INTERCEPTOR(int, pthread_rwlock_timedwrlock, pthread_rwlock_t *m, 151 const timespec *abstime) { 152 InitThread(); 153 int res = REAL(pthread_rwlock_timedwrlock)(m, abstime); 154 if (res == 0) 155 MutexAfterLock(thr, (uptr)m, true, true); 156 return res; 157} 158 159INTERCEPTOR(int, pthread_rwlock_unlock, pthread_rwlock_t *m) { 160 InitThread(); 161 MutexBeforeUnlock(thr, (uptr)m, true); // note: not necessary write unlock 162 return REAL(pthread_rwlock_unlock)(m); 163} 164 165static pthread_cond_t *init_cond(pthread_cond_t *c, bool force = false) { 166 atomic_uintptr_t *p = (atomic_uintptr_t*)c; 167 uptr cond = atomic_load(p, memory_order_acquire); 168 if (!force && cond != 0) 169 return (pthread_cond_t*)cond; 170 void *newcond = malloc(sizeof(pthread_cond_t)); 171 internal_memset(newcond, 0, sizeof(pthread_cond_t)); 172 if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond, 173 memory_order_acq_rel)) 174 return (pthread_cond_t*)newcond; 175 free(newcond); 176 return (pthread_cond_t*)cond; 177} 178 179INTERCEPTOR(int, pthread_cond_init, pthread_cond_t *c, 180 const pthread_condattr_t *a) { 181 InitThread(); 182 pthread_cond_t *cond = init_cond(c, true); 183 return REAL(pthread_cond_init)(cond, a); 184} 185 186INTERCEPTOR(int, pthread_cond_wait, pthread_cond_t *c, pthread_mutex_t *m) { 187 InitThread(); 188 pthread_cond_t *cond = init_cond(c); 189 MutexBeforeUnlock(thr, (uptr)m, true); 190 MutexBeforeLock(thr, (uptr)m, true); 191 int res = REAL(pthread_cond_wait)(cond, m); 192 MutexAfterLock(thr, (uptr)m, true, false); 193 return res; 194} 195 196INTERCEPTOR(int, pthread_cond_timedwait, pthread_cond_t *c, pthread_mutex_t *m, 197 const timespec *abstime) { 198 InitThread(); 199 pthread_cond_t *cond = init_cond(c); 200 MutexBeforeUnlock(thr, (uptr)m, true); 201 MutexBeforeLock(thr, (uptr)m, true); 202 int res = REAL(pthread_cond_timedwait)(cond, m, abstime); 203 MutexAfterLock(thr, (uptr)m, true, false); 204 return res; 205} 206 207INTERCEPTOR(int, pthread_cond_signal, pthread_cond_t *c) { 208 InitThread(); 209 pthread_cond_t *cond = init_cond(c); 210 return REAL(pthread_cond_signal)(cond); 211} 212 213INTERCEPTOR(int, pthread_cond_broadcast, pthread_cond_t *c) { 214 InitThread(); 215 pthread_cond_t *cond = init_cond(c); 216 return REAL(pthread_cond_broadcast)(cond); 217} 218 219INTERCEPTOR(int, pthread_cond_destroy, pthread_cond_t *c) { 220 InitThread(); 221 pthread_cond_t *cond = init_cond(c); 222 int res = REAL(pthread_cond_destroy)(cond); 223 free(cond); 224 atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed); 225 return res; 226} 227 228// for symbolizer 229INTERCEPTOR(char*, realpath, const char *path, char *resolved_path) { 230 InitThread(); 231 return REAL(realpath)(path, resolved_path); 232} 233 234INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) { 235 InitThread(); 236 return REAL(read)(fd, ptr, count); 237} 238 239INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) { 240 InitThread(); 241 return REAL(pread)(fd, ptr, count, offset); 242} 243 244extern "C" { 245void __dsan_before_mutex_lock(uptr m, int writelock) { 246 if (!InitThread()) 247 return; 248 MutexBeforeLock(thr, m, writelock); 249} 250 251void __dsan_after_mutex_lock(uptr m, int writelock, int trylock) { 252 if (!InitThread()) 253 return; 254 MutexAfterLock(thr, m, writelock, trylock); 255} 256 257void __dsan_before_mutex_unlock(uptr m, int writelock) { 258 if (!InitThread()) 259 return; 260 MutexBeforeUnlock(thr, m, writelock); 261} 262 263void __dsan_mutex_destroy(uptr m) { 264 if (!InitThread()) 265 return; 266 // if (m >= g_data_start && m < g_data_end) 267 // return; 268 MutexDestroy(thr, m); 269} 270} // extern "C" 271 272namespace __dsan { 273 274static void InitDataSeg() { 275 MemoryMappingLayout proc_maps(true); 276 uptr start, end, offset; 277 char name[128]; 278 bool prev_is_data = false; 279 while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), 280 /*protection*/ 0)) { 281 bool is_data = offset != 0 && name[0] != 0; 282 // BSS may get merged with [heap] in /proc/self/maps. This is not very 283 // reliable. 284 bool is_bss = offset == 0 && 285 (name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data; 286 if (g_data_start == 0 && is_data) 287 g_data_start = start; 288 if (is_bss) 289 g_data_end = end; 290 prev_is_data = is_data; 291 } 292 VPrintf(1, "guessed data_start=%p data_end=%p\n", g_data_start, g_data_end); 293 CHECK_LT(g_data_start, g_data_end); 294 CHECK_GE((uptr)&g_data_start, g_data_start); 295 CHECK_LT((uptr)&g_data_start, g_data_end); 296} 297 298void InitializeInterceptors() { 299 INTERCEPT_FUNCTION(pthread_mutex_destroy); 300 INTERCEPT_FUNCTION(pthread_mutex_lock); 301 INTERCEPT_FUNCTION(pthread_mutex_trylock); 302 INTERCEPT_FUNCTION(pthread_mutex_unlock); 303 304 INTERCEPT_FUNCTION(pthread_spin_destroy); 305 INTERCEPT_FUNCTION(pthread_spin_lock); 306 INTERCEPT_FUNCTION(pthread_spin_trylock); 307 INTERCEPT_FUNCTION(pthread_spin_unlock); 308 309 INTERCEPT_FUNCTION(pthread_rwlock_destroy); 310 INTERCEPT_FUNCTION(pthread_rwlock_rdlock); 311 INTERCEPT_FUNCTION(pthread_rwlock_tryrdlock); 312 INTERCEPT_FUNCTION(pthread_rwlock_timedrdlock); 313 INTERCEPT_FUNCTION(pthread_rwlock_wrlock); 314 INTERCEPT_FUNCTION(pthread_rwlock_trywrlock); 315 INTERCEPT_FUNCTION(pthread_rwlock_timedwrlock); 316 INTERCEPT_FUNCTION(pthread_rwlock_unlock); 317 318 INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2"); 319 INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2"); 320 INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2"); 321 INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2"); 322 INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, "GLIBC_2.3.2"); 323 INTERCEPT_FUNCTION_VER(pthread_cond_destroy, "GLIBC_2.3.2"); 324 325 // for symbolizer 326 INTERCEPT_FUNCTION(realpath); 327 INTERCEPT_FUNCTION(read); 328 INTERCEPT_FUNCTION(pread); 329 330 InitDataSeg(); 331} 332 333} // namespace __dsan 334