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