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) 41extern void Printf(const char *format, ...); 42extern 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) 49extern 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" 122using std::tr1::unordered_map; 123using 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" 141using std::tr1::unordered_map; 142using 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 170using std::set; 171using std::multiset; 172using std::multimap; 173using std::map; 174using std::deque; 175using std::stack; 176using std::string; 177using std::vector; 178using std::bitset; 179 180using std::min; 181using std::max; 182using std::sort; 183using std::pair; 184using std::make_pair; 185using 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) 215typedef __int8 int8_t; 216typedef __int16 int16_t; 217typedef __int32 int32_t; 218typedef __int64 int64_t; 219typedef unsigned __int8 uint8_t; 220typedef unsigned __int16 uint16_t; 221typedef unsigned __int32 uint32_t; 222typedef unsigned __int64 uint64_t; 223 224typedef int pthread_t; 225int 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 292class 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. 311extern MallocCostCenterStack g_malloc_stack; 312 313class 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 328class ThreadSanitizerReport; 329 330// Time since some moment before the program start. 331extern size_t TimeInMilliSeconds(); 332extern void YIELD(); 333 334extern "C" long my_strtol(const char *str, char **end, int base); 335extern void Printf(const char *format, ...); 336 337// Strip (.*) and <.*>, also handle "function returns a function pointer" case. 338string NormalizeFunctionName(const string &mangled_fname); 339 340string ReadFileToString(const string &file_name, bool die_if_failed); 341 342// Get the current memory footprint of myself (parse /proc/self/status). 343size_t GetVmSizeInMb(); 344 345// Sets the contents of the file 'file_name' to 'str'. 346void 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. 350FILE *OpenSocketForWriting(const string &host_and_port); 351 352// If addr is inside a global object, returns true and sets 'name' and 'offset' 353bool GetNameAndOffsetOfGlobalObject(uintptr_t addr, 354 string *name, uintptr_t *offset); 355 356extern uintptr_t GetPcOfCurrentThread(); 357 358extern void GetThreadStack(int tid, uintptr_t *min_addr, uintptr_t *max_addr); 359 360extern void SetNumberOfFoundErrors(int n_errs); 361extern int GetNumberOfFoundErrors(); 362 363bool LiteRaceSkipTrace(int tid, uint32_t trace_no, uint32_t sampling_rate); 364 365 366inline 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 385inline unsigned u32_log2(unsigned x) { 386 unsigned long y; 387 _BitScanReverse(&y, x); 388 return y; 389} 390#endif 391 392#ifdef __GNUC__ 393inline 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