Home | History | Annotate | Download | only in tsan
      1 /* Copyright (c) 2008-2010, Google Inc.
      2  * All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Neither the name of Google Inc. nor the names of its
     11  * contributors may be used to endorse or promote products derived from
     12  * this software without specific prior written permission.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 // This file is part of ThreadSanitizer, a dynamic data race detector.
     28 // Author: Konstantin Serebryany.
     29 // Author: Timur Iskhodzhanov.
     30 
     31 // This file contains utility classes and functions used by ThreadSanitizer.
     32 // TODO(kcc): move more utilities from thread_sanitizer.cc to this file.
     33 
     34 #ifndef TS_UTIL_H_
     35 #define TS_UTIL_H_
     36 
     37 //--------- Head ------------------- {{{1
     38 #if defined(TS_VALGRIND)
     39 # define CHECK tl_assert
     40 #elif defined(TS_PIN)
     41 extern void Printf(const char *format, ...);
     42 extern void ThreadSanitizerDumpAllStacks();
     43 # define CHECK(x) do { if (!(x)) { \
     44    Printf("Assertion failed: %s (%s:%d) %s\n", \
     45           __FUNCTION__, __FILE__, __LINE__, #x); \
     46    ThreadSanitizerDumpAllStacks(); \
     47    exit(1); }} while (0)
     48 #elif defined(TS_OFFLINE)
     49 extern unsigned long offline_line_n;
     50 # define CHECK(x) do { if (!(x)) { \
     51     Printf("ASSERT on line %ld\n", offline_line_n); \
     52      assert(x);}} while (0)
     53 #else
     54 # define CHECK assert
     55 #endif
     56 
     57 #if defined(TS_VALGRIND)
     58 # include "ts_valgrind.h"
     59 # define TS_USE_STLPORT
     60 #if defined(VGP_arm_linux)
     61 // This macro is explicitly undefined in glibc for ARM.
     62 #define _GLIBCXX_USE_C99 1
     63 #endif  // ARM
     64 
     65 // __WORDSIZE is GLibC-specific. Get it from Valgrind if needed.
     66 #if !defined(__WORDSIZE)
     67 #if VG_WORDSIZE == 4
     68 #define __WORDSIZE 32
     69 #elif VG_WORDSIZE == 8
     70 #define __WORDSIZE 64
     71 #endif // VG_WORDSIZE
     72 #endif // TS_VALGRIND && !__WORDSIZE
     73 
     74 #elif defined(TS_LLVM)
     75 # define TS_USE_STLPORT
     76 # include <assert.h>
     77 # include <fcntl.h>
     78 # include <time.h>
     79 
     80 #elif defined(__GNUC__)
     81 # undef NDEBUG  // Assert is always on.
     82 # include <assert.h>
     83 # include <sys/types.h>
     84 # include <sys/stat.h>
     85 # include <fcntl.h>
     86 # define TS_USE_GNUC_STL
     87 
     88 #elif defined(_MSC_VER)
     89 # undef NDEBUG  // Assert is always on.
     90 # include <assert.h>
     91 # include <stdio.h>
     92 # include <intrin.h>
     93 # define TS_USE_WIN_STL
     94 
     95 #else
     96 # error "Unknown configuration"
     97 #endif
     98 
     99 //--------- STL ------------------- {{{1
    100 #if defined(TS_USE_GNUC_STL)  // ----------- g++ STL -----------
    101 #include <string.h>
    102 #include <limits.h>
    103 #include <set>
    104 #include <map>
    105 #include <vector>
    106 #include <deque>
    107 #include <stack>
    108 #include <algorithm>
    109 #include <string>
    110 #include <bitset>
    111 #include "ext/algorithm"
    112 
    113 #ifdef __APPLE__
    114 // Apple's unordered_map in gcc 4.0 does not support -fno-exceptions.
    115 #include "ext/hash_map"
    116 #include "ext/hash_set"
    117 #define unordered_map __gnu_cxx::hash_map
    118 #define unordered_set __gnu_cxx::hash_set
    119 #else
    120 #include "tr1/unordered_map"
    121 #include "tr1/unordered_set"
    122 using std::tr1::unordered_map;
    123 using std::tr1::unordered_set;
    124 #endif
    125 
    126 #elif defined(TS_USE_STLPORT)  // ------------- STLport ----------
    127 #include "set"
    128 #include "map"
    129 #include "hash_map"
    130 #include "hash_set"
    131 #include "vector"
    132 #include "deque"
    133 #include "stack"
    134 #include "algorithm"
    135 #include "string"
    136 #include "bitset"
    137 #include "algorithm"
    138 
    139 #include "unordered_map"
    140 #include "unordered_set"
    141 using std::tr1::unordered_map;
    142 using std::tr1::unordered_set;
    143 
    144 #elif defined(TS_USE_WIN_STL)  // ------------- MSVC STL ---------
    145 #include <string.h>
    146 #include <limits.h>
    147 #include <set>
    148 #include <map>
    149 #include <vector>
    150 #include <deque>
    151 #include <stack>
    152 #include <algorithm>
    153 #include <string>
    154 #include <bitset>
    155 
    156 // No such thing in VC 2005
    157 //#include <unordered_map>
    158 //#include <unordered_set>
    159 //using std::tr1::unordered_map;
    160 //using std::tr1::unordered_set;
    161 #include <hash_map>
    162 #include <hash_set>
    163 #define unordered_map stdext::hash_map
    164 #define unordered_set stdext::hash_set
    165 
    166 #else
    167 # error "Unknown STL"
    168 #endif  // TS_USE_STANDARD_STL
    169 
    170 using std::set;
    171 using std::multiset;
    172 using std::multimap;
    173 using std::map;
    174 using std::deque;
    175 using std::stack;
    176 using std::string;
    177 using std::vector;
    178 using std::bitset;
    179 
    180 using std::min;
    181 using std::max;
    182 using std::sort;
    183 using std::pair;
    184 using std::make_pair;
    185 using std::unique_copy;
    186 
    187 #ifdef TS_LLVM
    188 # include "tsan_rtl_wrap.h"
    189 #endif
    190 
    191 //--------- defines ------------------- {{{1
    192 #ifdef TS_VALGRIND
    193 // TODO(kcc) get rid of these macros.
    194 #define sprintf(arg1, arg2...) VG_(sprintf)((Char*)arg1, (HChar*)arg2)
    195 #define vsnprintf(a1, a2, a3, a4) VG_(vsnprintf)((Char*)a1, a2, a3, a4)
    196 #define getpid VG_(getpid)
    197 #define strchr(a,b)    VG_(strchr)((Char*)a,b)
    198 #define strdup(a) (char*)VG_(strdup)((HChar*)"strdup", (const Char*)a)
    199 #define snprintf(a,b,c...)     VG_(snprintf)((Char*)a,b,c)
    200 #define read VG_(read)
    201 #define getenv(x) VG_(getenv)((Char*)x)
    202 #define close VG_(close)
    203 #define write VG_(write)
    204 #define usleep(a) /*nothing. TODO.*/
    205 
    206 #elif defined(__GNUC__)
    207 #include <unistd.h>
    208 #include <stdint.h>
    209 #include <stdio.h>
    210 
    211 #define UNLIKELY(x) __builtin_expect((x), 0)
    212 #define LIKELY(x)   __builtin_expect(!!(x), 1)
    213 
    214 #elif defined(_MSC_VER)
    215 typedef __int8 int8_t;
    216 typedef __int16 int16_t;
    217 typedef __int32 int32_t;
    218 typedef __int64 int64_t;
    219 typedef unsigned __int8 uint8_t;
    220 typedef unsigned __int16 uint16_t;
    221 typedef unsigned __int32 uint32_t;
    222 typedef unsigned __int64 uint64_t;
    223 
    224 typedef int pthread_t;
    225 int getpid();
    226 #define snprintf _snprintf
    227 #define strtoll strtol  // TODO(kcc): _MSC_VER hmm...
    228 #define UNLIKELY(x) (x)  // TODO(kcc): how to say this in MSVC?
    229 #define LIKELY(x)   (x)
    230 
    231 #else
    232 # error "Unknown configuration"
    233 #endif // TS_VALGRIND
    234 
    235 #define CHECK_GT(X, Y) CHECK((X) >  (Y))
    236 #define CHECK_LT(X, Y) CHECK((X) < (Y))
    237 #define CHECK_GE(X, Y) CHECK((X) >= (Y))
    238 #define CHECK_LE(X, Y) CHECK((X) <= (Y))
    239 #define CHECK_NE(X, Y) CHECK((X) != (Y))
    240 #define CHECK_EQ(X, Y) CHECK((X) == (Y))
    241 
    242 #if defined(DEBUG) && DEBUG >= 1
    243   #define DCHECK(a) CHECK(a)
    244   #define DEBUG_MODE (1)
    245 #else
    246   #define DCHECK(a) do { if (0) { if (a) {} } } while(0)
    247   #define DEBUG_MODE (0)
    248 #endif
    249 
    250 #if defined (__GNUC__)
    251   #define ALWAYS_INLINE  inline __attribute__ ((always_inline))
    252 #elif defined(_MSC_VER)
    253   #define ALWAYS_INLINE __forceinline
    254 #else
    255   #error "Unknown Configuration"
    256 #endif
    257 
    258 #if defined(DEBUG) && DEBUG >= 1
    259   #define INLINE
    260   #define NOINLINE
    261 #elif defined (__GNUC__)
    262   #define INLINE  ALWAYS_INLINE
    263   #define NOINLINE __attribute__ ((noinline))
    264 #elif defined(_MSC_VER)
    265   #define INLINE ALWAYS_INLINE
    266   #define NOINLINE __declspec(noinline)
    267 #else
    268   #error "Unknown Configuration"
    269 #endif
    270 
    271 // When TS_SERIALIZED==1, all calls to ThreadSanitizer* functions
    272 // should be serialized somehow. For example:
    273 //  - Valgrind serializes threads by using a pipe-based semaphore.
    274 //  - ThreadSanitizerOffline is single-threaded by nature.
    275 //  - A Multi-threaded environment (e.g. PIN) can use a single global Mutex.
    276 // When TS_SERIALIZED==0, ThreadSanitizer takes care of synchronization itself.
    277 
    278 #if defined(TS_SERIALIZED)
    279  // someone defined this already, leave it as is.
    280 #elif defined(TS_PIN)
    281 # define TS_SERIALIZED 1
    282 #elif defined(TS_LLVM)
    283 # define TS_SERIALIZED 0
    284 #else
    285 # define TS_SERIALIZED 1
    286 #endif
    287 
    288 
    289 #define TS_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
    290 
    291 //--------- Malloc profiling ------------------- {{{1
    292 class MallocCostCenterStack {
    293  public:
    294   void Push(const char *cc) {
    295     malloc_cost_centers_[size_++] = cc;
    296   }
    297   void Pop() {
    298     size_--;
    299   }
    300   const char *Top() {
    301     return size_ ? malloc_cost_centers_[size_ - 1] : "default_cc";
    302   }
    303  private:
    304   enum { kMaxMallocStackSize = 100 };
    305   int size_;
    306   const char *malloc_cost_centers_[kMaxMallocStackSize];
    307 };
    308 
    309 // Not thread-safe. Need to make it thread-local if we allow
    310 // malloc to be called concurrently.
    311 extern MallocCostCenterStack g_malloc_stack;
    312 
    313 class ScopedMallocCostCenter {
    314  public:
    315   ScopedMallocCostCenter(const char *cc) {
    316 #if defined(TS_VALGRIND)
    317     g_malloc_stack.Push(cc);
    318 #endif
    319   }
    320   ~ScopedMallocCostCenter() {
    321 #if defined(TS_VALGRIND)
    322     g_malloc_stack.Pop();
    323 #endif
    324   }
    325 };
    326 
    327 //--------- Forward decls ------------------- {{{1
    328 class ThreadSanitizerReport;
    329 
    330 // Time since some moment before the program start.
    331 extern size_t TimeInMilliSeconds();
    332 extern void YIELD();
    333 
    334 extern "C" long my_strtol(const char *str, char **end, int base);
    335 extern void Printf(const char *format, ...);
    336 
    337 // Strip (.*) and <.*>, also handle "function returns a function pointer" case.
    338 string NormalizeFunctionName(const string &mangled_fname);
    339 
    340 string ReadFileToString(const string &file_name, bool die_if_failed);
    341 
    342 // Get the current memory footprint of myself (parse /proc/self/status).
    343 size_t GetVmSizeInMb();
    344 
    345 // Sets the contents of the file 'file_name' to 'str'.
    346 void OpenFileWriteStringAndClose(const string &file_name, const string &str);
    347 
    348 // If host_and_port looks like myhost:12345, open a socket for writing
    349 // and returns a FILE object. Retuns NULL on failure.
    350 FILE *OpenSocketForWriting(const string &host_and_port);
    351 
    352 // If addr is inside a global object, returns true and sets 'name' and 'offset'
    353 bool GetNameAndOffsetOfGlobalObject(uintptr_t addr,
    354                                     string *name, uintptr_t *offset);
    355 
    356 extern uintptr_t GetPcOfCurrentThread();
    357 
    358 extern void GetThreadStack(int tid, uintptr_t *min_addr, uintptr_t *max_addr);
    359 
    360 extern void SetNumberOfFoundErrors(int n_errs);
    361 extern int GetNumberOfFoundErrors();
    362 
    363 bool LiteRaceSkipTrace(int tid, uint32_t trace_no, uint32_t sampling_rate);
    364 
    365 
    366 inline uintptr_t tsan_bswap(uintptr_t x) {
    367 #if defined(VGP_arm_linux) && __WORDSIZE == 64
    368   return __builtin_bswap64(x);
    369 #elif defined(VGP_arm_linux) && __WORDSIZE == 32
    370   return __builtin_bswap32(x);
    371 #elif defined(__GNUC__) && __WORDSIZE == 64
    372   __asm__("bswapq %0" : "=r" (x) : "0" (x));
    373   return x;
    374 #elif defined(__GNUC__) && __WORDSIZE == 32
    375   __asm__("bswapl %0" : "=r" (x) : "0" (x));
    376   return x;
    377 #elif defined(_WIN32)
    378   return x;  // TODO(kcc)
    379 #else
    380 # error  "Unknown Configuration"
    381 #endif // arch && VG_WORDSIZE
    382 }
    383 
    384 #ifdef _MSC_VER
    385 inline unsigned u32_log2(unsigned x) {
    386   unsigned long y;
    387   _BitScanReverse(&y, x);
    388   return y;
    389 }
    390 #endif
    391 
    392 #ifdef __GNUC__
    393 inline unsigned u32_log2(unsigned x) {
    394   return 31 - __builtin_clz(x);
    395 }
    396 #endif
    397 
    398 
    399 
    400 #endif  // TS_UTIL_H_
    401 // end. {{{1
    402 // vim:shiftwidth=2:softtabstop=2:expandtab:tw=80
    403