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