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:
Push(const char * cc)294 void Push(const char *cc) {
295 malloc_cost_centers_[size_++] = cc;
296 }
Pop()297 void Pop() {
298 size_--;
299 }
Top()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:
ScopedMallocCostCenter(const char * cc)315 ScopedMallocCostCenter(const char *cc) {
316 #if defined(TS_VALGRIND)
317 g_malloc_stack.Push(cc);
318 #endif
319 }
~ScopedMallocCostCenter()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
tsan_bswap(uintptr_t x)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
u32_log2(unsigned x)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__
u32_log2(unsigned x)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