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