1353944Sdim//===-- dd_interceptors.cpp -----------------------------------------------===// 2353944Sdim// 3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353944Sdim// See https://llvm.org/LICENSE.txt for license information. 5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353944Sdim// 7353944Sdim//===----------------------------------------------------------------------===// 8353944Sdim 9353944Sdim#include "dd_rtl.h" 10353944Sdim#include "interception/interception.h" 11353944Sdim#include "sanitizer_common/sanitizer_procmaps.h" 12353944Sdim#include <pthread.h> 13353944Sdim#include <stdlib.h> 14353944Sdim 15353944Sdimusing namespace __dsan; 16353944Sdim 17353944Sdim__attribute__((tls_model("initial-exec"))) 18353944Sdimstatic __thread Thread *thr; 19353944Sdim__attribute__((tls_model("initial-exec"))) 20353944Sdimstatic __thread volatile int initing; 21353944Sdimstatic bool inited; 22353944Sdimstatic uptr g_data_start; 23353944Sdimstatic uptr g_data_end; 24353944Sdim 25353944Sdimstatic bool InitThread() { 26353944Sdim if (initing) 27353944Sdim return false; 28353944Sdim if (thr != 0) 29353944Sdim return true; 30353944Sdim initing = true; 31353944Sdim if (!inited) { 32353944Sdim inited = true; 33353944Sdim Initialize(); 34353944Sdim } 35353944Sdim thr = (Thread*)InternalAlloc(sizeof(*thr)); 36353944Sdim internal_memset(thr, 0, sizeof(*thr)); 37353944Sdim ThreadInit(thr); 38353944Sdim initing = false; 39353944Sdim return true; 40353944Sdim} 41353944Sdim 42353944SdimINTERCEPTOR(int, pthread_mutex_destroy, pthread_mutex_t *m) { 43353944Sdim InitThread(); 44353944Sdim MutexDestroy(thr, (uptr)m); 45353944Sdim return REAL(pthread_mutex_destroy)(m); 46353944Sdim} 47353944Sdim 48353944SdimINTERCEPTOR(int, pthread_mutex_lock, pthread_mutex_t *m) { 49353944Sdim InitThread(); 50353944Sdim MutexBeforeLock(thr, (uptr)m, true); 51353944Sdim int res = REAL(pthread_mutex_lock)(m); 52353944Sdim MutexAfterLock(thr, (uptr)m, true, false); 53353944Sdim return res; 54353944Sdim} 55353944Sdim 56353944SdimINTERCEPTOR(int, pthread_mutex_trylock, pthread_mutex_t *m) { 57353944Sdim InitThread(); 58353944Sdim int res = REAL(pthread_mutex_trylock)(m); 59353944Sdim if (res == 0) 60353944Sdim MutexAfterLock(thr, (uptr)m, true, true); 61353944Sdim return res; 62353944Sdim} 63353944Sdim 64353944SdimINTERCEPTOR(int, pthread_mutex_unlock, pthread_mutex_t *m) { 65353944Sdim InitThread(); 66353944Sdim MutexBeforeUnlock(thr, (uptr)m, true); 67353944Sdim return REAL(pthread_mutex_unlock)(m); 68353944Sdim} 69353944Sdim 70353944SdimINTERCEPTOR(int, pthread_spin_destroy, pthread_spinlock_t *m) { 71353944Sdim InitThread(); 72353944Sdim int res = REAL(pthread_spin_destroy)(m); 73353944Sdim MutexDestroy(thr, (uptr)m); 74353944Sdim return res; 75353944Sdim} 76353944Sdim 77353944SdimINTERCEPTOR(int, pthread_spin_lock, pthread_spinlock_t *m) { 78353944Sdim InitThread(); 79353944Sdim MutexBeforeLock(thr, (uptr)m, true); 80353944Sdim int res = REAL(pthread_spin_lock)(m); 81353944Sdim MutexAfterLock(thr, (uptr)m, true, false); 82353944Sdim return res; 83353944Sdim} 84353944Sdim 85353944SdimINTERCEPTOR(int, pthread_spin_trylock, pthread_spinlock_t *m) { 86353944Sdim InitThread(); 87353944Sdim int res = REAL(pthread_spin_trylock)(m); 88353944Sdim if (res == 0) 89353944Sdim MutexAfterLock(thr, (uptr)m, true, true); 90353944Sdim return res; 91353944Sdim} 92353944Sdim 93353944SdimINTERCEPTOR(int, pthread_spin_unlock, pthread_spinlock_t *m) { 94353944Sdim InitThread(); 95353944Sdim MutexBeforeUnlock(thr, (uptr)m, true); 96353944Sdim return REAL(pthread_spin_unlock)(m); 97353944Sdim} 98353944Sdim 99353944SdimINTERCEPTOR(int, pthread_rwlock_destroy, pthread_rwlock_t *m) { 100353944Sdim InitThread(); 101353944Sdim MutexDestroy(thr, (uptr)m); 102353944Sdim return REAL(pthread_rwlock_destroy)(m); 103353944Sdim} 104353944Sdim 105353944SdimINTERCEPTOR(int, pthread_rwlock_rdlock, pthread_rwlock_t *m) { 106353944Sdim InitThread(); 107353944Sdim MutexBeforeLock(thr, (uptr)m, false); 108353944Sdim int res = REAL(pthread_rwlock_rdlock)(m); 109353944Sdim MutexAfterLock(thr, (uptr)m, false, false); 110353944Sdim return res; 111353944Sdim} 112353944Sdim 113353944SdimINTERCEPTOR(int, pthread_rwlock_tryrdlock, pthread_rwlock_t *m) { 114353944Sdim InitThread(); 115353944Sdim int res = REAL(pthread_rwlock_tryrdlock)(m); 116353944Sdim if (res == 0) 117353944Sdim MutexAfterLock(thr, (uptr)m, false, true); 118353944Sdim return res; 119353944Sdim} 120353944Sdim 121353944SdimINTERCEPTOR(int, pthread_rwlock_timedrdlock, pthread_rwlock_t *m, 122353944Sdim const timespec *abstime) { 123353944Sdim InitThread(); 124353944Sdim int res = REAL(pthread_rwlock_timedrdlock)(m, abstime); 125353944Sdim if (res == 0) 126353944Sdim MutexAfterLock(thr, (uptr)m, false, true); 127353944Sdim return res; 128353944Sdim} 129353944Sdim 130353944SdimINTERCEPTOR(int, pthread_rwlock_wrlock, pthread_rwlock_t *m) { 131353944Sdim InitThread(); 132353944Sdim MutexBeforeLock(thr, (uptr)m, true); 133353944Sdim int res = REAL(pthread_rwlock_wrlock)(m); 134353944Sdim MutexAfterLock(thr, (uptr)m, true, false); 135353944Sdim return res; 136353944Sdim} 137353944Sdim 138353944SdimINTERCEPTOR(int, pthread_rwlock_trywrlock, pthread_rwlock_t *m) { 139353944Sdim InitThread(); 140353944Sdim int res = REAL(pthread_rwlock_trywrlock)(m); 141353944Sdim if (res == 0) 142353944Sdim MutexAfterLock(thr, (uptr)m, true, true); 143353944Sdim return res; 144353944Sdim} 145353944Sdim 146353944SdimINTERCEPTOR(int, pthread_rwlock_timedwrlock, pthread_rwlock_t *m, 147353944Sdim const timespec *abstime) { 148353944Sdim InitThread(); 149353944Sdim int res = REAL(pthread_rwlock_timedwrlock)(m, abstime); 150353944Sdim if (res == 0) 151353944Sdim MutexAfterLock(thr, (uptr)m, true, true); 152353944Sdim return res; 153353944Sdim} 154353944Sdim 155353944SdimINTERCEPTOR(int, pthread_rwlock_unlock, pthread_rwlock_t *m) { 156353944Sdim InitThread(); 157353944Sdim MutexBeforeUnlock(thr, (uptr)m, true); // note: not necessary write unlock 158353944Sdim return REAL(pthread_rwlock_unlock)(m); 159353944Sdim} 160353944Sdim 161353944Sdimstatic pthread_cond_t *init_cond(pthread_cond_t *c, bool force = false) { 162353944Sdim atomic_uintptr_t *p = (atomic_uintptr_t*)c; 163353944Sdim uptr cond = atomic_load(p, memory_order_acquire); 164353944Sdim if (!force && cond != 0) 165353944Sdim return (pthread_cond_t*)cond; 166353944Sdim void *newcond = malloc(sizeof(pthread_cond_t)); 167353944Sdim internal_memset(newcond, 0, sizeof(pthread_cond_t)); 168353944Sdim if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond, 169353944Sdim memory_order_acq_rel)) 170353944Sdim return (pthread_cond_t*)newcond; 171353944Sdim free(newcond); 172353944Sdim return (pthread_cond_t*)cond; 173353944Sdim} 174353944Sdim 175353944SdimINTERCEPTOR(int, pthread_cond_init, pthread_cond_t *c, 176353944Sdim const pthread_condattr_t *a) { 177353944Sdim InitThread(); 178353944Sdim pthread_cond_t *cond = init_cond(c, true); 179353944Sdim return REAL(pthread_cond_init)(cond, a); 180353944Sdim} 181353944Sdim 182353944SdimINTERCEPTOR(int, pthread_cond_wait, pthread_cond_t *c, pthread_mutex_t *m) { 183353944Sdim InitThread(); 184353944Sdim pthread_cond_t *cond = init_cond(c); 185353944Sdim MutexBeforeUnlock(thr, (uptr)m, true); 186353944Sdim MutexBeforeLock(thr, (uptr)m, true); 187353944Sdim int res = REAL(pthread_cond_wait)(cond, m); 188353944Sdim MutexAfterLock(thr, (uptr)m, true, false); 189353944Sdim return res; 190353944Sdim} 191353944Sdim 192353944SdimINTERCEPTOR(int, pthread_cond_timedwait, pthread_cond_t *c, pthread_mutex_t *m, 193353944Sdim const timespec *abstime) { 194353944Sdim InitThread(); 195353944Sdim pthread_cond_t *cond = init_cond(c); 196353944Sdim MutexBeforeUnlock(thr, (uptr)m, true); 197353944Sdim MutexBeforeLock(thr, (uptr)m, true); 198353944Sdim int res = REAL(pthread_cond_timedwait)(cond, m, abstime); 199353944Sdim MutexAfterLock(thr, (uptr)m, true, false); 200353944Sdim return res; 201353944Sdim} 202353944Sdim 203353944SdimINTERCEPTOR(int, pthread_cond_signal, pthread_cond_t *c) { 204353944Sdim InitThread(); 205353944Sdim pthread_cond_t *cond = init_cond(c); 206353944Sdim return REAL(pthread_cond_signal)(cond); 207353944Sdim} 208353944Sdim 209353944SdimINTERCEPTOR(int, pthread_cond_broadcast, pthread_cond_t *c) { 210353944Sdim InitThread(); 211353944Sdim pthread_cond_t *cond = init_cond(c); 212353944Sdim return REAL(pthread_cond_broadcast)(cond); 213353944Sdim} 214353944Sdim 215353944SdimINTERCEPTOR(int, pthread_cond_destroy, pthread_cond_t *c) { 216353944Sdim InitThread(); 217353944Sdim pthread_cond_t *cond = init_cond(c); 218353944Sdim int res = REAL(pthread_cond_destroy)(cond); 219353944Sdim free(cond); 220353944Sdim atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed); 221353944Sdim return res; 222353944Sdim} 223353944Sdim 224353944Sdim// for symbolizer 225353944SdimINTERCEPTOR(char*, realpath, const char *path, char *resolved_path) { 226353944Sdim InitThread(); 227353944Sdim return REAL(realpath)(path, resolved_path); 228353944Sdim} 229353944Sdim 230353944SdimINTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) { 231353944Sdim InitThread(); 232353944Sdim return REAL(read)(fd, ptr, count); 233353944Sdim} 234353944Sdim 235353944SdimINTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) { 236353944Sdim InitThread(); 237353944Sdim return REAL(pread)(fd, ptr, count, offset); 238353944Sdim} 239353944Sdim 240353944Sdimextern "C" { 241353944Sdimvoid __dsan_before_mutex_lock(uptr m, int writelock) { 242353944Sdim if (!InitThread()) 243353944Sdim return; 244353944Sdim MutexBeforeLock(thr, m, writelock); 245353944Sdim} 246353944Sdim 247353944Sdimvoid __dsan_after_mutex_lock(uptr m, int writelock, int trylock) { 248353944Sdim if (!InitThread()) 249353944Sdim return; 250353944Sdim MutexAfterLock(thr, m, writelock, trylock); 251353944Sdim} 252353944Sdim 253353944Sdimvoid __dsan_before_mutex_unlock(uptr m, int writelock) { 254353944Sdim if (!InitThread()) 255353944Sdim return; 256353944Sdim MutexBeforeUnlock(thr, m, writelock); 257353944Sdim} 258353944Sdim 259353944Sdimvoid __dsan_mutex_destroy(uptr m) { 260353944Sdim if (!InitThread()) 261353944Sdim return; 262353944Sdim // if (m >= g_data_start && m < g_data_end) 263353944Sdim // return; 264353944Sdim MutexDestroy(thr, m); 265353944Sdim} 266353944Sdim} // extern "C" 267353944Sdim 268353944Sdimnamespace __dsan { 269353944Sdim 270353944Sdimstatic void InitDataSeg() { 271353944Sdim MemoryMappingLayout proc_maps(true); 272353944Sdim char name[128]; 273353944Sdim MemoryMappedSegment segment(name, ARRAY_SIZE(name)); 274353944Sdim bool prev_is_data = false; 275353944Sdim while (proc_maps.Next(&segment)) { 276353944Sdim bool is_data = segment.offset != 0 && segment.filename[0] != 0; 277353944Sdim // BSS may get merged with [heap] in /proc/self/maps. This is not very 278353944Sdim // reliable. 279353944Sdim bool is_bss = segment.offset == 0 && 280353944Sdim (segment.filename[0] == 0 || 281353944Sdim internal_strcmp(segment.filename, "[heap]") == 0) && 282353944Sdim prev_is_data; 283353944Sdim if (g_data_start == 0 && is_data) g_data_start = segment.start; 284353944Sdim if (is_bss) g_data_end = segment.end; 285353944Sdim prev_is_data = is_data; 286353944Sdim } 287353944Sdim VPrintf(1, "guessed data_start=%p data_end=%p\n", g_data_start, g_data_end); 288353944Sdim CHECK_LT(g_data_start, g_data_end); 289353944Sdim CHECK_GE((uptr)&g_data_start, g_data_start); 290353944Sdim CHECK_LT((uptr)&g_data_start, g_data_end); 291353944Sdim} 292353944Sdim 293353944Sdimvoid InitializeInterceptors() { 294353944Sdim INTERCEPT_FUNCTION(pthread_mutex_destroy); 295353944Sdim INTERCEPT_FUNCTION(pthread_mutex_lock); 296353944Sdim INTERCEPT_FUNCTION(pthread_mutex_trylock); 297353944Sdim INTERCEPT_FUNCTION(pthread_mutex_unlock); 298353944Sdim 299353944Sdim INTERCEPT_FUNCTION(pthread_spin_destroy); 300353944Sdim INTERCEPT_FUNCTION(pthread_spin_lock); 301353944Sdim INTERCEPT_FUNCTION(pthread_spin_trylock); 302353944Sdim INTERCEPT_FUNCTION(pthread_spin_unlock); 303353944Sdim 304353944Sdim INTERCEPT_FUNCTION(pthread_rwlock_destroy); 305353944Sdim INTERCEPT_FUNCTION(pthread_rwlock_rdlock); 306353944Sdim INTERCEPT_FUNCTION(pthread_rwlock_tryrdlock); 307353944Sdim INTERCEPT_FUNCTION(pthread_rwlock_timedrdlock); 308353944Sdim INTERCEPT_FUNCTION(pthread_rwlock_wrlock); 309353944Sdim INTERCEPT_FUNCTION(pthread_rwlock_trywrlock); 310353944Sdim INTERCEPT_FUNCTION(pthread_rwlock_timedwrlock); 311353944Sdim INTERCEPT_FUNCTION(pthread_rwlock_unlock); 312353944Sdim 313353944Sdim INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2"); 314353944Sdim INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2"); 315353944Sdim INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2"); 316353944Sdim INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2"); 317353944Sdim INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, "GLIBC_2.3.2"); 318353944Sdim INTERCEPT_FUNCTION_VER(pthread_cond_destroy, "GLIBC_2.3.2"); 319353944Sdim 320353944Sdim // for symbolizer 321353944Sdim INTERCEPT_FUNCTION(realpath); 322353944Sdim INTERCEPT_FUNCTION(read); 323353944Sdim INTERCEPT_FUNCTION(pread); 324353944Sdim 325353944Sdim InitDataSeg(); 326353944Sdim} 327353944Sdim 328353944Sdim} // namespace __dsan 329