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 extern "C" void *__libc_malloc(uptr size);
     19 extern "C" void __libc_free(void *ptr);
     20 
     21 __attribute__((tls_model("initial-exec")))
     22 static __thread Thread *thr;
     23 __attribute__((tls_model("initial-exec")))
     24 static __thread volatile int initing;
     25 static bool inited;
     26 static uptr g_data_start;
     27 static uptr g_data_end;
     28 
     29 static 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 
     46 INTERCEPTOR(int, pthread_mutex_destroy, pthread_mutex_t *m) {
     47   InitThread();
     48   MutexDestroy(thr, (uptr)m);
     49   return REAL(pthread_mutex_destroy)(m);
     50 }
     51 
     52 INTERCEPTOR(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 
     60 INTERCEPTOR(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 
     68 INTERCEPTOR(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 
     74 INTERCEPTOR(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 
     81 INTERCEPTOR(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 
     89 INTERCEPTOR(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 
     97 INTERCEPTOR(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 
    103 INTERCEPTOR(int, pthread_rwlock_destroy, pthread_rwlock_t *m) {
    104   InitThread();
    105   MutexDestroy(thr, (uptr)m);
    106   return REAL(pthread_rwlock_destroy)(m);
    107 }
    108 
    109 INTERCEPTOR(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 
    117 INTERCEPTOR(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 
    125 INTERCEPTOR(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 
    134 INTERCEPTOR(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 
    142 INTERCEPTOR(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 
    150 INTERCEPTOR(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 
    159 INTERCEPTOR(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 
    165 static 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 
    179 INTERCEPTOR(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 
    186 INTERCEPTOR(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 
    196 INTERCEPTOR(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 
    207 INTERCEPTOR(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 
    213 INTERCEPTOR(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 
    219 INTERCEPTOR(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
    229 INTERCEPTOR(char*, realpath, const char *path, char *resolved_path) {
    230   InitThread();
    231   return REAL(realpath)(path, resolved_path);
    232 }
    233 
    234 INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
    235   InitThread();
    236   return REAL(read)(fd, ptr, count);
    237 }
    238 
    239 INTERCEPTOR(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 
    244 extern "C" {
    245 void __dsan_before_mutex_lock(uptr m, int writelock) {
    246   if (!InitThread())
    247     return;
    248   MutexBeforeLock(thr, m, writelock);
    249 }
    250 
    251 void __dsan_after_mutex_lock(uptr m, int writelock, int trylock) {
    252   if (!InitThread())
    253     return;
    254   MutexAfterLock(thr, m, writelock, trylock);
    255 }
    256 
    257 void __dsan_before_mutex_unlock(uptr m, int writelock) {
    258   if (!InitThread())
    259     return;
    260   MutexBeforeUnlock(thr, m, writelock);
    261 }
    262 
    263 void __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 
    272 namespace __dsan {
    273 
    274 static 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 
    298 void 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