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 #define __STDC_LIMIT_MACROS
32 #include "pin.H"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <map>
38 #include <assert.h>
39
40 #include "thread_sanitizer.h"
41 #include "ts_lock.h"
42 #include "ts_trace_info.h"
43 #include "ts_race_verifier.h"
44 #include "common_util.h"
45
46
47 #if defined(__GNUC__)
48 # include <cxxabi.h> // __cxa_demangle
49 # define ATOMIC_READ(a) __sync_add_and_fetch(a, 0)
50
51 #elif defined(_MSC_VER)
52 namespace WINDOWS
53 {
54 // This is the way of including winows.h recommended by PIN docs.
55 #include<Windows.h>
56 }
57
58 #include <intrin.h>
59 # define popen(x,y) (NULL)
60 # define ATOMIC_READ(a) _InterlockedCompareExchange(a, 0, 0)
61 # define usleep(x) WINDOWS::Sleep((x)/1000)
62 # define UINTPTR_MAX ((uintptr_t)-1)
63 #endif
64
65 #ifdef NDEBUG
66 # error "Please don't define NDEBUG"
67 #endif
68
69 static void DumpEvent(CONTEXT *ctx, EventType type, int32_t tid, uintptr_t pc,
70 uintptr_t a, uintptr_t info);
71 //------ Global PIN lock ------- {{{1
72 class ScopedReentrantClientLock {
73 public:
ScopedReentrantClientLock(int line)74 ScopedReentrantClientLock(int line)
75 : line_(line) {
76 // if (line && G_flags->debug_level >= 5) Printf("??Try at line %d\n", line);
77 PIN_LockClient();
78 if (line && G_flags->debug_level >= 5) Printf("++Lock at line %d\n", line);
79 }
~ScopedReentrantClientLock()80 ~ScopedReentrantClientLock() {
81 if (line_ && G_flags->debug_level >= 5) Printf("--Unlock at line %d\n", line_);
82 PIN_UnlockClient();
83 }
84 private:
85 int line_;
86 };
87
88 //--------------- Globals ----------------- {{{1
89 extern FILE *G_out;
90
91 // Number of threads created by pthread_create (i.e. not counting main thread).
92 static int n_created_threads = 0;
93 // Number of started threads, i.e. the number of CallbackForThreadStart calls.
94 static int n_started_threads = 0;
95
96 const uint32_t kMaxThreads = PIN_MAX_THREADS;
97
98 // Serializes the ThreadSanitizer callbacks if TS_SERIALIZED==1
99 static TSLock g_main_ts_lock;
100
101 // Serializes calls to pthread_create and CreateThread.
102 static TSLock g_thread_create_lock;
103 // Under g_thread_create_lock.
104 static THREADID g_tid_of_thread_which_called_create_thread = -1;
105
106 #ifdef _MSC_VER
107 // On Windows, we need to create a h-b arc between
108 // RtlQueueWorkItem(callback, x, y) and the call to callback.
109 // Same for RegisterWaitForSingleObject.
110 static unordered_set<uintptr_t> *g_windows_thread_pool_calback_set;
111 // Similarly, we need h-b arcs between the returns from callbacks and
112 // thre related UnregisterWaitEx. Damn, what a stupid interface!
113 static unordered_map<uintptr_t, uintptr_t> *g_windows_thread_pool_wait_object_map;
114 #endif
115
116 //--------------- StackFrame ----------------- {{{1
117 struct StackFrame {
118 uintptr_t pc;
119 uintptr_t sp;
StackFrameStackFrame120 StackFrame(uintptr_t p, uintptr_t s) : pc(p), sp(s) { }
121 };
122 //--------------- InstrumentedCallFrame ----- {{{1
123 // Machinery to implement the fast interceptors in PIN
124 // (i.e. the ones that don't use PIN_CallApplicationFunction).
125 // We instrument the entry of the interesting function (e.g. malloc)
126 // and all RET instructions in this function's module (e.g. libc).
127 // At entry, we push an InstrumentedCallFrame object onto InstrumentedCallStack.
128 // At every RET instruction we check if the stack is not empty (fast path)
129 // and if the top contains the current SP. If yes -- this is the function return
130 // and we pop the stack.
131 struct InstrumentedCallFrame {
132 typedef void (*callback_t)(THREADID tid, InstrumentedCallFrame &frame,
133 ADDRINT ret);
134 callback_t callback;
135 uintptr_t pc;
136 uintptr_t sp;
137 uintptr_t arg[4];
138 };
139
140 struct InstrumentedCallStack {
141 public:
InstrumentedCallStackInstrumentedCallStack142 InstrumentedCallStack() : size_(0) { }
143
sizeInstrumentedCallStack144 size_t size() { return size_; }
145
PushInstrumentedCallStack146 void Push(InstrumentedCallFrame::callback_t callback,
147 uintptr_t pc,
148 uintptr_t sp,
149 uintptr_t a0, uintptr_t a1) {
150 CHECK(size() < TS_ARRAY_SIZE(frames_));
151 size_++;
152 Top()->callback = callback;
153 Top()->pc = pc;
154 Top()->sp = sp;
155 Top()->arg[0] = a0;
156 Top()->arg[1] = a1;
157 }
158
PopInstrumentedCallStack159 void Pop() {
160 CHECK(size() > 0);
161 size_--;
162 }
163
TopInstrumentedCallStack164 InstrumentedCallFrame *Top() {
165 CHECK(size() > 0);
166 return &frames_[size_-1];
167 }
168
PrintInstrumentedCallStack169 void Print() {
170 for (size_t i = 0; i < size(); i++) {
171 Printf( " %p\n", frames_[i].sp);
172 if (i > 0) CHECK(frames_[i].sp <= frames_[i-1].sp);
173 }
174 }
175
176 private:
177 InstrumentedCallFrame frames_[20];
178 size_t size_;
179 };
180
181 //--------------- PinThread ----------------- {{{1
182 const size_t kThreadLocalEventBufferSize = 2048 - 2;
183 // The number of mops should be at least 2 less than the size of TLEB
184 // so that we have space to put SBLOCK_ENTER token and the trace_info ptr.
185 const size_t kMaxMopsPerTrace = kThreadLocalEventBufferSize - 2;
186
187 REG tls_reg;
188
189 struct PinThread;
190
191 struct ThreadLocalEventBuffer {
192 PinThread *t;
193 size_t size;
194 uintptr_t events[kThreadLocalEventBufferSize];
195 };
196
197 struct PinThread {
198 ThreadLocalEventBuffer tleb;
199 int uniq_tid;
200 uint32_t literace_sampling; // cache of a flag.
201 volatile long last_child_tid;
202 InstrumentedCallStack ic_stack;
203 THREADID tid;
204 THREADID parent_tid;
205 pthread_t my_ptid;
206 size_t thread_stack_size_if_known;
207 size_t last_child_stack_size_if_known;
208 vector<StackFrame> shadow_stack;
209 TraceInfo *trace_info;
210 int ignore_accesses; // if > 0, ignore all memory accesses.
211 int ignore_accesses_depth;
212 int ignore_sync; // if > 0, ignore all sync events.
213 int spin_lock_recursion_depth;
214 bool thread_finished;
215 bool thread_done;
216 bool holding_lock;
217 int n_consumed_events;
218 #ifdef _MSC_VER
219 enum StartupState {
220 STARTING,
221 CHILD_READY,
222 MAY_CONTINUE,
223 };
224 volatile long startup_state; // used to handle the CREATE_SUSPENDED flag.
225 #endif
226 char padding[64]; // avoid any chance of ping-pong.
227 };
228
229 // Array of pin threads, indexed by pin's THREADID.
230 static PinThread *g_pin_threads;
231
232 // If true, ignore all accesses in all threads.
233 extern bool global_ignore;
234
235 #ifdef _MSC_VER
236 static unordered_set<pthread_t> *g_win_handles_which_are_threads;
237 #endif
238
239 //-------------------- ts_replace ------------------- {{{1
ReportAccesRange(THREADID tid,uintptr_t pc,EventType type,uintptr_t x,size_t size)240 static void ReportAccesRange(THREADID tid, uintptr_t pc, EventType type, uintptr_t x, size_t size) {
241 if (size && !g_pin_threads[tid].ignore_accesses) {
242 uintptr_t end = x + size;
243 for(uintptr_t a = x; a < end; a += 8) {
244 size_t cur_size = min((uintptr_t)8, end - a);
245 DumpEvent(0, type, tid, pc, a, cur_size);
246 }
247 }
248 }
249
250 #define REPORT_READ_RANGE(x, size) ReportAccesRange(tid, pc, READ, (uintptr_t)x, size)
251 #define REPORT_WRITE_RANGE(x, size) ReportAccesRange(tid, pc, WRITE, (uintptr_t)x, size)
252
253 #define EXTRA_REPLACE_PARAMS THREADID tid, uintptr_t pc,
254 #define EXTRA_REPLACE_ARGS tid, pc,
255 #include "ts_replace.h"
256
257 //------------- ThreadSanitizer exports ------------ {{{1
Demangle(const char * str)258 string Demangle(const char *str) {
259 #if defined(__GNUC__)
260 int status;
261 char *demangled = __cxxabiv1::__cxa_demangle(str, 0, 0, &status);
262 if (demangled) {
263 string res = demangled;
264 free(demangled);
265 return res;
266 }
267 #endif
268 return str;
269 }
270
PcToStrings(uintptr_t pc,bool demangle,string * img_name,string * rtn_name,string * file_name,int * line_no)271 void PcToStrings(uintptr_t pc, bool demangle,
272 string *img_name, string *rtn_name,
273 string *file_name, int *line_no) {
274 if (G_flags->symbolize) {
275 RTN rtn;
276 ScopedReentrantClientLock lock(__LINE__);
277 // ClientLock must be held.
278 PIN_GetSourceLocation(pc, NULL, line_no, file_name);
279 *file_name = ConvertToPlatformIndependentPath(*file_name);
280 rtn = RTN_FindByAddress(pc);
281 string name;
282 if (RTN_Valid(rtn)) {
283 *rtn_name = demangle
284 ? Demangle(RTN_Name(rtn).c_str())
285 : RTN_Name(rtn);
286 *img_name = IMG_Name(SEC_Img(RTN_Sec(rtn)));
287 }
288 }
289 }
290
PcToRtnName(uintptr_t pc,bool demangle)291 string PcToRtnName(uintptr_t pc, bool demangle) {
292 string res;
293 if (G_flags->symbolize) {
294 {
295 ScopedReentrantClientLock lock(__LINE__);
296 RTN rtn = RTN_FindByAddress(pc);
297 if (RTN_Valid(rtn)) {
298 res = demangle
299 ? Demangle(RTN_Name(rtn).c_str())
300 : RTN_Name(rtn);
301 }
302 }
303 }
304 return res;
305 }
306
307 //--------------- ThreadLocalEventBuffer ----------------- {{{1
308 // thread local event buffer is an array of uintptr_t.
309 // The events are encoded like this:
310 // { RTN_CALL, call_pc, target_pc }
311 // { RTN_EXIT }
312 // { SBLOCK_ENTER, trace_info_of_size_n, addr1, addr2, ... addr_n}
313
314 enum TLEBSpecificEvents {
315 TLEB_IGNORE_ALL_BEGIN = LAST_EVENT + 1,
316 TLEB_IGNORE_ALL_END,
317 TLEB_IGNORE_SYNC_BEGIN,
318 TLEB_IGNORE_SYNC_END,
319 TLEB_GLOBAL_IGNORE_ON,
320 TLEB_GLOBAL_IGNORE_OFF,
321 };
322
DumpEventPlainText(EventType type,int32_t tid,uintptr_t pc,uintptr_t a,uintptr_t info)323 static bool DumpEventPlainText(EventType type, int32_t tid, uintptr_t pc,
324 uintptr_t a, uintptr_t info) {
325 #if DEBUG == 0 || defined(_MSC_VER)
326 return false;
327 #else
328 if (G_flags->dump_events.empty()) return false;
329
330 static unordered_set<uintptr_t> *pc_set;
331 if (pc_set == NULL) {
332 pc_set = new unordered_set<uintptr_t>;
333 }
334 static FILE *log_file = NULL;
335 if (log_file == NULL) {
336 log_file = popen(("gzip > " + G_flags->dump_events).c_str(), "w");
337 }
338 if (G_flags->symbolize && pc_set->insert(pc).second) {
339 string img_name, rtn_name, file_name;
340 int line = 0;
341 PcToStrings(pc, false, &img_name, &rtn_name, &file_name, &line);
342 if (file_name.empty()) file_name = "unknown";
343 if (img_name.empty()) img_name = "unknown";
344 if (rtn_name.empty()) rtn_name = "unknown";
345 if (line == 0) line = 1;
346 fprintf(log_file, "#PC %lx %s %s %s %d\n",
347 (long)pc, img_name.c_str(), rtn_name.c_str(),
348 file_name.c_str(), line);
349 }
350 fprintf(log_file, "%s %x %lx %lx %lx\n", kEventNames[type], tid,
351 (long)pc, (long)a, (long)info);
352 return true;
353 #endif
354 }
355
DumpEventInternal(EventType type,int32_t uniq_tid,uintptr_t pc,uintptr_t a,uintptr_t info)356 static void DumpEventInternal(EventType type, int32_t uniq_tid, uintptr_t pc,
357 uintptr_t a, uintptr_t info) {
358 if (DumpEventPlainText(type, uniq_tid, pc, a, info)) return;
359 // PIN wraps the tid (after 2048), but we need a uniq tid.
360 Event event(type, uniq_tid, pc, a, info);
361 ThreadSanitizerHandleOneEvent(&event);
362 }
363
ComputeIgnoreAccesses(PinThread & t)364 void ComputeIgnoreAccesses(PinThread &t) {
365 t.ignore_accesses = (t.ignore_accesses_depth != 0) || (global_ignore != 0);
366 }
367
HandleInnerEvent(PinThread & t,uintptr_t event)368 static void HandleInnerEvent(PinThread &t, uintptr_t event) {
369 DCHECK(event > LAST_EVENT);
370 if (event == TLEB_IGNORE_ALL_BEGIN){
371 t.ignore_accesses_depth++;
372 ComputeIgnoreAccesses(t);
373 } else if (event == TLEB_IGNORE_ALL_END){
374 t.ignore_accesses_depth--;
375 CHECK(t.ignore_accesses_depth >= 0);
376 ComputeIgnoreAccesses(t);
377 } else if (event == TLEB_IGNORE_SYNC_BEGIN){
378 t.ignore_sync++;
379 } else if (event == TLEB_IGNORE_SYNC_END){
380 t.ignore_sync--;
381 CHECK(t.ignore_sync >= 0);
382 } else if (event == TLEB_GLOBAL_IGNORE_ON){
383 Report("INFO: GLOBAL IGNORE ON\n");
384 global_ignore = true;
385 ComputeIgnoreAccesses(t);
386 } else if (event == TLEB_GLOBAL_IGNORE_OFF){
387 Report("INFO: GLOBAL IGNORE OFF\n");
388 global_ignore = false;
389 ComputeIgnoreAccesses(t);
390 } else {
391 Printf("Event: %ld (last: %ld)\n", event, LAST_EVENT);
392 CHECK(0);
393 }
394 }
395
WantToIgnoreEvent(PinThread & t,uintptr_t event)396 static INLINE bool WantToIgnoreEvent(PinThread &t, uintptr_t event) {
397 if (t.ignore_sync &&
398 (event == WRITER_LOCK || event == READER_LOCK || event == UNLOCK ||
399 event == SIGNAL || event == WAIT)) {
400 // do nothing, we are ignoring locks.
401 return true;
402 } else if (t.ignore_accesses && (event == READ || event == WRITE)) {
403 // do nothing, we are ignoring mops.
404 return true;
405 }
406 return false;
407 }
408
TLEBFlushUnlocked(ThreadLocalEventBuffer & tleb)409 static INLINE void TLEBFlushUnlocked(ThreadLocalEventBuffer &tleb) {
410 if (tleb.size == 0) return;
411 PinThread &t = *tleb.t;
412 // global_ignore should be always on with race verifier
413 DCHECK(!g_race_verifier_active || global_ignore);
414 DCHECK(tleb.size <= kThreadLocalEventBufferSize);
415 if (DEBUG_MODE && t.thread_done) {
416 Printf("ACHTUNG!!! an event from a dead thread T%d\n", t.tid);
417 }
418 DCHECK(!t.thread_done);
419
420 if (TS_SERIALIZED == 1 || DEBUG_MODE) {
421 size_t max_idx = TS_ARRAY_SIZE(G_stats->tleb_flush);
422 size_t idx = min((size_t)u32_log2(tleb.size), max_idx - 1);
423 CHECK(idx < max_idx);
424 G_stats->tleb_flush[idx]++;
425 }
426
427 if (TS_SERIALIZED == 1 && G_flags->offline) {
428 fwrite(tleb.events, sizeof(uintptr_t), tleb.size, G_out);
429 tleb.size = 0;
430 return;
431 }
432
433 size_t i;
434 for (i = 0; i < tleb.size; ) {
435 uintptr_t event = tleb.events[i++];
436 DCHECK(!g_race_verifier_active ||
437 event == SBLOCK_ENTER || event == EXPECT_RACE || event == THR_START);
438 if (event == RTN_EXIT) {
439 if (DumpEventPlainText(RTN_EXIT, t.uniq_tid, 0, 0, 0)) continue;
440 ThreadSanitizerHandleRtnExit(t.uniq_tid);
441 } else if (event == RTN_CALL) {
442 uintptr_t call_pc = tleb.events[i++];
443 uintptr_t target_pc = tleb.events[i++];
444 IGNORE_BELOW_RTN ignore_below = (IGNORE_BELOW_RTN)tleb.events[i++];
445 if (DumpEventPlainText(RTN_CALL, t.uniq_tid, call_pc,
446 target_pc, ignore_below)) continue;
447 ThreadSanitizerHandleRtnCall(t.uniq_tid, call_pc, target_pc,
448 ignore_below);
449 } else if (event == SBLOCK_ENTER){
450 TraceInfo *trace_info = (TraceInfo*) tleb.events[i++];
451 DCHECK(trace_info);
452 bool do_this_trace = true;
453 if (t.ignore_accesses) {
454 do_this_trace = false;
455 } else if (t.literace_sampling) {
456 do_this_trace = !trace_info->LiteRaceSkipTraceRealTid(
457 t.uniq_tid, t.literace_sampling);
458 }
459
460 size_t n = trace_info->n_mops();
461 if (do_this_trace) {
462 if (DEBUG_MODE && !G_flags->dump_events.empty()) {
463 DumpEventPlainText(SBLOCK_ENTER, t.uniq_tid, trace_info->pc(), 0, 0);
464 for (size_t j = 0; j < n; j++) {
465 MopInfo *mop = trace_info->GetMop(j);
466 DCHECK(mop->size());
467 DCHECK(mop);
468 uintptr_t addr = tleb.events[i + j];
469 if (addr) {
470 DumpEventPlainText(mop->is_write() ? WRITE : READ, t.uniq_tid,
471 mop->pc(), addr, mop->size());
472 }
473 }
474 } else {
475 ThreadSanitizerHandleTrace(t.uniq_tid, trace_info, tleb.events+i);
476 }
477 }
478 i += n;
479 } else if (event == THR_START) {
480 uintptr_t parent = -1;
481 if (t.parent_tid != (THREADID)-1) {
482 parent = g_pin_threads[t.parent_tid].uniq_tid;
483 }
484 DumpEventInternal(THR_START, t.uniq_tid, 0, 0, parent);
485 } else if (event == THR_END) {
486 DumpEventInternal(THR_END, t.uniq_tid, 0, 0, 0);
487 DCHECK(t.thread_finished == true);
488 DCHECK(t.thread_done == false);
489 t.thread_done = true;
490 i += 3; // consume the unneeded data.
491 DCHECK(i == tleb.size); // should be last event in this tleb.
492 } else if (event > LAST_EVENT) {
493 HandleInnerEvent(t, event);
494 } else {
495 // all other events.
496 CHECK(event > NOOP && event < LAST_EVENT);
497 uintptr_t pc = tleb.events[i++];
498 uintptr_t a = tleb.events[i++];
499 uintptr_t info = tleb.events[i++];
500 if (!WantToIgnoreEvent(t, event)) {
501 DumpEventInternal((EventType)event, t.uniq_tid, pc, a, info);
502 }
503 }
504 }
505 DCHECK(i == tleb.size);
506 tleb.size = 0;
507 if (DEBUG_MODE) { // for sanity checking.
508 memset(tleb.events, 0xf0, sizeof(tleb.events));
509 }
510 }
511
TLEBFlushLocked(PinThread & t)512 static INLINE void TLEBFlushLocked(PinThread &t) {
513 #if TS_SERIALIZED==1
514 if (G_flags->dry_run) {
515 t.tleb.size = 0;
516 return;
517 }
518 CHECK(t.tleb.size <= kThreadLocalEventBufferSize);
519 G_stats->lock_sites[0]++;
520 ScopedLock lock(&g_main_ts_lock);
521 TLEBFlushUnlocked(t.tleb);
522 #else
523 TLEBFlushUnlocked(t.tleb);
524 #endif
525 }
526
TLEBAddRtnCall(PinThread & t,uintptr_t call_pc,uintptr_t target_pc,IGNORE_BELOW_RTN ignore_below)527 static void TLEBAddRtnCall(PinThread &t, uintptr_t call_pc,
528 uintptr_t target_pc, IGNORE_BELOW_RTN ignore_below) {
529 if (TS_SERIALIZED == 0) {
530 TLEBFlushLocked(t);
531 ThreadSanitizerHandleRtnCall(t.uniq_tid, call_pc, target_pc,
532 ignore_below);
533 return;
534 }
535 DCHECK(t.tleb.size <= kThreadLocalEventBufferSize);
536 if (t.tleb.size + 4 > kThreadLocalEventBufferSize) {
537 TLEBFlushLocked(t);
538 DCHECK(t.tleb.size == 0);
539 }
540 t.tleb.events[t.tleb.size++] = RTN_CALL;
541 t.tleb.events[t.tleb.size++] = call_pc;
542 t.tleb.events[t.tleb.size++] = target_pc;
543 t.tleb.events[t.tleb.size++] = ignore_below;
544 DCHECK(t.tleb.size <= kThreadLocalEventBufferSize);
545 }
546
TLEBAddRtnExit(PinThread & t)547 static void TLEBAddRtnExit(PinThread &t) {
548 if (TS_SERIALIZED == 0) {
549 TLEBFlushLocked(t);
550 ThreadSanitizerHandleRtnExit(t.uniq_tid);
551 return;
552 }
553 if (t.tleb.size + 1 > kThreadLocalEventBufferSize) {
554 TLEBFlushLocked(t);
555 }
556 t.tleb.events[t.tleb.size++] = RTN_EXIT;
557 DCHECK(t.tleb.size <= kThreadLocalEventBufferSize);
558 }
559
TLEBAddTrace(PinThread & t)560 static INLINE uintptr_t *TLEBAddTrace(PinThread &t) {
561 size_t n = t.trace_info->n_mops();
562 DCHECK(n > 0);
563 if (TS_SERIALIZED == 0) {
564 TLEBFlushLocked(t);
565 } else if (t.tleb.size + 2 + n > kThreadLocalEventBufferSize) {
566 TLEBFlushLocked(t);
567 }
568 if (TS_SERIALIZED == 1) {
569 t.tleb.events[t.tleb.size++] = SBLOCK_ENTER;
570 t.tleb.events[t.tleb.size++] = (uintptr_t)t.trace_info;
571 } else {
572 DCHECK(t.tleb.size == 0);
573 t.tleb.events[0] = SBLOCK_ENTER;
574 t.tleb.events[1] = (uintptr_t)t.trace_info;
575 t.tleb.size += 2;
576 }
577 uintptr_t *mop_addresses = &t.tleb.events[t.tleb.size];
578 // not every address will be written to. so they will stay 0.
579 for (size_t i = 0; i < n; i++) {
580 mop_addresses[i] = 0;
581 }
582 t.tleb.size += n;
583 DCHECK(t.tleb.size <= kThreadLocalEventBufferSize);
584 return mop_addresses;
585 }
586
TLEBStartThread(PinThread & t)587 static void TLEBStartThread(PinThread &t) {
588 CHECK(t.tleb.size == 0);
589 t.tleb.events[t.tleb.size++] = THR_START;
590 }
591
TLEBSimpleEvent(PinThread & t,uintptr_t event)592 static void TLEBSimpleEvent(PinThread &t, uintptr_t event) {
593 if (g_race_verifier_active)
594 return;
595 if (TS_SERIALIZED == 0) {
596 TLEBFlushLocked(t);
597 if (event < LAST_EVENT) {
598 Event e((EventType)event, t.uniq_tid, 0, 0, 0);
599 ThreadSanitizerHandleOneEvent(&e);
600 } else {
601 HandleInnerEvent(t, event);
602 }
603 return;
604 }
605 if (t.tleb.size + 1 > kThreadLocalEventBufferSize) {
606 TLEBFlushLocked(t);
607 }
608 t.tleb.events[t.tleb.size++] = event;
609 DCHECK(t.tleb.size <= kThreadLocalEventBufferSize);
610 }
611
TLEBAddGenericEventAndFlush(PinThread & t,EventType type,uintptr_t pc,uintptr_t a,uintptr_t info)612 static void TLEBAddGenericEventAndFlush(PinThread &t,
613 EventType type, uintptr_t pc,
614 uintptr_t a, uintptr_t info) {
615 if (TS_SERIALIZED == 0) {
616 if (WantToIgnoreEvent(t, type)) return;
617 TLEBFlushLocked(t);
618 Event e(type, t.uniq_tid, pc, a, info);
619 ThreadSanitizerHandleOneEvent(&e);
620 return;
621 }
622 if (t.tleb.size + 4 > kThreadLocalEventBufferSize) {
623 TLEBFlushLocked(t);
624 }
625 DCHECK(type > NOOP && type < LAST_EVENT);
626 t.tleb.events[t.tleb.size++] = type;
627 t.tleb.events[t.tleb.size++] = pc;
628 t.tleb.events[t.tleb.size++] = a;
629 t.tleb.events[t.tleb.size++] = info;
630 TLEBFlushLocked(t);
631 DCHECK(t.tleb.size <= kThreadLocalEventBufferSize);
632 }
633
634 static void UpdateCallStack(PinThread &t, ADDRINT sp);
635
636 // Must be called from its thread (except for THR_END case)!
DumpEventWithSp(uintptr_t sp,EventType type,int32_t tid,uintptr_t pc,uintptr_t a,uintptr_t info)637 static void DumpEventWithSp(uintptr_t sp, EventType type, int32_t tid, uintptr_t pc,
638 uintptr_t a, uintptr_t info) {
639 if (!g_race_verifier_active || type == EXPECT_RACE) {
640 PinThread &t = g_pin_threads[tid];
641 if (sp) {
642 UpdateCallStack(t, sp);
643 }
644 TLEBAddGenericEventAndFlush(t, type, pc, a, info);
645 }
646 }
DumpEvent(CONTEXT * ctx,EventType type,int32_t tid,uintptr_t pc,uintptr_t a,uintptr_t info)647 static void DumpEvent(CONTEXT *ctx, EventType type, int32_t tid, uintptr_t pc,
648 uintptr_t a, uintptr_t info) {
649 DumpEventWithSp(ctx ? PIN_GetContextReg(ctx, REG_STACK_PTR) : 0,
650 type, tid, pc, a, info);
651 }
652
653 //--------- Wraping and relacing --------------- {{{1
654 static set<string> g_wrapped_functions;
InformAboutFunctionWrap(RTN rtn,string name)655 static void InformAboutFunctionWrap(RTN rtn, string name) {
656 g_wrapped_functions.insert(name);
657 if (!debug_wrap) return;
658 Printf("Function wrapped: %s (%s %s)\n", name.c_str(),
659 RTN_Name(rtn).c_str(), IMG_Name(SEC_Img(RTN_Sec(rtn))).c_str());
660 }
661
RtnMatchesName(const string & rtn_name,const string & name)662 static bool RtnMatchesName(const string &rtn_name, const string &name) {
663 CHECK(name.size() > 0);
664 size_t pos = rtn_name.find(name);
665 if (pos == string::npos) {
666 return false;
667 }
668 if (pos == 0 && name.size() == rtn_name.size()) {
669 // Printf("Full match: %s %s\n", rtn_name.c_str(), name.c_str());
670 return true;
671 }
672 // match MyFuncName@123
673 if (pos == 0 && name.size() < rtn_name.size()
674 && rtn_name[name.size()] == '@') {
675 // Printf("Versioned match: %s %s\n", rtn_name.c_str(), name.c_str());
676 return true;
677 }
678 // match _MyFuncName@123
679 if (pos == 1 && rtn_name[0] == '_' && name.size() < rtn_name.size()
680 && rtn_name[name.size() + 1] == '@') {
681 // Printf("Versioned match: %s %s\n", rtn_name.c_str(), name.c_str());
682 return true;
683 }
684
685 return false;
686 }
687
688 #define FAST_WRAP_PARAM0 THREADID tid, ADDRINT pc, ADDRINT sp
689 #define FAST_WRAP_PARAM1 FAST_WRAP_PARAM0, ADDRINT arg0
690 #define FAST_WRAP_PARAM2 FAST_WRAP_PARAM1, ADDRINT arg1
691 #define FAST_WRAP_PARAM3 FAST_WRAP_PARAM2, ADDRINT arg2
692
693 #define FAST_WRAP_PARAM_AFTER \
694 THREADID tid, InstrumentedCallFrame &frame, ADDRINT ret
695
696
697 #define DEBUG_FAST_INTERCEPTORS 0
698 //#define DEBUG_FAST_INTERCEPTORS (tid == 1)
699
700 #define PUSH_AFTER_CALLBACK1(callback, a0) \
701 g_pin_threads[tid].ic_stack.Push(callback, pc, sp, a0, 0); \
702 if (DEBUG_FAST_INTERCEPTORS) \
703 Printf("T%d %s pc=%p sp=%p *sp=(%p) arg0=%p stack_size=%ld\n",\
704 tid, __FUNCTION__, pc, sp,\
705 ((void**)sp)[0],\
706 arg0,\
707 g_pin_threads[tid].ic_stack.size()\
708 );\
709
710
711 #define WRAP_NAME(name) Wrap_##name
712 #define WRAP4(name) WrapFunc4(img, rtn, #name, (AFUNPTR)Wrap_##name)
713 #define WRAPSTD1(name) WrapStdCallFunc1(rtn, #name, (AFUNPTR)Wrap_##name)
714 #define WRAPSTD2(name) WrapStdCallFunc2(rtn, #name, (AFUNPTR)Wrap_##name)
715 #define WRAPSTD3(name) WrapStdCallFunc3(rtn, #name, (AFUNPTR)Wrap_##name)
716 #define WRAPSTD4(name) WrapStdCallFunc4(rtn, #name, (AFUNPTR)Wrap_##name)
717 #define WRAPSTD5(name) WrapStdCallFunc5(rtn, #name, (AFUNPTR)Wrap_##name)
718 #define WRAPSTD6(name) WrapStdCallFunc6(rtn, #name, (AFUNPTR)Wrap_##name)
719 #define WRAPSTD7(name) WrapStdCallFunc7(rtn, #name, (AFUNPTR)Wrap_##name)
720 #define WRAPSTD8(name) WrapStdCallFunc8(rtn, #name, (AFUNPTR)Wrap_##name)
721 #define WRAPSTD10(name) WrapStdCallFunc10(rtn, #name, (AFUNPTR)Wrap_##name)
722 #define WRAPSTD11(name) WrapStdCallFunc11(rtn, #name, (AFUNPTR)Wrap_##name)
723 #define WRAP_PARAM4 THREADID tid, ADDRINT pc, CONTEXT *ctx, \
724 AFUNPTR f,\
725 uintptr_t arg0, uintptr_t arg1, \
726 uintptr_t arg2, uintptr_t arg3
727
728 #define WRAP_PARAM6 WRAP_PARAM4, uintptr_t arg4, uintptr_t arg5
729 #define WRAP_PARAM8 WRAP_PARAM6, uintptr_t arg6, uintptr_t arg7
730 #define WRAP_PARAM10 WRAP_PARAM8, uintptr_t arg8, uintptr_t arg9
731 #define WRAP_PARAM12 WRAP_PARAM10, uintptr_t arg10, uintptr_t arg11
732
CallFun4(CONTEXT * ctx,THREADID tid,AFUNPTR f,uintptr_t arg0,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3)733 static uintptr_t CallFun4(CONTEXT *ctx, THREADID tid,
734 AFUNPTR f, uintptr_t arg0, uintptr_t arg1,
735 uintptr_t arg2, uintptr_t arg3) {
736 uintptr_t ret = 0xdeadbee1;
737 PIN_CallApplicationFunction(ctx, tid,
738 CALLINGSTD_DEFAULT, (AFUNPTR)(f),
739 PIN_PARG(uintptr_t), &ret,
740 PIN_PARG(uintptr_t), arg0,
741 PIN_PARG(uintptr_t), arg1,
742 PIN_PARG(uintptr_t), arg2,
743 PIN_PARG(uintptr_t), arg3,
744 PIN_PARG_END());
745 return ret;
746 }
747
CallFun6(CONTEXT * ctx,THREADID tid,AFUNPTR f,uintptr_t arg0,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t arg4,uintptr_t arg5)748 static uintptr_t CallFun6(CONTEXT *ctx, THREADID tid,
749 AFUNPTR f, uintptr_t arg0, uintptr_t arg1,
750 uintptr_t arg2, uintptr_t arg3,
751 uintptr_t arg4, uintptr_t arg5) {
752 uintptr_t ret = 0xdeadbee1;
753 PIN_CallApplicationFunction(ctx, tid,
754 CALLINGSTD_DEFAULT, (AFUNPTR)(f),
755 PIN_PARG(uintptr_t), &ret,
756 PIN_PARG(uintptr_t), arg0,
757 PIN_PARG(uintptr_t), arg1,
758 PIN_PARG(uintptr_t), arg2,
759 PIN_PARG(uintptr_t), arg3,
760 PIN_PARG(uintptr_t), arg4,
761 PIN_PARG(uintptr_t), arg5,
762 PIN_PARG_END());
763 return ret;
764 }
765
766 #define CALL_ME_INSIDE_WRAPPER_4() CallFun4(ctx, tid, f, arg0, arg1, arg2, arg3)
767 #define CALL_ME_INSIDE_WRAPPER_6() CallFun6(ctx, tid, f, arg0, arg1, arg2, arg3, arg4, arg5)
768
769 // Completely replace (i.e. not wrap) a function with 3 (or less) parameters.
770 // The original function will not be called.
ReplaceFunc3(IMG img,RTN rtn,const char * name,AFUNPTR replacement_func)771 void ReplaceFunc3(IMG img, RTN rtn, const char *name, AFUNPTR replacement_func) {
772 if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name)) {
773 InformAboutFunctionWrap(rtn, name);
774 PROTO proto = PROTO_Allocate(PIN_PARG(uintptr_t),
775 CALLINGSTD_DEFAULT,
776 "proto",
777 PIN_PARG(uintptr_t),
778 PIN_PARG(uintptr_t),
779 PIN_PARG(uintptr_t),
780 PIN_PARG_END());
781 RTN_ReplaceSignature(rtn,
782 AFUNPTR(replacement_func),
783 IARG_PROTOTYPE, proto,
784 IARG_THREAD_ID,
785 IARG_INST_PTR,
786 IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
787 IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
788 IARG_FUNCARG_ENTRYPOINT_VALUE, 2,
789 IARG_END);
790 PROTO_Free(proto);
791 }
792 }
793
794 // Wrap a function with up to 4 parameters.
WrapFunc4(IMG img,RTN rtn,const char * name,AFUNPTR replacement_func)795 void WrapFunc4(IMG img, RTN rtn, const char *name, AFUNPTR replacement_func) {
796 if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name)) {
797 InformAboutFunctionWrap(rtn, name);
798 PROTO proto = PROTO_Allocate(PIN_PARG(uintptr_t),
799 CALLINGSTD_DEFAULT,
800 "proto",
801 PIN_PARG(uintptr_t),
802 PIN_PARG(uintptr_t),
803 PIN_PARG(uintptr_t),
804 PIN_PARG(uintptr_t),
805 PIN_PARG_END());
806 RTN_ReplaceSignature(rtn,
807 AFUNPTR(replacement_func),
808 IARG_PROTOTYPE, proto,
809 IARG_THREAD_ID,
810 IARG_INST_PTR,
811 IARG_CONTEXT,
812 IARG_ORIG_FUNCPTR,
813 IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
814 IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
815 IARG_FUNCARG_ENTRYPOINT_VALUE, 2,
816 IARG_FUNCARG_ENTRYPOINT_VALUE, 3,
817 IARG_END);
818 PROTO_Free(proto);
819 }
820 }
821
822 // Wrap a function with up to 6 parameters.
WrapFunc6(IMG img,RTN rtn,const char * name,AFUNPTR replacement_func)823 void WrapFunc6(IMG img, RTN rtn, const char *name, AFUNPTR replacement_func) {
824 if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name)) {
825 InformAboutFunctionWrap(rtn, name);
826 PROTO proto = PROTO_Allocate(PIN_PARG(uintptr_t),
827 CALLINGSTD_DEFAULT,
828 "proto",
829 PIN_PARG(uintptr_t),
830 PIN_PARG(uintptr_t),
831 PIN_PARG(uintptr_t),
832 PIN_PARG(uintptr_t),
833 PIN_PARG(uintptr_t),
834 PIN_PARG(uintptr_t),
835 PIN_PARG_END());
836 RTN_ReplaceSignature(rtn,
837 AFUNPTR(replacement_func),
838 IARG_PROTOTYPE, proto,
839 IARG_THREAD_ID,
840 IARG_INST_PTR,
841 IARG_CONTEXT,
842 IARG_ORIG_FUNCPTR,
843 IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
844 IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
845 IARG_FUNCARG_ENTRYPOINT_VALUE, 2,
846 IARG_FUNCARG_ENTRYPOINT_VALUE, 3,
847 IARG_FUNCARG_ENTRYPOINT_VALUE, 4,
848 IARG_FUNCARG_ENTRYPOINT_VALUE, 5,
849 IARG_END);
850 PROTO_Free(proto);
851 }
852 }
853
854
855 //--------- Instrumentation callbacks --------------- {{{1
856 //---------- Debug -----------------------------------{{{2
857 #define DEB_PR (0)
858
ShowPcAndSp(const char * where,THREADID tid,ADDRINT pc,ADDRINT sp)859 static void ShowPcAndSp(const char *where, THREADID tid,
860 ADDRINT pc, ADDRINT sp) {
861 Printf("%s T%d sp=%ld pc=%p %s\n", where, tid, sp, pc,
862 PcToRtnName(pc, true).c_str());
863 }
864
PrintShadowStack(PinThread & t)865 static void PrintShadowStack(PinThread &t) {
866 Printf("T%d Shadow stack (%d)\n", t.tid, (int)t.shadow_stack.size());
867 for (int i = t.shadow_stack.size() - 1; i >= 0; i--) {
868 uintptr_t pc = t.shadow_stack[i].pc;
869 uintptr_t sp = t.shadow_stack[i].sp;
870 Printf(" sp=%ld pc=%lx %s\n", sp, pc, PcToRtnName(pc, true).c_str());
871 }
872 }
873
DebugOnlyShowPcAndSp(const char * where,THREADID tid,ADDRINT pc,ADDRINT sp)874 static void DebugOnlyShowPcAndSp(const char *where, THREADID tid,
875 ADDRINT pc, ADDRINT sp) {
876 if (DEB_PR) {
877 ShowPcAndSp(where, tid, pc, sp);
878 }
879 }
880
WRAP_NAME(ThreadSanitizerQuery)881 static uintptr_t WRAP_NAME(ThreadSanitizerQuery)(WRAP_PARAM4) {
882 const char *query = (const char*)arg0;
883 return (uintptr_t)ThreadSanitizerQuery(query);
884 }
885
886 //--------- Ignores -------------------------------- {{{2
IgnoreMopsBegin(THREADID tid)887 static void IgnoreMopsBegin(THREADID tid) {
888 // if (tid != 0) Printf("T%d IgnoreMops++\n", tid);
889 TLEBSimpleEvent(g_pin_threads[tid], TLEB_IGNORE_ALL_BEGIN);
890 }
IgnoreMopsEnd(THREADID tid)891 static void IgnoreMopsEnd(THREADID tid) {
892 // if (tid != 0) Printf("T%d IgnoreMops--\n", tid);
893 TLEBSimpleEvent(g_pin_threads[tid], TLEB_IGNORE_ALL_END);
894 }
895
IgnoreSyncAndMopsBegin(THREADID tid)896 static void IgnoreSyncAndMopsBegin(THREADID tid) {
897 // if (tid != 0) Printf("T%d IgnoreSync++\n", tid);
898 IgnoreMopsBegin(tid);
899 TLEBSimpleEvent(g_pin_threads[tid], TLEB_IGNORE_SYNC_BEGIN);
900 }
IgnoreSyncAndMopsEnd(THREADID tid)901 static void IgnoreSyncAndMopsEnd(THREADID tid) {
902 // if (tid != 0) Printf("T%d IgnoreSync--\n", tid);
903 IgnoreMopsEnd(tid);
904 TLEBSimpleEvent(g_pin_threads[tid], TLEB_IGNORE_SYNC_END);
905 }
906
907 //--------- __cxa_guard_* -------------------------- {{{2
908 // From gcc/cp/decl.c:
909 // --------------------------------------------------------------
910 // Emit code to perform this initialization but once. This code
911 // looks like:
912 //
913 // static <type> guard;
914 // if (!guard.first_byte) {
915 // if (__cxa_guard_acquire (&guard)) {
916 // bool flag = false;
917 // try {
918 // // Do initialization.
919 // flag = true; __cxa_guard_release (&guard);
920 // // Register variable for destruction at end of program.
921 // } catch {
922 // if (!flag) __cxa_guard_abort (&guard);
923 // }
924 // }
925 // --------------------------------------------------------------
926 // So, when __cxa_guard_acquire returns true, we start ignoring all accesses
927 // and in __cxa_guard_release we stop ignoring them.
928 // We also need to ignore all accesses inside these two functions.
929
Before_cxa_guard_acquire(THREADID tid,ADDRINT pc,ADDRINT guard)930 static void Before_cxa_guard_acquire(THREADID tid, ADDRINT pc, ADDRINT guard) {
931 IgnoreMopsBegin(tid);
932 }
933
After_cxa_guard_acquire(THREADID tid,ADDRINT pc,ADDRINT ret)934 static void After_cxa_guard_acquire(THREADID tid, ADDRINT pc, ADDRINT ret) {
935 if (ret) {
936 // Continue ignoring, it will end in __cxa_guard_release.
937 } else {
938 // Stop ignoring, there will be no matching call to __cxa_guard_release.
939 IgnoreMopsEnd(tid);
940 }
941 }
942
After_cxa_guard_release(THREADID tid,ADDRINT pc)943 static void After_cxa_guard_release(THREADID tid, ADDRINT pc) {
944 IgnoreMopsEnd(tid);
945 }
946
WRAP_NAME(pthread_once)947 static uintptr_t WRAP_NAME(pthread_once)(WRAP_PARAM4) {
948 uintptr_t ret;
949 IgnoreMopsBegin(tid);
950 ret = CALL_ME_INSIDE_WRAPPER_4();
951 IgnoreMopsEnd(tid);
952 return ret;
953 }
954
TmpCallback1(THREADID tid,ADDRINT pc)955 void TmpCallback1(THREADID tid, ADDRINT pc) {
956 Printf("%s T%d %lx\n", __FUNCTION__, tid, pc);
957 }
TmpCallback2(THREADID tid,ADDRINT pc)958 void TmpCallback2(THREADID tid, ADDRINT pc) {
959 Printf("%s T%d %lx\n", __FUNCTION__, tid, pc);
960 }
961
962 //--------- Threads --------------------------------- {{{2
HandleThreadCreateBefore(THREADID tid,ADDRINT pc)963 static void HandleThreadCreateBefore(THREADID tid, ADDRINT pc) {
964 DumpEvent(0, THR_CREATE_BEFORE, tid, pc, 0, 0);
965 g_thread_create_lock.Lock();
966 IgnoreMopsBegin(tid);
967 CHECK(g_tid_of_thread_which_called_create_thread == (THREADID)-1);
968 g_tid_of_thread_which_called_create_thread = tid;
969 n_created_threads++;
970 }
971
HandleThreadCreateAbort(THREADID tid)972 static void HandleThreadCreateAbort(THREADID tid) {
973 CHECK(g_tid_of_thread_which_called_create_thread == tid);
974 g_tid_of_thread_which_called_create_thread = (THREADID)-1;
975 n_created_threads--;
976 IgnoreMopsEnd(tid);
977 g_thread_create_lock.Unlock();
978 }
979
HandleThreadCreateAfter(THREADID tid,pthread_t child_ptid,bool suspend_child)980 static THREADID HandleThreadCreateAfter(THREADID tid, pthread_t child_ptid,
981 bool suspend_child) {
982 // Spin, waiting for last_child_tid to appear (i.e. wait for the thread to
983 // actually start) so that we know the child's tid. No locks.
984 while (!ATOMIC_READ(&g_pin_threads[tid].last_child_tid)) {
985 YIELD();
986 }
987
988 CHECK(g_tid_of_thread_which_called_create_thread == tid);
989 g_tid_of_thread_which_called_create_thread = -1;
990
991 THREADID last_child_tid = g_pin_threads[tid].last_child_tid;
992 CHECK(last_child_tid);
993
994 PinThread &child_t = g_pin_threads[last_child_tid];
995 child_t.my_ptid = child_ptid;
996
997 #ifdef _MSC_VER
998 if (suspend_child) {
999 while (ATOMIC_READ(&child_t.startup_state) != PinThread::CHILD_READY) {
1000 YIELD();
1001 }
1002 // Strictly speaking, PIN forbids calling system functions like this.
1003 // This may violate application library isolation but
1004 // a) YIELD == WINDOWS::Sleep, so we violate it anyways
1005 // b) SuspendThread probably calls NtSuspendThread right away
1006 WINDOWS::DWORD old_count = WINDOWS::SuspendThread((WINDOWS::HANDLE)child_ptid); // TODO handle?
1007 CHECK(old_count == 0);
1008 }
1009 child_t.startup_state = PinThread::MAY_CONTINUE;
1010 #else
1011 CHECK(!suspend_child); // Not implemented - do we need to?
1012 #endif
1013
1014 int uniq_tid_of_child = child_t.uniq_tid;
1015 g_pin_threads[tid].last_child_tid = 0;
1016
1017 IgnoreMopsEnd(tid);
1018 g_thread_create_lock.Unlock();
1019
1020 DumpEvent(0, THR_CREATE_AFTER, tid, 0, 0, uniq_tid_of_child);
1021 return last_child_tid;
1022 }
1023
WRAP_NAME(pthread_create)1024 static uintptr_t WRAP_NAME(pthread_create)(WRAP_PARAM4) {
1025 HandleThreadCreateBefore(tid, pc);
1026
1027 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
1028 if (ret != 0) {
1029 HandleThreadCreateAbort(tid);
1030 return ret;
1031 }
1032
1033 pthread_t child_ptid = *(pthread_t*)arg0;
1034 HandleThreadCreateAfter(tid, child_ptid, false);
1035
1036 return ret;
1037 }
1038
CallbackForThreadStart(THREADID tid,CONTEXT * ctxt,INT32 flags,void * v)1039 void CallbackForThreadStart(THREADID tid, CONTEXT *ctxt,
1040 INT32 flags, void *v) {
1041 // We can not rely on PIN_GetParentTid() since it is broken on Windows.
1042
1043 if (g_pin_threads == NULL) {
1044 g_pin_threads = new PinThread[kMaxThreads];
1045 }
1046
1047 bool has_parent = true;
1048 if (tid == 0) {
1049 // Main thread or we have attached to a running process.
1050 has_parent = false;
1051 } else {
1052 CHECK(tid > 0);
1053 }
1054
1055 CHECK(tid < kMaxThreads);
1056 PinThread &t = g_pin_threads[tid];
1057 memset(&t, 0, sizeof(PinThread));
1058 t.uniq_tid = n_started_threads++;
1059 t.literace_sampling = G_flags->literace_sampling;
1060 t.tid = tid;
1061 t.tleb.t = &t;
1062 #if defined(_MSC_VER)
1063 t.startup_state = PinThread::STARTING;
1064 #endif
1065 ComputeIgnoreAccesses(t);
1066
1067
1068 PIN_SetContextReg(ctxt, tls_reg, (ADDRINT)&t.tleb.events[2]);
1069
1070 t.parent_tid = -1;
1071 if (has_parent) {
1072 t.parent_tid = g_tid_of_thread_which_called_create_thread;
1073 #if !defined(_MSC_VER) // On Windows, threads may appear out of thin air.
1074 CHECK(t.parent_tid != (THREADID)-1);
1075 #endif // _MSC_VER
1076 }
1077
1078 if (debug_thread) {
1079 Printf("T%d ThreadStart parent=%d child=%d\n", tid, t.parent_tid, tid);
1080 }
1081
1082 if (has_parent && t.parent_tid != (THREADID)-1) {
1083 g_pin_threads[t.parent_tid].last_child_tid = tid;
1084 t.thread_stack_size_if_known =
1085 g_pin_threads[t.parent_tid].last_child_stack_size_if_known;
1086 } else {
1087 #if defined(_MSC_VER)
1088 t.startup_state = PinThread::MAY_CONTINUE;
1089 #endif
1090 }
1091
1092 // This is a lock-free (thread local) operation.
1093 TLEBStartThread(t);
1094 /* TODO(timurrrr): investigate and un-comment
1095 #ifdef _MSC_VER
1096 // Ignore all mops & sync before the real thread code.
1097 // See the corresponding IgnoreSyncAndMopsEnd in Before_BaseThreadInitThunk.
1098 IgnoreSyncAndMopsBegin(tid);
1099 #endif
1100 */
1101 }
1102
Before_start_thread(THREADID tid,ADDRINT pc,ADDRINT sp)1103 static void Before_start_thread(THREADID tid, ADDRINT pc, ADDRINT sp) {
1104 PinThread &t = g_pin_threads[tid];
1105 if (debug_thread) {
1106 Printf("T%d Before_start_thread: sp=%p my_ptid=%p diff=%p\n",
1107 tid, sp, t.my_ptid, t.my_ptid - sp);
1108 }
1109 // This is a rather scary hack, but I see no easy way to avoid it.
1110 // On linux NPTL, the pthread_t structure is the same block of memory
1111 // as the stack (and the tls?). Somewhere inside the pthread_t
1112 // object lives the address of stackblock followed by its size
1113 // (see nptl/descr.h).
1114 // At the current point we may not know the value of pthread_t (my_ptid),
1115 // but we do know the current sp, which is a bit less than my_ptid.
1116 //
1117 // address value
1118 // ------------------------------------------------
1119 // 0xffffffffffffffff:
1120 //
1121 // stackblock + stackblock_size:
1122 // my_ptid:
1123 //
1124 // stackblock_size
1125 // stackblock
1126 //
1127 // current_sp:
1128 //
1129 //
1130 // stackblock:
1131 //
1132 // 0x0000000000000000:
1133 // -------------------------------------------------
1134 //
1135 // So, we itrate from sp to the higher addresses (but just in case, not more
1136 // than a few pages) trying to find a pair of values which looks like
1137 // stackblock and stackblock_size. Oh well.
1138 // Note that in valgrind we are able to get this info from
1139 // pthread_getattr_np (linux) or pthread_get_stackaddr_np (mac),
1140 // but in PIN we can't call those (can we?).
1141 uintptr_t prev = 0;
1142 for (uintptr_t sp1 = sp; sp1 - sp < 0x2000;
1143 sp1 += sizeof(uintptr_t)) {
1144 uintptr_t val = *(uintptr_t*)sp1;
1145 if (val == 0) continue;
1146 if (prev &&
1147 (prev & 0xfff) == 0 && // stack is page aligned
1148 prev < sp && // min stack is < sp
1149 prev + val > sp && // max stack is > sp
1150 val >= (1 << 15) && // stack size is >= 32k
1151 val <= 128 * (1 << 20) // stack size is hardly > 128M
1152 ) {
1153 if (debug_thread) {
1154 Printf("T%d found stack: %p size=%p\n", tid, prev, val);
1155 }
1156 DumpEvent(0, THR_STACK_TOP, tid, pc, prev + val, val);
1157 return;
1158 }
1159 prev = val;
1160 }
1161 // The hack above does not always works. (TODO(kcc)). Do something.
1162 Printf("WARNING: ThreadSanitizerPin is guessing stack size for T%d\n", tid);
1163 DumpEvent(0, THR_STACK_TOP, tid, pc, sp, t.thread_stack_size_if_known);
1164 }
1165
1166 #ifdef _MSC_VER
WRAP_NAME(CreateThread)1167 static uintptr_t WRAP_NAME(CreateThread)(WRAP_PARAM6) {
1168 PinThread &t = g_pin_threads[tid];
1169 t.last_child_stack_size_if_known = arg1 ? arg1 : 1024 * 1024;
1170
1171 HandleThreadCreateBefore(tid, pc);
1172
1173 // We can't start the thread suspended because we want to get its
1174 // PIN thread ID before leaving CreateThread.
1175 // So, we reset the CREATE_SUSPENDED flag and SuspendThread before any client
1176 // code is executed in the HandleThreadCreateAfter if needed.
1177 bool should_be_suspended = arg4 & CREATE_SUSPENDED;
1178 arg4 &= ~CREATE_SUSPENDED;
1179
1180 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_6();
1181 if (ret == NULL) {
1182 HandleThreadCreateAbort(tid);
1183 return ret;
1184 }
1185 pthread_t child_ptid = ret;
1186 THREADID child_tid = HandleThreadCreateAfter(tid, child_ptid,
1187 should_be_suspended);
1188 {
1189 ScopedReentrantClientLock lock(__LINE__);
1190 if (g_win_handles_which_are_threads == NULL) {
1191 g_win_handles_which_are_threads = new unordered_set<pthread_t>;
1192 }
1193 g_win_handles_which_are_threads->insert(child_ptid);
1194 }
1195 return ret;
1196 }
1197
Before_BaseThreadInitThunk(THREADID tid,ADDRINT pc,ADDRINT sp)1198 static void Before_BaseThreadInitThunk(THREADID tid, ADDRINT pc, ADDRINT sp) {
1199 PinThread &t = g_pin_threads[tid];
1200 size_t stack_size = t.thread_stack_size_if_known;
1201 // Printf("T%d %s %p %p\n", tid, __FUNCTION__, sp, stack_size);
1202 /* TODO(timurrrr): investigate and uncomment
1203 if (tid != 0) {
1204 // Ignore all mops & sync before the real thread code.
1205 // See the corresponding IgnoreSyncAndMopsBegin in CallbackForThreadStart.
1206 IgnoreSyncAndMopsEnd(tid);
1207 TLEBFlushLocked(t);
1208 CHECK(t.ignore_sync == 0);
1209 CHECK(t.ignore_accesses == 0);
1210 }
1211 */
1212 DumpEvent(0, THR_STACK_TOP, tid, pc, sp, stack_size);
1213
1214 #ifdef _MSC_VER
1215 if (t.startup_state != PinThread::MAY_CONTINUE) {
1216 CHECK(t.startup_state == PinThread::STARTING);
1217 t.startup_state = PinThread::CHILD_READY;
1218 while (ATOMIC_READ(&t.startup_state) != PinThread::MAY_CONTINUE) {
1219 YIELD();
1220 }
1221 // Corresponds to SIGNAL from ResumeThread if the thread was suspended on
1222 // start.
1223 DumpEvent(0, WAIT, tid, pc, t.my_ptid, 0);
1224 }
1225 #endif
1226 }
1227
Before_RtlExitUserThread(THREADID tid,ADDRINT pc)1228 static void Before_RtlExitUserThread(THREADID tid, ADDRINT pc) {
1229 PinThread &t = g_pin_threads[tid];
1230 if (t.tid != 0) {
1231 // Once we started exiting the thread, ignore the locking events.
1232 // This way we will avoid h-b arcs between unrelated threads.
1233 // We also start ignoring all mops, otherwise we will get tons of race
1234 // reports from the windows guts.
1235 IgnoreSyncAndMopsBegin(tid);
1236 }
1237 }
1238 #endif // _MSC_VER
1239
CallbackForThreadFini(THREADID tid,const CONTEXT * ctxt,INT32 code,void * v)1240 void CallbackForThreadFini(THREADID tid, const CONTEXT *ctxt,
1241 INT32 code, void *v) {
1242 PinThread &t = g_pin_threads[tid];
1243 t.thread_finished = true;
1244 // We can not DumpEvent here,
1245 // due to possible deadlock with PIN's internal lock.
1246 if (debug_thread) {
1247 Printf("T%d Thread finished (ptid=%d)\n", tid, t.my_ptid);
1248 }
1249 }
1250
HandleThreadJoinAfter(THREADID tid,pthread_t joined_ptid)1251 static bool HandleThreadJoinAfter(THREADID tid, pthread_t joined_ptid) {
1252 THREADID joined_tid = kMaxThreads;
1253 int max_uniq_tid_found = -1;
1254
1255 // TODO(timurrrr): walking through g_pin_threads may be slow.
1256 // Do we need to/Can we optimize it?
1257 for (THREADID j = 1; j < kMaxThreads; j++) {
1258 if (g_pin_threads[j].thread_finished == false)
1259 continue;
1260 if (g_pin_threads[j].my_ptid == joined_ptid) {
1261 // We search for the thread with the maximum uniq_tid to work around
1262 // thread HANDLE reuse issues.
1263 if (max_uniq_tid_found < g_pin_threads[j].uniq_tid) {
1264 max_uniq_tid_found = g_pin_threads[j].uniq_tid;
1265 joined_tid = j;
1266 }
1267 }
1268 }
1269 if (joined_tid == kMaxThreads) {
1270 // This may happen in the following case:
1271 // - A non-joinable thread is created and a handle is assigned to it.
1272 // - Since the thread is non-joinable, the handle is then reused
1273 // for some other purpose, e.g. for a WaitableEvent.
1274 // - We did not yet register the thread fini event.
1275 // - We observe WaitForSingleObjectEx(ptid) and think that this is thread
1276 // join event, while it is not.
1277 if (debug_thread)
1278 Printf("T%d JoinAfter returns false! ptid=%d\n", tid, joined_ptid);
1279 return false;
1280 }
1281 CHECK(joined_tid < kMaxThreads);
1282 CHECK(joined_tid > 0);
1283 g_pin_threads[joined_tid].my_ptid = 0;
1284 int joined_uniq_tid = g_pin_threads[joined_tid].uniq_tid;
1285
1286 if (debug_thread) {
1287 Printf("T%d JoinAfter parent=%d child=%d (uniq=%d)\n", tid, tid,
1288 joined_tid, joined_uniq_tid);
1289 }
1290
1291 // Here we send an event for a different thread (joined_tid), which is already
1292 // dead.
1293 DumpEvent(0, THR_END, joined_tid, 0, 0, 0);
1294
1295
1296 DumpEvent(0, THR_JOIN_AFTER, tid, 0, joined_uniq_tid, 0);
1297 return true;
1298 }
1299
WRAP_NAME(pthread_join)1300 static uintptr_t WRAP_NAME(pthread_join)(WRAP_PARAM4) {
1301 if (G_flags->debug_level >= 2)
1302 Printf("T%d in pthread_join %p\n", tid, arg0);
1303 pthread_t joined_ptid = (pthread_t)arg0;
1304 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
1305 HandleThreadJoinAfter(tid, joined_ptid);
1306 if (G_flags->debug_level >= 2)
1307 Printf("T%d out pthread_join %p\n", tid, arg0);
1308 return ret;
1309 }
1310
WRAP_NAME(fwrite)1311 static size_t WRAP_NAME(fwrite)(WRAP_PARAM4) {
1312 void* p = (void*)arg0;
1313 size_t size = (size_t)arg1 * (size_t)arg2;
1314 REPORT_READ_RANGE(p, size);
1315 IgnoreMopsBegin(tid);
1316 size_t ret = CALL_ME_INSIDE_WRAPPER_4();
1317 IgnoreMopsEnd(tid);
1318 return ret;
1319 }
1320
1321 #ifdef _MSC_VER
1322
1323
CallStdCallFun1(CONTEXT * ctx,THREADID tid,AFUNPTR f,uintptr_t arg0)1324 uintptr_t CallStdCallFun1(CONTEXT *ctx, THREADID tid,
1325 AFUNPTR f, uintptr_t arg0) {
1326 uintptr_t ret = 0xdeadbee1;
1327 PIN_CallApplicationFunction(ctx, tid,
1328 CALLINGSTD_STDCALL, (AFUNPTR)(f),
1329 PIN_PARG(uintptr_t), &ret,
1330 PIN_PARG(uintptr_t), arg0,
1331 PIN_PARG_END());
1332 return ret;
1333 }
1334
CallStdCallFun2(CONTEXT * ctx,THREADID tid,AFUNPTR f,uintptr_t arg0,uintptr_t arg1)1335 uintptr_t CallStdCallFun2(CONTEXT *ctx, THREADID tid,
1336 AFUNPTR f, uintptr_t arg0, uintptr_t arg1) {
1337 uintptr_t ret = 0xdeadbee2;
1338 PIN_CallApplicationFunction(ctx, tid,
1339 CALLINGSTD_STDCALL, (AFUNPTR)(f),
1340 PIN_PARG(uintptr_t), &ret,
1341 PIN_PARG(uintptr_t), arg0,
1342 PIN_PARG(uintptr_t), arg1,
1343 PIN_PARG_END());
1344 return ret;
1345 }
1346
CallStdCallFun3(CONTEXT * ctx,THREADID tid,AFUNPTR f,uintptr_t arg0,uintptr_t arg1,uintptr_t arg2)1347 uintptr_t CallStdCallFun3(CONTEXT *ctx, THREADID tid,
1348 AFUNPTR f, uintptr_t arg0, uintptr_t arg1,
1349 uintptr_t arg2) {
1350 uintptr_t ret = 0xdeadbee3;
1351 PIN_CallApplicationFunction(ctx, tid,
1352 CALLINGSTD_STDCALL, (AFUNPTR)(f),
1353 PIN_PARG(uintptr_t), &ret,
1354 PIN_PARG(uintptr_t), arg0,
1355 PIN_PARG(uintptr_t), arg1,
1356 PIN_PARG(uintptr_t), arg2,
1357 PIN_PARG_END());
1358 return ret;
1359 }
1360
CallStdCallFun4(CONTEXT * ctx,THREADID tid,AFUNPTR f,uintptr_t arg0,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3)1361 uintptr_t CallStdCallFun4(CONTEXT *ctx, THREADID tid,
1362 AFUNPTR f, uintptr_t arg0, uintptr_t arg1,
1363 uintptr_t arg2, uintptr_t arg3) {
1364 uintptr_t ret = 0xdeadbee4;
1365 PIN_CallApplicationFunction(ctx, tid,
1366 CALLINGSTD_STDCALL, (AFUNPTR)(f),
1367 PIN_PARG(uintptr_t), &ret,
1368 PIN_PARG(uintptr_t), arg0,
1369 PIN_PARG(uintptr_t), arg1,
1370 PIN_PARG(uintptr_t), arg2,
1371 PIN_PARG(uintptr_t), arg3,
1372 PIN_PARG_END());
1373 return ret;
1374 }
1375
CallStdCallFun5(CONTEXT * ctx,THREADID tid,AFUNPTR f,uintptr_t arg0,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t arg4)1376 uintptr_t CallStdCallFun5(CONTEXT *ctx, THREADID tid,
1377 AFUNPTR f, uintptr_t arg0, uintptr_t arg1,
1378 uintptr_t arg2, uintptr_t arg3,
1379 uintptr_t arg4) {
1380 uintptr_t ret = 0xdeadbee5;
1381 PIN_CallApplicationFunction(ctx, tid,
1382 CALLINGSTD_STDCALL, (AFUNPTR)(f),
1383 PIN_PARG(uintptr_t), &ret,
1384 PIN_PARG(uintptr_t), arg0,
1385 PIN_PARG(uintptr_t), arg1,
1386 PIN_PARG(uintptr_t), arg2,
1387 PIN_PARG(uintptr_t), arg3,
1388 PIN_PARG(uintptr_t), arg4,
1389 PIN_PARG_END());
1390 return ret;
1391 }
1392
CallStdCallFun6(CONTEXT * ctx,THREADID tid,AFUNPTR f,uintptr_t arg0,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t arg4,uintptr_t arg5)1393 uintptr_t CallStdCallFun6(CONTEXT *ctx, THREADID tid,
1394 AFUNPTR f, uintptr_t arg0, uintptr_t arg1,
1395 uintptr_t arg2, uintptr_t arg3,
1396 uintptr_t arg4, uintptr_t arg5) {
1397 uintptr_t ret = 0xdeadbee6;
1398 PIN_CallApplicationFunction(ctx, tid,
1399 CALLINGSTD_STDCALL, (AFUNPTR)(f),
1400 PIN_PARG(uintptr_t), &ret,
1401 PIN_PARG(uintptr_t), arg0,
1402 PIN_PARG(uintptr_t), arg1,
1403 PIN_PARG(uintptr_t), arg2,
1404 PIN_PARG(uintptr_t), arg3,
1405 PIN_PARG(uintptr_t), arg4,
1406 PIN_PARG(uintptr_t), arg5,
1407 PIN_PARG_END());
1408 return ret;
1409 }
1410
CallStdCallFun7(CONTEXT * ctx,THREADID tid,AFUNPTR f,uintptr_t arg0,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t arg4,uintptr_t arg5,uintptr_t arg6)1411 uintptr_t CallStdCallFun7(CONTEXT *ctx, THREADID tid,
1412 AFUNPTR f, uintptr_t arg0, uintptr_t arg1,
1413 uintptr_t arg2, uintptr_t arg3,
1414 uintptr_t arg4, uintptr_t arg5,
1415 uintptr_t arg6) {
1416 uintptr_t ret = 0xdeadbee7;
1417 PIN_CallApplicationFunction(ctx, tid,
1418 CALLINGSTD_STDCALL, (AFUNPTR)(f),
1419 PIN_PARG(uintptr_t), &ret,
1420 PIN_PARG(uintptr_t), arg0,
1421 PIN_PARG(uintptr_t), arg1,
1422 PIN_PARG(uintptr_t), arg2,
1423 PIN_PARG(uintptr_t), arg3,
1424 PIN_PARG(uintptr_t), arg4,
1425 PIN_PARG(uintptr_t), arg5,
1426 PIN_PARG(uintptr_t), arg6,
1427 PIN_PARG_END());
1428 return ret;
1429 }
1430
WRAP_NAME(ResumeThread)1431 uintptr_t WRAP_NAME(ResumeThread)(WRAP_PARAM4) {
1432 // Printf("T%d %s arg0=%p\n", tid, __FUNCTION__, arg0);
1433 DumpEvent(ctx, SIGNAL, tid, pc, arg0, 0);
1434 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1435 return ret;
1436 }
WRAP_NAME(RtlInitializeCriticalSection)1437 uintptr_t WRAP_NAME(RtlInitializeCriticalSection)(WRAP_PARAM4) {
1438 // Printf("T%d pc=%p %s: %p\n", tid, pc, __FUNCTION__+8, arg0);
1439 DumpEvent(ctx, LOCK_CREATE, tid, pc, arg0, 0);
1440 IgnoreSyncAndMopsBegin(tid);
1441 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1442 IgnoreSyncAndMopsEnd(tid);
1443 return ret;
1444 }
WRAP_NAME(RtlInitializeCriticalSectionAndSpinCount)1445 uintptr_t WRAP_NAME(RtlInitializeCriticalSectionAndSpinCount)(WRAP_PARAM4) {
1446 // Printf("T%d pc=%p %s: %p\n", tid, pc, __FUNCTION__+8, arg0);
1447 DumpEvent(ctx, LOCK_CREATE, tid, pc, arg0, 0);
1448 IgnoreSyncAndMopsBegin(tid);
1449 uintptr_t ret = CallStdCallFun2(ctx, tid, f, arg0, arg1);
1450 IgnoreSyncAndMopsEnd(tid);
1451 return ret;
1452 }
WRAP_NAME(RtlInitializeCriticalSectionEx)1453 uintptr_t WRAP_NAME(RtlInitializeCriticalSectionEx)(WRAP_PARAM4) {
1454 // Printf("T%d pc=%p %s: %p\n", tid, pc, __FUNCTION__+8, arg0);
1455 DumpEvent(ctx, LOCK_CREATE, tid, pc, arg0, 0);
1456 IgnoreSyncAndMopsBegin(tid);
1457 uintptr_t ret = CallStdCallFun3(ctx, tid, f, arg0, arg1, arg2);
1458 IgnoreSyncAndMopsEnd(tid);
1459 return ret;
1460 }
WRAP_NAME(RtlDeleteCriticalSection)1461 uintptr_t WRAP_NAME(RtlDeleteCriticalSection)(WRAP_PARAM4) {
1462 // Printf("T%d pc=%p %s: %p\n", tid, pc, __FUNCTION__+8, arg0);
1463 DumpEvent(ctx, LOCK_DESTROY, tid, pc, arg0, 0);
1464 IgnoreSyncAndMopsBegin(tid);
1465 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1466 IgnoreSyncAndMopsEnd(tid);
1467 return ret;
1468 }
WRAP_NAME(RtlEnterCriticalSection)1469 uintptr_t WRAP_NAME(RtlEnterCriticalSection)(WRAP_PARAM4) {
1470 // Printf("T%d pc=%p %s: %p\n", tid, pc, __FUNCTION__+8, arg0);
1471 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1472 DumpEvent(ctx, WRITER_LOCK, tid, pc, arg0, 0);
1473 return ret;
1474 }
WRAP_NAME(RtlTryEnterCriticalSection)1475 uintptr_t WRAP_NAME(RtlTryEnterCriticalSection)(WRAP_PARAM4) {
1476 // Printf("T%d pc=%p %s: %p\n", tid, pc, __FUNCTION__+5, arg0);
1477 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1478 if (ret) {
1479 DumpEvent(ctx, WRITER_LOCK, tid, pc, arg0, 0);
1480 }
1481 return ret;
1482 }
WRAP_NAME(RtlLeaveCriticalSection)1483 uintptr_t WRAP_NAME(RtlLeaveCriticalSection)(WRAP_PARAM4) {
1484 // Printf("T%d pc=%p %s: %p\n", tid, pc, __FUNCTION__+8, arg0);
1485 DumpEvent(ctx, UNLOCK, tid, pc, arg0, 0);
1486 return CallStdCallFun1(ctx, tid, f, arg0);
1487 }
1488
WRAP_NAME(DuplicateHandle)1489 uintptr_t WRAP_NAME(DuplicateHandle)(WRAP_PARAM8) {
1490 Printf("WARNING: DuplicateHandle called for handle 0x%X.\n", arg1);
1491 Printf("Future events on this handle may be processed incorrectly.\n");
1492 return CallStdCallFun7(ctx, tid, f, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
1493 }
1494
WRAP_NAME(SetEvent)1495 uintptr_t WRAP_NAME(SetEvent)(WRAP_PARAM4) {
1496 //Printf("T%d before pc=%p %s: %p\n", tid, pc, __FUNCTION__+8, arg0);
1497 DumpEvent(ctx, SIGNAL, tid, pc, arg0, 0);
1498 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1499 //Printf("T%d after pc=%p %s: %p\n", tid, pc, __FUNCTION__+8, arg0);
1500 return ret;
1501 }
1502
InternalWrapCreateSemaphore(WRAP_PARAM4)1503 uintptr_t InternalWrapCreateSemaphore(WRAP_PARAM4) {
1504 if (arg3 != NULL) {
1505 Printf("WARNING: CreateSemaphore called with lpName='%s'.\n", arg3);
1506 Printf("Future events on this semaphore may be processed incorrectly "
1507 "if it is reused.\n");
1508 }
1509 return CallStdCallFun4(ctx, tid, f, arg0, arg1, arg2, arg3);
1510 }
1511
WRAP_NAME(CreateSemaphoreA)1512 uintptr_t WRAP_NAME(CreateSemaphoreA)(WRAP_PARAM4) {
1513 return InternalWrapCreateSemaphore(tid, pc, ctx, f, arg0, arg1, arg2, arg3);
1514 }
1515
WRAP_NAME(CreateSemaphoreW)1516 uintptr_t WRAP_NAME(CreateSemaphoreW)(WRAP_PARAM4) {
1517 return InternalWrapCreateSemaphore(tid, pc, ctx, f, arg0, arg1, arg2, arg3);
1518 }
1519
WRAP_NAME(ReleaseSemaphore)1520 uintptr_t WRAP_NAME(ReleaseSemaphore)(WRAP_PARAM4) {
1521 DumpEvent(ctx, SIGNAL, tid, pc, arg0, 0);
1522 return CallStdCallFun3(ctx, tid, f, arg0, arg1, arg2);
1523 }
1524
WRAP_NAME(RtlInterlockedPushEntrySList)1525 uintptr_t WRAP_NAME(RtlInterlockedPushEntrySList)(WRAP_PARAM4) {
1526 DumpEvent(ctx, SIGNAL, tid, pc, arg1, 0);
1527 uintptr_t ret = CallStdCallFun2(ctx, tid, f, arg0, arg1);
1528 // Printf("T%d %s list=%p item=%p\n", tid, __FUNCTION__, arg0, arg1);
1529 return ret;
1530 }
1531
WRAP_NAME(RtlInterlockedPopEntrySList)1532 uintptr_t WRAP_NAME(RtlInterlockedPopEntrySList)(WRAP_PARAM4) {
1533 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1534 // Printf("T%d %s list=%p item=%p\n", tid, __FUNCTION__, arg0, ret);
1535 if (ret) {
1536 DumpEvent(ctx, WAIT, tid, pc, ret, 0);
1537 }
1538 return ret;
1539 }
1540
WRAP_NAME(RtlAcquireSRWLockExclusive)1541 uintptr_t WRAP_NAME(RtlAcquireSRWLockExclusive)(WRAP_PARAM4) {
1542 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1543 DumpEvent(ctx, WRITER_LOCK, tid, pc, arg0, 0);
1544 return ret;
1545 }
WRAP_NAME(RtlAcquireSRWLockShared)1546 uintptr_t WRAP_NAME(RtlAcquireSRWLockShared)(WRAP_PARAM4) {
1547 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1548 DumpEvent(ctx, READER_LOCK, tid, pc, arg0, 0);
1549 return ret;
1550 }
WRAP_NAME(RtlTryAcquireSRWLockExclusive)1551 uintptr_t WRAP_NAME(RtlTryAcquireSRWLockExclusive)(WRAP_PARAM4) {
1552 // Printf("T%d %s %p\n", tid, __FUNCTION__, arg0);
1553 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1554 if (ret & 0xFF) { // Looks like this syscall return value is just 1 byte.
1555 DumpEvent(ctx, WRITER_LOCK, tid, pc, arg0, 0);
1556 }
1557 return ret;
1558 }
WRAP_NAME(RtlTryAcquireSRWLockShared)1559 uintptr_t WRAP_NAME(RtlTryAcquireSRWLockShared)(WRAP_PARAM4) {
1560 // Printf("T%d %s %p\n", tid, __FUNCTION__, arg0);
1561 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1562 if (ret & 0xFF) { // Looks like this syscall return value is just 1 byte.
1563 DumpEvent(ctx, READER_LOCK, tid, pc, arg0, 0);
1564 }
1565 return ret;
1566 }
WRAP_NAME(RtlReleaseSRWLockExclusive)1567 uintptr_t WRAP_NAME(RtlReleaseSRWLockExclusive)(WRAP_PARAM4) {
1568 // Printf("T%d %s %p\n", tid, __FUNCTION__, arg0);
1569 DumpEvent(ctx, UNLOCK, tid, pc, arg0, 0);
1570 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1571 return ret;
1572 }
WRAP_NAME(RtlReleaseSRWLockShared)1573 uintptr_t WRAP_NAME(RtlReleaseSRWLockShared)(WRAP_PARAM4) {
1574 // Printf("T%d %s %p\n", tid, __FUNCTION__, arg0);
1575 DumpEvent(ctx, UNLOCK, tid, pc, arg0, 0);
1576 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1577 return ret;
1578 }
WRAP_NAME(RtlInitializeSRWLock)1579 uintptr_t WRAP_NAME(RtlInitializeSRWLock)(WRAP_PARAM4) {
1580 // Printf("T%d %s %p\n", tid, __FUNCTION__, arg0);
1581 DumpEvent(ctx, LOCK_CREATE, tid, pc, arg0, 0);
1582 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1583 return ret;
1584 }
1585
WRAP_NAME(RtlWakeConditionVariable)1586 uintptr_t WRAP_NAME(RtlWakeConditionVariable)(WRAP_PARAM4) {
1587 // Printf("T%d %s arg0=%p\n", tid, __FUNCTION__, arg0);
1588 DumpEvent(ctx, SIGNAL, tid, pc, arg0, 0);
1589 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1590 return ret;
1591 }
WRAP_NAME(RtlWakeAllConditionVariable)1592 uintptr_t WRAP_NAME(RtlWakeAllConditionVariable)(WRAP_PARAM4) {
1593 // Printf("T%d %s arg0=%p\n", tid, __FUNCTION__, arg0);
1594 DumpEvent(ctx, SIGNAL, tid, pc, arg0, 0);
1595 uintptr_t ret = CallStdCallFun1(ctx, tid, f, arg0);
1596 return ret;
1597 }
WRAP_NAME(RtlSleepConditionVariableSRW)1598 uintptr_t WRAP_NAME(RtlSleepConditionVariableSRW)(WRAP_PARAM4) {
1599 // No need to unlock/lock - looks like RtlSleepConditionVariableSRW performs
1600 // Rtl{Acquire,Release}SRW... calls itself!
1601 uintptr_t ret = CallStdCallFun4(ctx, tid, f, arg0, arg1, arg2, arg3);
1602 if ((ret & 0xFF) == 0)
1603 DumpEvent(ctx, WAIT, tid, pc, arg0, 0);
1604 // Printf("T%d %s arg0=%p arg1=%p; ret=%d\n", tid, __FUNCTION__, arg0, arg1, ret);
1605 return ret;
1606 }
WRAP_NAME(RtlSleepConditionVariableCS)1607 uintptr_t WRAP_NAME(RtlSleepConditionVariableCS)(WRAP_PARAM4) {
1608 // TODO(timurrrr): do we need unlock/lock?
1609 uintptr_t ret = CallStdCallFun3(ctx, tid, f, arg0, arg1, arg2);
1610 if ((ret & 0xFF) == 0)
1611 DumpEvent(ctx, WAIT, tid, pc, arg0, 0);
1612 // Printf("T%d %s arg0=%p arg1=%p; ret=%d\n", tid, __FUNCTION__, arg0, arg1, ret);
1613 return ret;
1614 }
1615
WRAP_NAME(RtlQueueWorkItem)1616 uintptr_t WRAP_NAME(RtlQueueWorkItem)(WRAP_PARAM4) {
1617 // Printf("T%d %s arg0=%p arg1=%p; arg2=%d\n", tid, __FUNCTION__, arg0, arg1, arg2);
1618 g_windows_thread_pool_calback_set->insert(arg0);
1619 DumpEvent(ctx, SIGNAL, tid, pc, arg0, 0);
1620 uintptr_t ret = CallStdCallFun3(ctx, tid, f, arg0, arg1, arg2);
1621 return ret;
1622 }
1623
WRAP_NAME(RegisterWaitForSingleObject)1624 uintptr_t WRAP_NAME(RegisterWaitForSingleObject)(WRAP_PARAM6) {
1625 // Printf("T%d %s arg0=%p arg2=%p\n", tid, __FUNCTION__, arg0, arg2);
1626 g_windows_thread_pool_calback_set->insert(arg2);
1627 DumpEvent(ctx, SIGNAL, tid, pc, arg2, 0);
1628 uintptr_t ret = CallStdCallFun6(ctx, tid, f, arg0, arg1, arg2, arg3, arg4, arg5);
1629 if (ret) {
1630 uintptr_t wait_object = *(uintptr_t*)arg0;
1631 (*g_windows_thread_pool_wait_object_map)[wait_object] = arg2;
1632 // Printf("T%d %s *arg0=%p\n", tid, __FUNCTION__, wait_object);
1633 }
1634 return ret;
1635 }
1636
WRAP_NAME(UnregisterWaitEx)1637 uintptr_t WRAP_NAME(UnregisterWaitEx)(WRAP_PARAM4) {
1638 CHECK(g_windows_thread_pool_wait_object_map);
1639 uintptr_t obj = (*g_windows_thread_pool_wait_object_map)[arg0];
1640 // Printf("T%d %s arg0=%p obj=%p\n", tid, __FUNCTION__, arg0, obj);
1641 uintptr_t ret = CallStdCallFun2(ctx, tid, f, arg0, arg1);
1642 if (ret) {
1643 DumpEvent(ctx, WAIT, tid, pc, obj, 0);
1644 }
1645 return ret;
1646 }
1647
WRAP_NAME(VirtualAlloc)1648 uintptr_t WRAP_NAME(VirtualAlloc)(WRAP_PARAM4) {
1649 // Printf("T%d VirtualAlloc: %p %p %p %p\n", tid, arg0, arg1, arg2, arg3);
1650 uintptr_t ret = CallStdCallFun4(ctx, tid, f, arg0, arg1, arg2, arg3);
1651 return ret;
1652 }
1653
WRAP_NAME(GlobalAlloc)1654 uintptr_t WRAP_NAME(GlobalAlloc)(WRAP_PARAM4) {
1655 uintptr_t ret = CallStdCallFun2(ctx, tid, f, arg0, arg1);
1656 // Printf("T%d %s(%p %p)=%p\n", tid, __FUNCTION__, arg0, arg1, ret);
1657 if (ret != 0) {
1658 DumpEvent(ctx, MALLOC, tid, pc, ret, arg1);
1659 }
1660 return ret;
1661 }
1662
WRAP_NAME(ZwAllocateVirtualMemory)1663 uintptr_t WRAP_NAME(ZwAllocateVirtualMemory)(WRAP_PARAM6) {
1664 // Printf("T%d >>%s(%p %p %p %p %p %p)\n", tid, __FUNCTION__, arg0, arg1, arg2, arg3, arg4, arg5);
1665 uintptr_t ret = CallStdCallFun6(ctx, tid, f, arg0, arg1, arg2, arg3, arg4, arg5);
1666 // Printf("T%d <<%s(%p %p) = %p\n", tid, __FUNCTION__, *(void**)arg1, *(void**)arg3, ret);
1667 if (ret == 0) {
1668 DumpEvent(ctx, MALLOC, tid, pc, *(uintptr_t*)arg1, *(uintptr_t*)arg3);
1669 }
1670 return ret;
1671 }
1672
WRAP_NAME(AllocateHeap)1673 uintptr_t WRAP_NAME(AllocateHeap)(WRAP_PARAM4) {
1674 uintptr_t ret = CallStdCallFun3(ctx, tid, f, arg0, arg1, arg2);
1675 // Printf("T%d RtlAllocateHeap(%p %p %p)=%p\n", tid, arg0, arg1, arg2, ret);
1676 if (ret != 0) {
1677 DumpEvent(ctx, MALLOC, tid, pc, ret, arg3);
1678 }
1679 return ret;
1680 }
1681
WRAP_NAME(HeapCreate)1682 uintptr_t WRAP_NAME(HeapCreate)(WRAP_PARAM4) {
1683 uintptr_t ret = CallStdCallFun3(ctx, tid, f, arg0, arg1, arg2);
1684 Printf("T%d %s(%p %p %p)=%p\n", tid, __FUNCTION__, arg0, arg1, arg2, ret);
1685 return ret;
1686 }
1687
1688 // We don't use the definition of WAIT_OBJECT_0 from winbase.h because
1689 // it can't be compiled here for some reason.
1690 #define WAIT_OBJECT_0_ 0
1691
WRAP_NAME(WaitForSingleObjectEx)1692 uintptr_t WRAP_NAME(WaitForSingleObjectEx)(WRAP_PARAM4) {
1693 if (G_flags->verbosity >= 1) {
1694 ShowPcAndSp(__FUNCTION__, tid, pc, 0);
1695 Printf("arg0=%lx arg1=%lx\n", arg0, arg1);
1696 }
1697
1698 //Printf("T%d before pc=%p %s: %p\n", tid, pc, __FUNCTION__+8, arg0, arg1);
1699 uintptr_t ret = CallStdCallFun3(ctx, tid, f, arg0, arg1, arg2);
1700 //Printf("T%d after pc=%p %s: %p\n", tid, pc, __FUNCTION__+8, arg0, arg1);
1701
1702 if (ret == WAIT_OBJECT_0_) {
1703 bool is_thread_handle = false;
1704 {
1705 ScopedReentrantClientLock lock(__LINE__);
1706 if (g_win_handles_which_are_threads) {
1707 is_thread_handle = g_win_handles_which_are_threads->count(arg0) > 0;
1708 g_win_handles_which_are_threads->erase(arg0);
1709 }
1710 }
1711 if (is_thread_handle)
1712 HandleThreadJoinAfter(tid, arg0);
1713 DumpEvent(ctx, WAIT, tid, pc, arg0, 0);
1714 }
1715
1716 return ret;
1717 }
1718
WRAP_NAME(WaitForMultipleObjectsEx)1719 uintptr_t WRAP_NAME(WaitForMultipleObjectsEx)(WRAP_PARAM6) {
1720 if (G_flags->verbosity >= 1) {
1721 ShowPcAndSp(__FUNCTION__, tid, pc, 0);
1722 Printf("arg0=%lx arg1=%lx arg2=%lx arg3=%lx\n", arg0, arg1, arg2, arg3);
1723 }
1724
1725 //Printf("T%d before pc=%p %s: %p\n", tid, pc, __FUNCTION__+8, arg0, arg1);
1726 uintptr_t ret = CallStdCallFun5(ctx, tid, f, arg0, arg1, arg2, arg3, arg4);
1727 //Printf("T%d after pc=%p %s: %p\n", tid, pc, __FUNCTION__+8, arg0, arg1);
1728
1729 if (ret >= WAIT_OBJECT_0_ && ret < WAIT_OBJECT_0_ + arg0) {
1730 // TODO(timurrrr): add support for WAIT_ABANDONED_0
1731
1732 int start_id, count;
1733 if (arg2 /* wait_for_all */ == 1) {
1734 start_id = 0;
1735 count = arg0;
1736 } else {
1737 start_id = ret - WAIT_OBJECT_0_;
1738 count = 1;
1739 }
1740
1741 for (int i = start_id; i < start_id + count; i++) {
1742 uintptr_t handle = ((uintptr_t*)arg1)[i];
1743 bool is_thread_handle = false;
1744 {
1745 ScopedReentrantClientLock lock(__LINE__);
1746 if (g_win_handles_which_are_threads) {
1747 is_thread_handle = g_win_handles_which_are_threads->count(handle) > 0;
1748 g_win_handles_which_are_threads->erase(handle);
1749 }
1750 }
1751 if (is_thread_handle)
1752 HandleThreadJoinAfter(tid, handle);
1753 DumpEvent(ctx, WAIT, tid, pc, handle, 0);
1754 }
1755 }
1756
1757 return ret;
1758 }
1759
1760 #endif // _MSC_VER
1761
1762 //--------- memory allocation ---------------------- {{{2
WRAP_NAME(mmap)1763 uintptr_t WRAP_NAME(mmap)(WRAP_PARAM6) {
1764 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_6();
1765
1766 if (ret != (ADDRINT)-1L) {
1767 DumpEvent(ctx, MMAP, tid, pc, ret, arg1);
1768 }
1769
1770 return ret;
1771 }
1772
WRAP_NAME(munmap)1773 uintptr_t WRAP_NAME(munmap)(WRAP_PARAM4) {
1774 PinThread &t = g_pin_threads[tid];
1775 TLEBFlushLocked(t);
1776 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
1777 if (ret != (uintptr_t)-1L) {
1778 DumpEvent(ctx, MUNMAP, tid, pc, arg0, arg1);
1779 }
1780 return ret;
1781 }
1782
1783
After_malloc(FAST_WRAP_PARAM_AFTER)1784 void After_malloc(FAST_WRAP_PARAM_AFTER) {
1785 size_t size = frame.arg[0];
1786 if (DEBUG_FAST_INTERCEPTORS)
1787 Printf("T%d %s %ld %p\n", tid, __FUNCTION__, size, ret);
1788 IgnoreSyncAndMopsEnd(tid);
1789 DumpEventWithSp(frame.sp, MALLOC, tid, frame.pc, ret, size);
1790 }
1791
Before_malloc(FAST_WRAP_PARAM1)1792 void Before_malloc(FAST_WRAP_PARAM1) {
1793 IgnoreSyncAndMopsBegin(tid);
1794 PUSH_AFTER_CALLBACK1(After_malloc, arg0);
1795 }
1796
After_free(FAST_WRAP_PARAM_AFTER)1797 void After_free(FAST_WRAP_PARAM_AFTER) {
1798 if (DEBUG_FAST_INTERCEPTORS)
1799 Printf("T%d %s %p\n", tid, __FUNCTION__, frame.arg[0]);
1800 IgnoreSyncAndMopsEnd(tid);
1801 }
1802
Before_free(FAST_WRAP_PARAM1)1803 void Before_free(FAST_WRAP_PARAM1) {
1804 DumpEvent(0, FREE, tid, pc, arg0, 0);
1805 IgnoreSyncAndMopsBegin(tid);
1806 PUSH_AFTER_CALLBACK1(After_free, arg0);
1807 }
1808
Before_calloc(FAST_WRAP_PARAM2)1809 void Before_calloc(FAST_WRAP_PARAM2) {
1810 IgnoreSyncAndMopsBegin(tid);
1811 PUSH_AFTER_CALLBACK1(After_malloc, arg0 * arg1);
1812 }
1813
Before_realloc(FAST_WRAP_PARAM2)1814 void Before_realloc(FAST_WRAP_PARAM2) {
1815 IgnoreSyncAndMopsBegin(tid);
1816 // TODO: handle FREE? We don't do it in Valgrind right now.
1817 PUSH_AFTER_CALLBACK1(After_malloc, arg1);
1818 }
1819
1820 // Fast path for INS_InsertIfCall.
Before_RET_IF(THREADID tid,ADDRINT pc,ADDRINT sp,ADDRINT ret)1821 ADDRINT Before_RET_IF(THREADID tid, ADDRINT pc, ADDRINT sp, ADDRINT ret) {
1822 PinThread &t = g_pin_threads[tid];
1823 return t.ic_stack.size();
1824 }
1825
Before_RET_THEN(THREADID tid,ADDRINT pc,ADDRINT sp,ADDRINT ret)1826 void Before_RET_THEN(THREADID tid, ADDRINT pc, ADDRINT sp, ADDRINT ret) {
1827 PinThread &t = g_pin_threads[tid];
1828 if (t.ic_stack.size() == 0) return;
1829 DCHECK(t.ic_stack.size());
1830 InstrumentedCallFrame *frame = t.ic_stack.Top();
1831 if (DEBUG_FAST_INTERCEPTORS) {
1832 Printf("T%d RET pc=%p sp=%p *sp=%p frame.sp=%p stack_size %ld\n",
1833 tid, pc, sp, *(uintptr_t*)sp, frame->sp, t.ic_stack.size());
1834 t.ic_stack.Print();
1835 }
1836 while (frame->sp <= sp) {
1837 if (DEBUG_FAST_INTERCEPTORS)
1838 Printf("pop\n");
1839 frame->callback(tid, *frame, ret);
1840 t.ic_stack.Pop();
1841 if (t.ic_stack.size()) {
1842 frame = t.ic_stack.Top();
1843 } else {
1844 break;
1845 }
1846 }
1847 }
1848
WRAP_NAME(malloc)1849 uintptr_t WRAP_NAME(malloc)(WRAP_PARAM4) {
1850 IgnoreSyncAndMopsBegin(tid);
1851 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
1852 IgnoreSyncAndMopsEnd(tid);
1853
1854 DumpEvent(ctx, MALLOC, tid, pc, ret, arg0);
1855 return ret;
1856 }
1857
WRAP_NAME(realloc)1858 uintptr_t WRAP_NAME(realloc)(WRAP_PARAM4) {
1859 PinThread &t = g_pin_threads[tid];
1860 TLEBFlushLocked(t);
1861 IgnoreSyncAndMopsBegin(tid);
1862 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
1863 IgnoreSyncAndMopsEnd(tid);
1864
1865 // TODO: handle FREE? We don't do it in Valgrind right now.
1866 DumpEvent(ctx, MALLOC, tid, pc, ret, arg1);
1867 return ret;
1868 }
1869
WRAP_NAME(calloc)1870 uintptr_t WRAP_NAME(calloc)(WRAP_PARAM4) {
1871 IgnoreSyncAndMopsBegin(tid);
1872 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
1873 IgnoreSyncAndMopsEnd(tid);
1874
1875 DumpEvent(ctx, MALLOC, tid, pc, ret, arg0*arg1);
1876 return ret;
1877 }
1878
WRAP_NAME(free)1879 uintptr_t WRAP_NAME(free)(WRAP_PARAM4) {
1880 DumpEvent(ctx, FREE, tid, pc, arg0, 0);
1881
1882 IgnoreSyncAndMopsBegin(tid);
1883 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
1884 IgnoreSyncAndMopsEnd(tid);
1885 return ret;
1886 }
1887
1888
1889 //-------- Routines and stack ---------------------- {{{2
UpdateCallStack(PinThread & t,ADDRINT sp)1890 static INLINE void UpdateCallStack(PinThread &t, ADDRINT sp) {
1891 while (t.shadow_stack.size() > 0 && sp >= t.shadow_stack.back().sp) {
1892 TLEBAddRtnExit(t);
1893 size_t size = t.shadow_stack.size();
1894 CHECK(size < 1000000); // stay sane.
1895 uintptr_t popped_pc = t.shadow_stack.back().pc;
1896 #ifdef _MSC_VER
1897 // h-b edge from here to UnregisterWaitEx.
1898 CHECK(g_windows_thread_pool_calback_set);
1899 if (g_windows_thread_pool_calback_set->count(popped_pc)) {
1900 DumpEvent(0, SIGNAL, t.tid, 0, popped_pc, 0);
1901 // Printf("T%d ret %p\n", t.tid, popped_pc);
1902 }
1903 #endif
1904
1905 if (debug_rtn) {
1906 ShowPcAndSp("RET : ", t.tid, popped_pc, sp);
1907 }
1908 t.shadow_stack.pop_back();
1909 CHECK(size - 1 == t.shadow_stack.size());
1910 if (DEB_PR) {
1911 Printf("POP SHADOW STACK\n");
1912 PrintShadowStack(t);
1913 }
1914 }
1915 }
1916
InsertBeforeEvent_SysCall(THREADID tid,ADDRINT sp)1917 void InsertBeforeEvent_SysCall(THREADID tid, ADDRINT sp) {
1918 PinThread &t = g_pin_threads[tid];
1919 UpdateCallStack(t, sp);
1920 TLEBFlushLocked(t);
1921 }
1922
InsertBeforeEvent_Call(THREADID tid,ADDRINT pc,ADDRINT target,ADDRINT sp,IGNORE_BELOW_RTN ignore_below)1923 void InsertBeforeEvent_Call(THREADID tid, ADDRINT pc, ADDRINT target,
1924 ADDRINT sp, IGNORE_BELOW_RTN ignore_below) {
1925 PinThread &t = g_pin_threads[tid];
1926 DebugOnlyShowPcAndSp(__FUNCTION__, t.tid, pc, sp);
1927 UpdateCallStack(t, sp);
1928 TLEBAddRtnCall(t, pc, target, ignore_below);
1929 t.shadow_stack.push_back(StackFrame(target, sp));
1930 if (DEB_PR) {
1931 PrintShadowStack(t);
1932 }
1933 if (DEBUG_MODE && debug_rtn) {
1934 ShowPcAndSp("CALL: ", t.tid, target, sp);
1935 }
1936
1937 #ifdef _MSC_VER
1938 // h-b edge from RtlQueueWorkItem to here.
1939 CHECK(g_windows_thread_pool_calback_set);
1940 if (g_windows_thread_pool_calback_set->count(target)) {
1941 DumpEvent(0, WAIT, tid, pc, target, 0);
1942 }
1943 #endif
1944 }
1945
OnTraceSerial(THREADID tid,ADDRINT sp,TraceInfo * trace_info,uintptr_t ** tls_reg_p)1946 static void OnTraceSerial(THREADID tid, ADDRINT sp, TraceInfo *trace_info,
1947 uintptr_t **tls_reg_p) {
1948 PinThread &t = g_pin_threads[tid];
1949
1950 DCHECK(trace_info);
1951 DCHECK(trace_info->n_mops() > 0);
1952 DebugOnlyShowPcAndSp(__FUNCTION__, t.tid, trace_info->pc(), sp);
1953
1954 UpdateCallStack(t, sp);
1955
1956 t.trace_info = trace_info;
1957 trace_info->counter()++;
1958 *tls_reg_p = TLEBAddTrace(t);
1959 }
1960
OnTraceParallel(uintptr_t * tls_reg,ADDRINT sp,TraceInfo * trace_info)1961 static void OnTraceParallel(uintptr_t *tls_reg, ADDRINT sp, TraceInfo *trace_info) {
1962 // Get the thread handler directly from tls_reg.
1963 PinThread &t = *(PinThread*)(tls_reg - 4);
1964 t.trace_info = trace_info;
1965 if (t.ignore_accesses) return;
1966
1967 DCHECK(trace_info);
1968 DCHECK(trace_info->n_mops() > 0);
1969 DebugOnlyShowPcAndSp(__FUNCTION__, t.tid, trace_info->pc(), sp);
1970
1971 UpdateCallStack(t, sp);
1972
1973
1974 if (DEBUG_MODE && G_flags->show_stats) // this stat may be racey; avoid ping-pong.
1975 trace_info->counter()++;
1976 TLEBAddTrace(t);
1977 }
1978
1979 /* Verify all mop accesses in the last trace of the given thread by registering
1980 them with RaceVerifier and sleeping a bit. */
OnTraceVerifyInternal(PinThread & t,uintptr_t ** tls_reg_p)1981 static void OnTraceVerifyInternal(PinThread &t, uintptr_t **tls_reg_p) {
1982 DCHECK(g_race_verifier_active);
1983 if (t.trace_info) {
1984 int need_sleep = 0;
1985 for (unsigned i = 0; i < t.trace_info->n_mops(); ++i) {
1986 uintptr_t addr = (*tls_reg_p)[i];
1987 if (addr) {
1988 MopInfo *mop = t.trace_info->GetMop(i);
1989 need_sleep += RaceVerifierStartAccess(t.uniq_tid, addr, mop->pc(),
1990 mop->is_write());
1991 }
1992 }
1993
1994 if (!need_sleep)
1995 return;
1996
1997 usleep(G_flags->race_verifier_sleep_ms * 1000);
1998
1999 for (unsigned i = 0; i < t.trace_info->n_mops(); ++i) {
2000 uintptr_t addr = (*tls_reg_p)[i];
2001 if (addr) {
2002 MopInfo *mop = t.trace_info->GetMop(i);
2003 RaceVerifierEndAccess(t.uniq_tid, addr, mop->pc(), mop->is_write());
2004 }
2005 }
2006 }
2007 }
2008
OnTraceNoMopsVerify(THREADID tid,ADDRINT sp,uintptr_t ** tls_reg_p)2009 static void OnTraceNoMopsVerify(THREADID tid, ADDRINT sp,
2010 uintptr_t **tls_reg_p) {
2011 PinThread &t = g_pin_threads[tid];
2012 DCHECK(g_race_verifier_active);
2013 OnTraceVerifyInternal(t, tls_reg_p);
2014 t.trace_info = NULL;
2015 }
2016
OnTraceVerify(THREADID tid,ADDRINT sp,TraceInfo * trace_info,uintptr_t ** tls_reg_p)2017 static void OnTraceVerify(THREADID tid, ADDRINT sp, TraceInfo *trace_info,
2018 uintptr_t **tls_reg_p) {
2019 DCHECK(g_race_verifier_active);
2020 PinThread &t = g_pin_threads[tid];
2021 OnTraceVerifyInternal(t, tls_reg_p);
2022
2023 DCHECK(trace_info->n_mops() > 0);
2024
2025 t.trace_info = trace_info;
2026 trace_info->counter()++;
2027 *tls_reg_p = TLEBAddTrace(t);
2028 }
2029
2030
2031 //---------- Memory accesses -------------------------- {{{2
2032 // 'addr' is the section of t.tleb.events which is set in OnTrace.
2033 // 'idx' is the number of this mop in its trace.
2034 // 'a' is the actuall address.
2035 // 'tid' is thread ID, used only in debug mode.
2036 //
2037 // In opt mode this is just one instruction! Something like this:
2038 // mov %rcx,(%rdi,%rdx,8)
OnMop(uintptr_t * addr,THREADID tid,ADDRINT idx,ADDRINT a)2039 static void OnMop(uintptr_t *addr, THREADID tid, ADDRINT idx, ADDRINT a) {
2040 if (DEBUG_MODE) {
2041 PinThread &t= g_pin_threads[tid];
2042 CHECK(idx < kMaxMopsPerTrace);
2043 CHECK(idx < t.trace_info->n_mops());
2044 uintptr_t *ptr = addr + idx;
2045 CHECK(ptr >= t.tleb.events);
2046 CHECK(ptr < t.tleb.events + kThreadLocalEventBufferSize);
2047 if (a == G_flags->trace_addr) {
2048 Printf("T%d %s %lx\n", t.tid, __FUNCTION__, a);
2049 }
2050 }
2051 addr[idx] = a;
2052 }
2053
On_PredicatedMop(BOOL is_running,uintptr_t * addr,THREADID tid,ADDRINT idx,ADDRINT a)2054 static void On_PredicatedMop(BOOL is_running, uintptr_t *addr,
2055 THREADID tid, ADDRINT idx, ADDRINT a) {
2056 if (is_running) {
2057 OnMop(addr, tid, idx, a);
2058 }
2059 }
2060
OnMopCheckIdentStoreBefore(uintptr_t * addr,THREADID tid,ADDRINT idx,ADDRINT a)2061 static void OnMopCheckIdentStoreBefore(uintptr_t *addr, THREADID tid, ADDRINT idx, ADDRINT a) {
2062 // Write the value of *a to tleb.
2063 addr[idx] = *(uintptr_t*)a;
2064 }
OnMopCheckIdentStoreAfter(uintptr_t * addr,THREADID tid,ADDRINT idx,ADDRINT a)2065 static void OnMopCheckIdentStoreAfter(uintptr_t *addr, THREADID tid, ADDRINT idx, ADDRINT a) {
2066 // Check if the previous value of *a is equal to the new one.
2067 // If not, we have a regular memory access. If yes, we have an ident operation,
2068 // which we want to ignore.
2069 uintptr_t previous_value_of_a = addr[idx];
2070 uintptr_t new_value_of_a = *(uintptr_t*)a;
2071 // 111...111 if the values are different, 0 otherwise.
2072 uintptr_t ne_mask = -(uintptr_t)(new_value_of_a != previous_value_of_a);
2073 addr[idx] = ne_mask & a;
2074 }
2075
2076 //---------- I/O; exit------------------------------- {{{2
2077 static const uintptr_t kIOMagic = 0x1234c678;
2078
Before_SignallingIOCall(THREADID tid,ADDRINT pc)2079 static void Before_SignallingIOCall(THREADID tid, ADDRINT pc) {
2080 DumpEvent(0, SIGNAL, tid, pc, kIOMagic, 0);
2081 }
2082
After_WaitingIOCall(THREADID tid,ADDRINT pc)2083 static void After_WaitingIOCall(THREADID tid, ADDRINT pc) {
2084 DumpEvent(0, WAIT, tid, pc, kIOMagic, 0);
2085 }
2086
2087 static const uintptr_t kAtexitMagic = 0x9876f432;
2088
On_atexit(THREADID tid,ADDRINT pc)2089 static void On_atexit(THREADID tid, ADDRINT pc) {
2090 DumpEvent(0, SIGNAL, tid, pc, kAtexitMagic, 0);
2091 }
2092
On_exit(THREADID tid,ADDRINT pc)2093 static void On_exit(THREADID tid, ADDRINT pc) {
2094 DumpEvent(0, WAIT, tid, pc, kAtexitMagic, 0);
2095 }
2096
2097 //---------- Synchronization -------------------------- {{{2
2098 // locks
Before_pthread_unlock(THREADID tid,ADDRINT pc,ADDRINT mu)2099 static void Before_pthread_unlock(THREADID tid, ADDRINT pc, ADDRINT mu) {
2100 DumpEvent(0, UNLOCK, tid, pc, mu, 0);
2101 }
2102
After_pthread_mutex_lock(FAST_WRAP_PARAM_AFTER)2103 static void After_pthread_mutex_lock(FAST_WRAP_PARAM_AFTER) {
2104 DumpEventWithSp(frame.sp, WRITER_LOCK, tid, frame.pc, frame.arg[0], 0);
2105 }
2106
Before_pthread_mutex_lock(FAST_WRAP_PARAM1)2107 static void Before_pthread_mutex_lock(FAST_WRAP_PARAM1) {
2108 PUSH_AFTER_CALLBACK1(After_pthread_mutex_lock, arg0);
2109 }
2110
2111 // In some versions of libpthread, pthread_spin_lock is effectively
2112 // a recursive function. It jumps to its first insn:
2113 // beb0: f0 ff 0f lock decl (%rdi)
2114 // beb3: 75 0b jne bec0 <pthread_spin_lock+0x10>
2115 // beb5: 31 c0 xor %eax,%eax
2116 // beb7: c3 retq
2117 // beb8: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
2118 // bebf: 00
2119 // bec0: f3 90 pause
2120 // bec2: 83 3f 00 cmpl $0x0,(%rdi)
2121 // bec5: 7f e9 >>>>>>>>>>>>> jg beb0 <pthread_spin_lock>
2122 // bec7: eb f7 jmp bec0 <pthread_spin_lock+0x10>
2123 //
2124 // So, we need to act only when we return from the last (depth=0) invocation.
WRAP_NAME(pthread_spin_lock)2125 static uintptr_t WRAP_NAME(pthread_spin_lock)(WRAP_PARAM4) {
2126 PinThread &t= g_pin_threads[tid];
2127 t.spin_lock_recursion_depth++;
2128 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2129 t.spin_lock_recursion_depth--;
2130 if (t.spin_lock_recursion_depth == 0) {
2131 DumpEvent(ctx, WRITER_LOCK, tid, pc, arg0, 0);
2132 }
2133 return ret;
2134 }
2135
WRAP_NAME(pthread_rwlock_wrlock)2136 static uintptr_t WRAP_NAME(pthread_rwlock_wrlock)(WRAP_PARAM4) {
2137 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2138 DumpEvent(ctx, WRITER_LOCK, tid, pc, arg0, 0);
2139 return ret;
2140 }
2141
WRAP_NAME(pthread_rwlock_rdlock)2142 static uintptr_t WRAP_NAME(pthread_rwlock_rdlock)(WRAP_PARAM4) {
2143 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2144 DumpEvent(ctx, READER_LOCK, tid, pc, arg0, 0);
2145 return ret;
2146 }
2147
WRAP_NAME(pthread_mutex_trylock)2148 static uintptr_t WRAP_NAME(pthread_mutex_trylock)(WRAP_PARAM4) {
2149 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2150 if (ret == 0)
2151 DumpEvent(ctx, WRITER_LOCK, tid, pc, arg0, 0);
2152 return ret;
2153 }
2154
WRAP_NAME(pthread_spin_trylock)2155 static uintptr_t WRAP_NAME(pthread_spin_trylock)(WRAP_PARAM4) {
2156 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2157 if (ret == 0)
2158 DumpEvent(ctx, WRITER_LOCK, tid, pc, arg0, 0);
2159 return ret;
2160 }
2161
WRAP_NAME(pthread_spin_init)2162 static uintptr_t WRAP_NAME(pthread_spin_init)(WRAP_PARAM4) {
2163 DumpEvent(ctx, UNLOCK_OR_INIT, tid, pc, arg0, 0);
2164 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2165 return ret;
2166 }
WRAP_NAME(pthread_spin_destroy)2167 static uintptr_t WRAP_NAME(pthread_spin_destroy)(WRAP_PARAM4) {
2168 DumpEvent(ctx, LOCK_DESTROY, tid, pc, arg0, 0);
2169 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2170 return ret;
2171 }
WRAP_NAME(pthread_spin_unlock)2172 static uintptr_t WRAP_NAME(pthread_spin_unlock)(WRAP_PARAM4) {
2173 DumpEvent(ctx, UNLOCK_OR_INIT, tid, pc, arg0, 0);
2174 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2175 return ret;
2176 }
2177
WRAP_NAME(pthread_rwlock_trywrlock)2178 static uintptr_t WRAP_NAME(pthread_rwlock_trywrlock)(WRAP_PARAM4) {
2179 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2180 if (ret == 0)
2181 DumpEvent(ctx, WRITER_LOCK, tid, pc, arg0, 0);
2182 return ret;
2183 }
2184
WRAP_NAME(pthread_rwlock_tryrdlock)2185 static uintptr_t WRAP_NAME(pthread_rwlock_tryrdlock)(WRAP_PARAM4) {
2186 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2187 if (ret == 0)
2188 DumpEvent(ctx, READER_LOCK, tid, pc, arg0, 0);
2189 return ret;
2190 }
2191
2192
Before_pthread_mutex_init(THREADID tid,ADDRINT pc,ADDRINT mu)2193 static void Before_pthread_mutex_init(THREADID tid, ADDRINT pc, ADDRINT mu) {
2194 DumpEvent(0, LOCK_CREATE, tid, pc, mu, 0);
2195 }
Before_pthread_rwlock_init(THREADID tid,ADDRINT pc,ADDRINT mu)2196 static void Before_pthread_rwlock_init(THREADID tid, ADDRINT pc, ADDRINT mu) {
2197 DumpEvent(0, LOCK_CREATE, tid, pc, mu, 0);
2198 }
2199
Before_pthread_mutex_destroy(THREADID tid,ADDRINT pc,ADDRINT mu)2200 static void Before_pthread_mutex_destroy(THREADID tid, ADDRINT pc, ADDRINT mu) {
2201 DumpEvent(0, LOCK_DESTROY, tid, pc, mu, 0);
2202 }
Before_pthread_rwlock_destroy(THREADID tid,ADDRINT pc,ADDRINT mu)2203 static void Before_pthread_rwlock_destroy(THREADID tid, ADDRINT pc, ADDRINT mu) {
2204 DumpEvent(0, LOCK_DESTROY, tid, pc, mu, 0);
2205 }
2206
2207 // barrier
WRAP_NAME(pthread_barrier_init)2208 static uintptr_t WRAP_NAME(pthread_barrier_init)(WRAP_PARAM4) {
2209 DumpEvent(ctx, CYCLIC_BARRIER_INIT, tid, pc, arg0, arg2);
2210 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2211 return ret;
2212 }
WRAP_NAME(pthread_barrier_wait)2213 static uintptr_t WRAP_NAME(pthread_barrier_wait)(WRAP_PARAM4) {
2214 DumpEvent(ctx, CYCLIC_BARRIER_WAIT_BEFORE, tid, pc, arg0, 0);
2215 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2216 DumpEvent(ctx, CYCLIC_BARRIER_WAIT_AFTER, tid, pc, arg0, 0);
2217 return ret;
2218 }
2219
2220
2221 // condvar
Before_pthread_cond_signal(THREADID tid,ADDRINT pc,ADDRINT cv)2222 static void Before_pthread_cond_signal(THREADID tid, ADDRINT pc, ADDRINT cv) {
2223 DumpEvent(0, SIGNAL, tid, pc, cv, 0);
2224 }
2225
WRAP_NAME(pthread_cond_wait)2226 static uintptr_t WRAP_NAME(pthread_cond_wait)(WRAP_PARAM4) {
2227 DumpEvent(ctx, UNLOCK, tid, pc, arg1, 0);
2228 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2229 DumpEvent(ctx, WAIT, tid, pc, arg0, 0);
2230 DumpEvent(ctx, WRITER_LOCK, tid, pc, arg1, 0);
2231 return ret;
2232 }
WRAP_NAME(pthread_cond_timedwait)2233 static uintptr_t WRAP_NAME(pthread_cond_timedwait)(WRAP_PARAM4) {
2234 DumpEvent(ctx, UNLOCK, tid, pc, arg1, 0);
2235 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2236 if (ret == 0) {
2237 DumpEvent(ctx, WAIT, tid, pc, arg0, 0);
2238 }
2239 DumpEvent(ctx, WRITER_LOCK, tid, pc, arg1, 0);
2240 return ret;
2241 }
2242
2243 // epoll
2244 static const uintptr_t kSocketMagic = 0xDEADFBAD;
2245
Before_epoll_ctl(THREADID tid,ADDRINT pc)2246 static void Before_epoll_ctl(THREADID tid, ADDRINT pc) {
2247 DumpEvent(0, SIGNAL, tid, pc, kSocketMagic, 0);
2248 }
2249
After_epoll_wait(THREADID tid,ADDRINT pc)2250 static void After_epoll_wait(THREADID tid, ADDRINT pc) {
2251 DumpEvent(0, WAIT, tid, pc, kSocketMagic, 0);
2252 }
2253
2254 // sem
After_sem_open(THREADID tid,ADDRINT pc,ADDRINT ret)2255 static void After_sem_open(THREADID tid, ADDRINT pc, ADDRINT ret) {
2256 // TODO(kcc): need to handle it more precise?
2257 DumpEvent(0, SIGNAL, tid, pc, ret, 0);
2258 }
Before_sem_post(THREADID tid,ADDRINT pc,ADDRINT sem)2259 static void Before_sem_post(THREADID tid, ADDRINT pc, ADDRINT sem) {
2260 DumpEvent(0, SIGNAL, tid, pc, sem, 0);
2261 }
2262
WRAP_NAME(sem_wait)2263 static uintptr_t WRAP_NAME(sem_wait)(WRAP_PARAM4) {
2264 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2265 DumpEvent(ctx, WAIT, tid, pc, arg0, 0);
2266 return ret;
2267 }
WRAP_NAME(sem_trywait)2268 static uintptr_t WRAP_NAME(sem_trywait)(WRAP_PARAM4) {
2269 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2270 if (ret == 0) {
2271 DumpEvent(ctx, WAIT, tid, pc, arg0, 0);
2272 }
2273 return ret;
2274 }
2275
2276 // etc
2277 #if defined(__GNUC__)
WRAP_NAME(lockf)2278 uintptr_t WRAP_NAME(lockf)(WRAP_PARAM4) {
2279 const long offset_magic = 0xFEB0ACC0;
2280
2281 if (arg1 == F_ULOCK)
2282 DumpEvent(ctx, UNLOCK, tid, pc, arg0 ^ offset_magic, 0);
2283
2284 uintptr_t ret = CALL_ME_INSIDE_WRAPPER_4();
2285
2286 if (arg1 == F_LOCK && ret == 0)
2287 DumpEvent(ctx, WRITER_LOCK, tid, pc, arg0 ^ offset_magic, 0);
2288
2289 return ret;
2290 }
2291 #endif
2292
2293 //--------- Annotations -------------------------- {{{2
On_AnnotateBenignRace(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT a,ADDRINT descr)2294 static void On_AnnotateBenignRace(THREADID tid, ADDRINT pc,
2295 ADDRINT file, ADDRINT line,
2296 ADDRINT a, ADDRINT descr) {
2297 DumpEvent(0, BENIGN_RACE, tid, descr, a, 1);
2298 }
2299
On_AnnotateBenignRaceSized(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT a,ADDRINT size,ADDRINT descr)2300 static void On_AnnotateBenignRaceSized(THREADID tid, ADDRINT pc,
2301 ADDRINT file, ADDRINT line,
2302 ADDRINT a, ADDRINT size, ADDRINT descr) {
2303 DumpEvent(0, BENIGN_RACE, tid, descr, a, size);
2304 }
2305
On_AnnotateExpectRace(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT a,ADDRINT descr)2306 static void On_AnnotateExpectRace(THREADID tid, ADDRINT pc,
2307 ADDRINT file, ADDRINT line,
2308 ADDRINT a, ADDRINT descr) {
2309 DumpEvent(0, EXPECT_RACE, tid, descr, a, 1);
2310 }
2311
On_AnnotateFlushExpectedRaces(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line)2312 static void On_AnnotateFlushExpectedRaces(THREADID tid, ADDRINT pc,
2313 ADDRINT file, ADDRINT line) {
2314 DumpEvent(0, FLUSH_EXPECTED_RACES, 0, 0, 0, 0);
2315 }
2316
2317
On_AnnotateTraceMemory(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT a)2318 static void On_AnnotateTraceMemory(THREADID tid, ADDRINT pc,
2319 ADDRINT file, ADDRINT line,
2320 ADDRINT a) {
2321 DumpEvent(0, TRACE_MEM, tid, pc, a, 0);
2322 }
2323
On_AnnotateNewMemory(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT a,ADDRINT size)2324 static void On_AnnotateNewMemory(THREADID tid, ADDRINT pc,
2325 ADDRINT file, ADDRINT line,
2326 ADDRINT a, ADDRINT size) {
2327 DumpEvent(0, MALLOC, tid, pc, a, size);
2328 }
2329
On_AnnotateNoOp(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT a)2330 static void On_AnnotateNoOp(THREADID tid, ADDRINT pc,
2331 ADDRINT file, ADDRINT line, ADDRINT a) {
2332 Printf("%s T%d: %s:%d %p\n", __FUNCTION__, tid, (char*)file, (int)line, a);
2333 //DumpEvent(0, STACK_TRACE, tid, pc, 0, 0);
2334 // PrintShadowStack(tid);
2335 }
2336
On_AnnotateFlushState(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line)2337 static void On_AnnotateFlushState(THREADID tid, ADDRINT pc,
2338 ADDRINT file, ADDRINT line) {
2339 DumpEvent(0, FLUSH_STATE, tid, pc, 0, 0);
2340 }
2341
On_AnnotateCondVarSignal(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT obj)2342 static void On_AnnotateCondVarSignal(THREADID tid, ADDRINT pc,
2343 ADDRINT file, ADDRINT line, ADDRINT obj) {
2344 DumpEvent(0, SIGNAL, tid, pc, obj, 0);
2345 }
2346
On_AnnotateCondVarWait(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT obj)2347 static void On_AnnotateCondVarWait(THREADID tid, ADDRINT pc,
2348 ADDRINT file, ADDRINT line, ADDRINT obj) {
2349 DumpEvent(0, WAIT, tid, pc, obj, 0);
2350 }
2351
On_AnnotateHappensBefore(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT obj)2352 static void On_AnnotateHappensBefore(THREADID tid, ADDRINT pc,
2353 ADDRINT file, ADDRINT line, ADDRINT obj) {
2354 DumpEvent(0, SIGNAL, tid, pc, obj, 0);
2355 }
2356
On_AnnotateHappensAfter(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT obj)2357 static void On_AnnotateHappensAfter(THREADID tid, ADDRINT pc,
2358 ADDRINT file, ADDRINT line, ADDRINT obj) {
2359 DumpEvent(0, WAIT, tid, pc, obj, 0);
2360 }
2361
On_AnnotateEnableRaceDetection(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT enable)2362 static void On_AnnotateEnableRaceDetection(THREADID tid, ADDRINT pc,
2363 ADDRINT file, ADDRINT line,
2364 ADDRINT enable) {
2365 if (!g_race_verifier_active)
2366 TLEBSimpleEvent(g_pin_threads[tid],
2367 enable ? TLEB_GLOBAL_IGNORE_OFF : TLEB_GLOBAL_IGNORE_ON);
2368 }
2369
On_AnnotateIgnoreReadsBegin(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line)2370 static void On_AnnotateIgnoreReadsBegin(THREADID tid, ADDRINT pc,
2371 ADDRINT file, ADDRINT line) {
2372 DumpEvent(0, IGNORE_READS_BEG, tid, pc, 0, 0);
2373 }
On_AnnotateIgnoreReadsEnd(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line)2374 static void On_AnnotateIgnoreReadsEnd(THREADID tid, ADDRINT pc,
2375 ADDRINT file, ADDRINT line) {
2376 DumpEvent(0, IGNORE_READS_END, tid, pc, 0, 0);
2377 }
On_AnnotateIgnoreWritesBegin(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line)2378 static void On_AnnotateIgnoreWritesBegin(THREADID tid, ADDRINT pc,
2379 ADDRINT file, ADDRINT line) {
2380 DumpEvent(0, IGNORE_WRITES_BEG, tid, pc, 0, 0);
2381 }
On_AnnotateIgnoreWritesEnd(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line)2382 static void On_AnnotateIgnoreWritesEnd(THREADID tid, ADDRINT pc,
2383 ADDRINT file, ADDRINT line) {
2384 DumpEvent(0, IGNORE_WRITES_END, tid, pc, 0, 0);
2385 }
On_AnnotateThreadName(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT name)2386 static void On_AnnotateThreadName(THREADID tid, ADDRINT pc,
2387 ADDRINT file, ADDRINT line,
2388 ADDRINT name) {
2389 DumpEvent(0, SET_THREAD_NAME, tid, pc, name, 0);
2390 }
On_AnnotatePublishMemoryRange(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT a,ADDRINT size)2391 static void On_AnnotatePublishMemoryRange(THREADID tid, ADDRINT pc,
2392 ADDRINT file, ADDRINT line,
2393 ADDRINT a, ADDRINT size) {
2394 DumpEvent(0, PUBLISH_RANGE, tid, pc, a, size);
2395 }
2396
On_AnnotateUnpublishMemoryRange(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT a,ADDRINT size)2397 static void On_AnnotateUnpublishMemoryRange(THREADID tid, ADDRINT pc,
2398 ADDRINT file, ADDRINT line,
2399 ADDRINT a, ADDRINT size) {
2400 // Printf("T%d %s %lx %lx\n", tid, __FUNCTION__, a, size);
2401 DumpEvent(0, UNPUBLISH_RANGE, tid, pc, a, size);
2402 }
2403
2404
On_AnnotateMutexIsUsedAsCondVar(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT mu)2405 static void On_AnnotateMutexIsUsedAsCondVar(THREADID tid, ADDRINT pc,
2406 ADDRINT file, ADDRINT line,
2407 ADDRINT mu) {
2408 DumpEvent(0, HB_LOCK, tid, pc, mu, 0);
2409 }
2410
On_AnnotateMutexIsNotPhb(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT mu)2411 static void On_AnnotateMutexIsNotPhb(THREADID tid, ADDRINT pc,
2412 ADDRINT file, ADDRINT line,
2413 ADDRINT mu) {
2414 DumpEvent(0, NON_HB_LOCK, tid, pc, mu, 0);
2415 }
2416
On_AnnotatePCQCreate(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT pcq)2417 static void On_AnnotatePCQCreate(THREADID tid, ADDRINT pc,
2418 ADDRINT file, ADDRINT line,
2419 ADDRINT pcq) {
2420 DumpEvent(0, PCQ_CREATE, tid, pc, pcq, 0);
2421 }
2422
On_AnnotatePCQDestroy(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT pcq)2423 static void On_AnnotatePCQDestroy(THREADID tid, ADDRINT pc,
2424 ADDRINT file, ADDRINT line,
2425 ADDRINT pcq) {
2426 DumpEvent(0, PCQ_DESTROY, tid, pc, pcq, 0);
2427 }
2428
On_AnnotatePCQPut(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT pcq)2429 static void On_AnnotatePCQPut(THREADID tid, ADDRINT pc,
2430 ADDRINT file, ADDRINT line,
2431 ADDRINT pcq) {
2432 DumpEvent(0, PCQ_PUT, tid, pc, pcq, 0);
2433 }
2434
On_AnnotatePCQGet(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT pcq)2435 static void On_AnnotatePCQGet(THREADID tid, ADDRINT pc,
2436 ADDRINT file, ADDRINT line,
2437 ADDRINT pcq) {
2438 DumpEvent(0, PCQ_GET, tid, pc, pcq, 0);
2439 }
2440
On_AnnotateRWLockCreate(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT lock)2441 static void On_AnnotateRWLockCreate(THREADID tid, ADDRINT pc,
2442 ADDRINT file, ADDRINT line,
2443 ADDRINT lock) {
2444 DumpEvent(0, LOCK_CREATE, tid, pc, lock, 0);
2445 }
2446
On_AnnotateRWLockDestroy(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT lock)2447 static void On_AnnotateRWLockDestroy(THREADID tid, ADDRINT pc,
2448 ADDRINT file, ADDRINT line,
2449 ADDRINT lock) {
2450 DumpEvent(0, LOCK_DESTROY, tid, pc, lock, 0);
2451 }
2452
On_AnnotateRWLockAcquired(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT lock,ADDRINT is_w)2453 static void On_AnnotateRWLockAcquired(THREADID tid, ADDRINT pc,
2454 ADDRINT file, ADDRINT line,
2455 ADDRINT lock, ADDRINT is_w) {
2456 DumpEvent(0, is_w ? WRITER_LOCK : READER_LOCK, tid, pc, lock, 0);
2457 }
2458
On_AnnotateRWLockReleased(THREADID tid,ADDRINT pc,ADDRINT file,ADDRINT line,ADDRINT lock,ADDRINT is_w)2459 static void On_AnnotateRWLockReleased(THREADID tid, ADDRINT pc,
2460 ADDRINT file, ADDRINT line,
2461 ADDRINT lock, ADDRINT is_w) {
2462 DumpEvent(0, UNLOCK, tid, pc, lock, 0);
2463 }
2464
2465
WRAP_NAME(RunningOnValgrind)2466 int WRAP_NAME(RunningOnValgrind)(WRAP_PARAM4) {
2467 return 1;
2468 }
2469
2470 //--------- Instrumentation ----------------------- {{{1
IgnoreImage(IMG img)2471 static bool IgnoreImage(IMG img) {
2472 string name = IMG_Name(img);
2473 if (name.find("/ld-") != string::npos)
2474 return true;
2475 return false;
2476 }
2477
IgnoreRtn(RTN rtn)2478 static bool IgnoreRtn(RTN rtn) {
2479 CHECK(rtn != RTN_Invalid());
2480 ADDRINT rtn_address = RTN_Address(rtn);
2481 if (ThreadSanitizerWantToInstrumentSblock(rtn_address) == false)
2482 return true;
2483 return false;
2484 }
2485
InstrumentCall(INS ins)2486 static bool InstrumentCall(INS ins) {
2487 // Call.
2488 if (INS_IsProcedureCall(ins) && !INS_IsSyscall(ins)) {
2489 IGNORE_BELOW_RTN ignore_below = IGNORE_BELOW_RTN_UNKNOWN;
2490 if (INS_IsDirectBranchOrCall(ins)) {
2491 ADDRINT target = INS_DirectBranchOrCallTargetAddress(ins);
2492 bool ignore = ThreadSanitizerIgnoreAccessesBelowFunction(target);
2493 ignore_below = ignore ? IGNORE_BELOW_RTN_YES : IGNORE_BELOW_RTN_NO;
2494 }
2495 INS_InsertCall(ins, IPOINT_BEFORE,
2496 (AFUNPTR)InsertBeforeEvent_Call,
2497 IARG_THREAD_ID,
2498 IARG_INST_PTR,
2499 IARG_BRANCH_TARGET_ADDR,
2500 IARG_REG_VALUE, REG_STACK_PTR,
2501 IARG_ADDRINT, ignore_below,
2502 IARG_END);
2503 return true;
2504 }
2505 if (INS_IsSyscall(ins)) {
2506 INS_InsertCall(ins, IPOINT_BEFORE,
2507 (AFUNPTR)InsertBeforeEvent_SysCall,
2508 IARG_THREAD_ID,
2509 IARG_REG_VALUE, REG_STACK_PTR,
2510 IARG_END);
2511 }
2512 return false;
2513 }
2514
2515
2516 // return the number of inserted instrumentations.
InstrumentMopsInBBl(BBL bbl,RTN rtn,TraceInfo * trace_info,uintptr_t instrument_pc,size_t * mop_idx)2517 static void InstrumentMopsInBBl(BBL bbl, RTN rtn, TraceInfo *trace_info, uintptr_t instrument_pc, size_t *mop_idx) {
2518 // compute 'dtor_head', see
2519 // http://code.google.com/p/data-race-test/wiki/PopularDataRaces#Data_race_on_vptr
2520 // On x86_64 only the first BB of DTOR is treated as dtor_head.
2521 // On x86, we have to treat more BBs as dtor_head due to -fPIC.
2522 // See http://code.google.com/p/chromium/issues/detail?id=61199
2523 bool dtor_head = false;
2524 #ifdef TARGET_IA32
2525 size_t max_offset_for_dtor_head = 32;
2526 #else
2527 size_t max_offset_for_dtor_head = 0;
2528 #endif
2529
2530 if (BBL_Address(bbl) - RTN_Address(rtn) <= max_offset_for_dtor_head) {
2531 string demangled_rtn_name = Demangle(RTN_Name(rtn).c_str());
2532 if (demangled_rtn_name.find("::~") != string::npos)
2533 dtor_head = true;
2534 }
2535
2536 INS tail = BBL_InsTail(bbl);
2537 // All memory reads/writes
2538 for( INS ins = BBL_InsHead(bbl);
2539 INS_Valid(ins);
2540 ins = INS_Next(ins) ) {
2541 if (ins != tail) {
2542 CHECK(!INS_IsRet(ins));
2543 CHECK(!INS_IsProcedureCall(ins));
2544 }
2545 // bool is_stack = INS_IsStackRead(ins) || INS_IsStackWrite(ins);
2546 if (INS_IsAtomicUpdate(ins)) continue;
2547
2548 int n_mops = INS_MemoryOperandCount(ins);
2549 if (n_mops == 0) continue;
2550
2551 string opcode_str = OPCODE_StringShort(INS_Opcode(ins));
2552 if (trace_info && debug_ins) {
2553 Printf(" INS: opcode=%s n_mops=%d dis=\"%s\"\n",
2554 opcode_str.c_str(), n_mops,
2555 INS_Disassemble(ins).c_str());
2556 }
2557
2558 bool ins_ignore_writes = false;
2559 bool ins_ignore_reads = false;
2560
2561 // CALL writes to stack and (if the call is indirect) reads the target
2562 // address. We don't want to handle the stack write.
2563 if (INS_IsCall(ins)) {
2564 CHECK(n_mops == 1 || n_mops == 2);
2565 ins_ignore_writes = true;
2566 }
2567
2568 // PUSH: we ignore the write to stack but we don't ignore the read (if any).
2569 if (opcode_str == "PUSH") {
2570 CHECK(n_mops == 1 || n_mops == 2);
2571 ins_ignore_writes = true;
2572 }
2573
2574 // POP: we are reading from stack, Ignore it.
2575 if (opcode_str == "POP") {
2576 CHECK(n_mops == 1 || n_mops == 2);
2577 ins_ignore_reads = true;
2578 continue;
2579 }
2580
2581 // RET/LEAVE -- ignore it, it just reads the return address and stack.
2582 if (INS_IsRet(ins) || opcode_str == "LEAVE") {
2583 CHECK(n_mops == 1);
2584 continue;
2585 }
2586
2587 bool is_predicated = INS_IsPredicated(ins);
2588 for (int i = 0; i < n_mops; i++) {
2589 if (*mop_idx >= kMaxMopsPerTrace) {
2590 Report("INFO: too many mops in trace: %d %s\n",
2591 INS_Address(ins), PcToRtnName(INS_Address(ins), true).c_str());
2592 return;
2593 }
2594 size_t size = INS_MemoryOperandSize(ins, i);
2595 CHECK(size);
2596 bool is_write = INS_MemoryOperandIsWritten(ins, i);
2597
2598 if (ins_ignore_writes && is_write) continue;
2599 if (ins_ignore_reads && !is_write) continue;
2600 if (instrument_pc && instrument_pc != INS_Address(ins)) continue;
2601
2602 bool check_ident_store = false;
2603 if (dtor_head && is_write && INS_IsMov(ins) && size == sizeof(void*)) {
2604 // This is a special case for '*addr = value', where we want to ignore the
2605 // access if *addr == value before the store.
2606 CHECK(!is_predicated);
2607 check_ident_store = true;
2608 }
2609
2610 if (trace_info) {
2611 if (debug_ins) {
2612 Printf(" size=%ld is_w=%d\n", size, (int)is_write);
2613 }
2614 IPOINT point = IPOINT_BEFORE;
2615 AFUNPTR on_mop_callback = (AFUNPTR)OnMop;
2616 if (check_ident_store) {
2617 INS_InsertCall(ins, IPOINT_BEFORE,
2618 (AFUNPTR)OnMopCheckIdentStoreBefore,
2619 IARG_REG_VALUE, tls_reg,
2620 IARG_THREAD_ID,
2621 IARG_ADDRINT, *mop_idx,
2622 IARG_MEMORYOP_EA, i,
2623 IARG_END);
2624 // This is just a MOV, so we can insert the instrumentation code
2625 // after the insn.
2626 point = IPOINT_AFTER;
2627 on_mop_callback = (AFUNPTR)OnMopCheckIdentStoreAfter;
2628 }
2629
2630 MopInfo *mop = trace_info->GetMop(*mop_idx);
2631 new (mop) MopInfo(INS_Address(ins), size, is_write, false);
2632 if (is_predicated) {
2633 INS_InsertPredicatedCall(ins, point,
2634 (AFUNPTR)On_PredicatedMop,
2635 IARG_EXECUTING,
2636 IARG_REG_VALUE, tls_reg,
2637 IARG_THREAD_ID,
2638 IARG_ADDRINT, *mop_idx,
2639 IARG_MEMORYOP_EA, i,
2640 IARG_END);
2641 } else {
2642 INS_InsertCall(ins, point,
2643 on_mop_callback,
2644 IARG_REG_VALUE, tls_reg,
2645 IARG_THREAD_ID,
2646 IARG_ADDRINT, *mop_idx,
2647 IARG_MEMORYOP_EA, i,
2648 IARG_END);
2649 }
2650 }
2651 (*mop_idx)++;
2652 }
2653 }
2654 }
2655
CallbackForTRACE(TRACE trace,void * v)2656 void CallbackForTRACE(TRACE trace, void *v) {
2657 CHECK(n_started_threads > 0);
2658
2659 RTN rtn = TRACE_Rtn(trace);
2660 bool ignore_memory = false;
2661 string img_name = "<>";
2662 string rtn_name = "<>";
2663 if (RTN_Valid(rtn)) {
2664 SEC sec = RTN_Sec(rtn);
2665 IMG img = SEC_Img(sec);
2666 rtn_name = RTN_Name(rtn);
2667 img_name = IMG_Name(img);
2668
2669 if (IgnoreImage(img)) {
2670 // Printf("Ignoring memory accesses in %s\n", IMG_Name(img).c_str());
2671 ignore_memory = true;
2672 } else if (IgnoreRtn(rtn)) {
2673 ignore_memory = true;
2674 }
2675 }
2676
2677 uintptr_t instrument_pc = 0;
2678 if (g_race_verifier_active) {
2679 // Check if this trace looks like part of a possible race report.
2680 uintptr_t min_pc = UINTPTR_MAX;
2681 uintptr_t max_pc = 0;
2682 for(BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
2683 min_pc = MIN(min_pc, INS_Address(BBL_InsHead(bbl)));
2684 max_pc = MAX(max_pc, INS_Address(BBL_InsTail(bbl)));
2685 }
2686
2687 bool verify_trace = RaceVerifierGetAddresses(min_pc, max_pc, &instrument_pc);
2688 if (!verify_trace)
2689 ignore_memory = true;
2690 }
2691
2692 size_t n_mops = 0;
2693 // count the mops.
2694 for(BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
2695 if (!ignore_memory) {
2696 InstrumentMopsInBBl(bbl, rtn, NULL, instrument_pc, &n_mops);
2697 }
2698 INS tail = BBL_InsTail(bbl);
2699 if (INS_IsRet(tail)) {
2700 #if 0
2701 INS_InsertIfCall(tail, IPOINT_BEFORE,
2702 (AFUNPTR)Before_RET_IF,
2703 IARG_THREAD_ID,
2704 IARG_END);
2705
2706 INS_InsertThenCall(
2707 #else
2708 INS_InsertCall(
2709 #endif
2710 tail, IPOINT_BEFORE,
2711 (AFUNPTR)Before_RET_THEN,
2712 IARG_THREAD_ID,
2713 IARG_INST_PTR,
2714 IARG_REG_VALUE, REG_STACK_PTR,
2715 IARG_FUNCRET_EXITPOINT_VALUE,
2716 IARG_END);
2717 }
2718 }
2719
2720 // Handle the head of the trace
2721 INS head = BBL_InsHead(TRACE_BblHead(trace));
2722 CHECK(n_mops <= kMaxMopsPerTrace);
2723
2724 TraceInfo *trace_info = NULL;
2725 if (n_mops) {
2726 trace_info = TraceInfo::NewTraceInfo(n_mops, INS_Address(head));
2727 if (TS_SERIALIZED == 0) {
2728 // TODO(kcc): implement race verifier here.
2729 INS_InsertCall(head, IPOINT_BEFORE,
2730 (AFUNPTR)OnTraceParallel,
2731 IARG_REG_VALUE, tls_reg,
2732 IARG_REG_VALUE, REG_STACK_PTR,
2733 IARG_PTR, trace_info,
2734 IARG_END);
2735 } else {
2736 AFUNPTR handler = (AFUNPTR)(g_race_verifier_active ?
2737 OnTraceVerify : OnTraceSerial);
2738 INS_InsertCall(head, IPOINT_BEFORE,
2739 handler,
2740 IARG_THREAD_ID,
2741 IARG_REG_VALUE, REG_STACK_PTR,
2742 IARG_PTR, trace_info,
2743 IARG_REG_REFERENCE, tls_reg,
2744 IARG_END);
2745 }
2746 } else {
2747 if (g_race_verifier_active) {
2748 INS_InsertCall(head, IPOINT_BEFORE,
2749 (AFUNPTR)OnTraceNoMopsVerify,
2750 IARG_THREAD_ID,
2751 IARG_REG_VALUE, REG_STACK_PTR,
2752 IARG_REG_REFERENCE, tls_reg,
2753 IARG_END);
2754 }
2755 }
2756
2757 // instrument the mops. We want to do it after we instrumented the head
2758 // to maintain the right order of instrumentation callbacks (head first, then
2759 // mops).
2760 size_t i = 0;
2761 if (n_mops) {
2762 if (debug_ins) {
2763 Printf("TRACE %p (%p); n_mops=%ld %s\n", trace_info,
2764 TRACE_Address(trace),
2765 trace_info->n_mops(),
2766 PcToRtnName(trace_info->pc(), false).c_str());
2767 }
2768 for(BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
2769 InstrumentMopsInBBl(bbl, rtn, trace_info, instrument_pc, &i);
2770 }
2771 }
2772
2773 // instrument the calls, do it after all other instrumentation.
2774 if (!g_race_verifier_active) {
2775 for(BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
2776 InstrumentCall(BBL_InsTail(bbl));
2777 }
2778 }
2779
2780 CHECK(n_mops == i);
2781 }
2782
2783
2784 #define INSERT_FN_HELPER(point, name, rtn, to_insert, ...) \
2785 RTN_Open(rtn); \
2786 if (G_flags->verbosity >= 2) Printf("RTN: Inserting %-50s (%s) %s (%s) img: %s\n", \
2787 #to_insert, #point, RTN_Name(rtn).c_str(), name, IMG_Name(img).c_str());\
2788 RTN_InsertCall(rtn, point, (AFUNPTR)to_insert, IARG_THREAD_ID, \
2789 IARG_INST_PTR, __VA_ARGS__, IARG_END);\
2790 RTN_Close(rtn); \
2791
2792 #define INSERT_FN(point, name, to_insert, ...) \
2793 while (RtnMatchesName(rtn_name, name)) {\
2794 INSERT_FN_HELPER(point, name, rtn, to_insert, __VA_ARGS__); \
2795 break;\
2796 }\
2797
2798
2799 #define INSERT_BEFORE_FN(name, to_insert, ...) \
2800 INSERT_FN(IPOINT_BEFORE, name, to_insert, __VA_ARGS__)
2801
2802 #define INSERT_BEFORE_1_SP(name, to_insert) \
2803 INSERT_BEFORE_FN(name, to_insert, \
2804 IARG_REG_VALUE, REG_STACK_PTR, \
2805 IARG_FUNCARG_ENTRYPOINT_VALUE, 0)
2806
2807 #define INSERT_BEFORE_2_SP(name, to_insert) \
2808 INSERT_BEFORE_FN(name, to_insert, \
2809 IARG_REG_VALUE, REG_STACK_PTR, \
2810 IARG_FUNCARG_ENTRYPOINT_VALUE, 0, \
2811 IARG_FUNCARG_ENTRYPOINT_VALUE, 1)
2812
2813 #define INSERT_BEFORE_0(name, to_insert) \
2814 INSERT_BEFORE_FN(name, to_insert, IARG_END);
2815
2816 #define INSERT_BEFORE_1(name, to_insert) \
2817 INSERT_BEFORE_FN(name, to_insert, \
2818 IARG_FUNCARG_ENTRYPOINT_VALUE, 0)
2819
2820 #define INSERT_BEFORE_2(name, to_insert) \
2821 INSERT_BEFORE_FN(name, to_insert, \
2822 IARG_FUNCARG_ENTRYPOINT_VALUE, 0, \
2823 IARG_FUNCARG_ENTRYPOINT_VALUE, 1)
2824
2825 #define INSERT_BEFORE_3(name, to_insert) \
2826 INSERT_BEFORE_FN(name, to_insert, \
2827 IARG_FUNCARG_ENTRYPOINT_VALUE, 0, \
2828 IARG_FUNCARG_ENTRYPOINT_VALUE, 1, \
2829 IARG_FUNCARG_ENTRYPOINT_VALUE, 2)
2830
2831 #define INSERT_BEFORE_4(name, to_insert) \
2832 INSERT_BEFORE_FN(name, to_insert, \
2833 IARG_FUNCARG_ENTRYPOINT_VALUE, 0, \
2834 IARG_FUNCARG_ENTRYPOINT_VALUE, 1, \
2835 IARG_FUNCARG_ENTRYPOINT_VALUE, 2, \
2836 IARG_FUNCARG_ENTRYPOINT_VALUE, 3)
2837
2838 #define INSERT_BEFORE_5(name, to_insert) \
2839 INSERT_BEFORE_FN(name, to_insert, \
2840 IARG_FUNCARG_ENTRYPOINT_VALUE, 0, \
2841 IARG_FUNCARG_ENTRYPOINT_VALUE, 1, \
2842 IARG_FUNCARG_ENTRYPOINT_VALUE, 2, \
2843 IARG_FUNCARG_ENTRYPOINT_VALUE, 3, \
2844 IARG_FUNCARG_ENTRYPOINT_VALUE, 4)
2845
2846 #define INSERT_BEFORE_6(name, to_insert) \
2847 INSERT_BEFORE_FN(name, to_insert, \
2848 IARG_FUNCARG_ENTRYPOINT_VALUE, 0, \
2849 IARG_FUNCARG_ENTRYPOINT_VALUE, 1, \
2850 IARG_FUNCARG_ENTRYPOINT_VALUE, 2, \
2851 IARG_FUNCARG_ENTRYPOINT_VALUE, 3, \
2852 IARG_FUNCARG_ENTRYPOINT_VALUE, 4, \
2853 IARG_FUNCARG_ENTRYPOINT_VALUE, 5)
2854
2855 #define INSERT_AFTER_FN(name, to_insert, ...) \
2856 INSERT_FN(IPOINT_AFTER, name, to_insert, __VA_ARGS__)
2857
2858 #define INSERT_AFTER_0(name, to_insert) \
2859 INSERT_AFTER_FN(name, to_insert, IARG_END)
2860
2861 #define INSERT_AFTER_1(name, to_insert) \
2862 INSERT_AFTER_FN(name, to_insert, IARG_FUNCRET_EXITPOINT_VALUE)
2863
2864
2865 #ifdef _MSC_VER
WrapStdCallFunc1(RTN rtn,char * name,AFUNPTR replacement_func)2866 void WrapStdCallFunc1(RTN rtn, char *name, AFUNPTR replacement_func) {
2867 if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name)) {
2868 InformAboutFunctionWrap(rtn, name);
2869 PROTO proto = PROTO_Allocate(PIN_PARG(uintptr_t),
2870 CALLINGSTD_STDCALL,
2871 "proto",
2872 PIN_PARG(uintptr_t),
2873 PIN_PARG_END());
2874 RTN_ReplaceSignature(rtn,
2875 AFUNPTR(replacement_func),
2876 IARG_PROTOTYPE, proto,
2877 IARG_THREAD_ID,
2878 IARG_INST_PTR,
2879 IARG_CONTEXT,
2880 IARG_ORIG_FUNCPTR,
2881 IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
2882 IARG_END);
2883 PROTO_Free(proto);
2884 }
2885 }
2886
WrapStdCallFunc2(RTN rtn,char * name,AFUNPTR replacement_func)2887 void WrapStdCallFunc2(RTN rtn, char *name, AFUNPTR replacement_func) {
2888 if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name)) {
2889 InformAboutFunctionWrap(rtn, name);
2890 PROTO proto = PROTO_Allocate(PIN_PARG(uintptr_t),
2891 CALLINGSTD_STDCALL,
2892 "proto",
2893 PIN_PARG(uintptr_t),
2894 PIN_PARG(uintptr_t),
2895 PIN_PARG_END());
2896 RTN_ReplaceSignature(rtn,
2897 AFUNPTR(replacement_func),
2898 IARG_PROTOTYPE, proto,
2899 IARG_THREAD_ID,
2900 IARG_INST_PTR,
2901 IARG_CONTEXT,
2902 IARG_ORIG_FUNCPTR,
2903 IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
2904 IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
2905 IARG_END);
2906 PROTO_Free(proto);
2907 }
2908 }
2909
WrapStdCallFunc3(RTN rtn,char * name,AFUNPTR replacement_func)2910 void WrapStdCallFunc3(RTN rtn, char *name, AFUNPTR replacement_func) {
2911 if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name)) {
2912 InformAboutFunctionWrap(rtn, name);
2913 PROTO proto = PROTO_Allocate(PIN_PARG(uintptr_t),
2914 CALLINGSTD_STDCALL,
2915 "proto",
2916 PIN_PARG(uintptr_t),
2917 PIN_PARG(uintptr_t),
2918 PIN_PARG(uintptr_t),
2919 PIN_PARG_END());
2920 RTN_ReplaceSignature(rtn,
2921 AFUNPTR(replacement_func),
2922 IARG_PROTOTYPE, proto,
2923 IARG_THREAD_ID,
2924 IARG_INST_PTR,
2925 IARG_CONTEXT,
2926 IARG_ORIG_FUNCPTR,
2927 IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
2928 IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
2929 IARG_FUNCARG_ENTRYPOINT_VALUE, 2,
2930 IARG_END);
2931 PROTO_Free(proto);
2932 }
2933 }
2934
WrapStdCallFunc4(RTN rtn,char * name,AFUNPTR replacement_func)2935 void WrapStdCallFunc4(RTN rtn, char *name, AFUNPTR replacement_func) {
2936 if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name)) {
2937 InformAboutFunctionWrap(rtn, name);
2938 PROTO proto = PROTO_Allocate(PIN_PARG(uintptr_t),
2939 CALLINGSTD_STDCALL,
2940 "proto",
2941 PIN_PARG(uintptr_t),
2942 PIN_PARG(uintptr_t),
2943 PIN_PARG(uintptr_t),
2944 PIN_PARG(uintptr_t),
2945 PIN_PARG_END());
2946 RTN_ReplaceSignature(rtn,
2947 AFUNPTR(replacement_func),
2948 IARG_PROTOTYPE, proto,
2949 IARG_THREAD_ID,
2950 IARG_INST_PTR,
2951 IARG_CONTEXT,
2952 IARG_ORIG_FUNCPTR,
2953 IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
2954 IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
2955 IARG_FUNCARG_ENTRYPOINT_VALUE, 2,
2956 IARG_FUNCARG_ENTRYPOINT_VALUE, 3,
2957 IARG_END);
2958 PROTO_Free(proto);
2959 }
2960 }
2961
WrapStdCallFunc5(RTN rtn,char * name,AFUNPTR replacement_func)2962 void WrapStdCallFunc5(RTN rtn, char *name, AFUNPTR replacement_func) {
2963 if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name)) {
2964 InformAboutFunctionWrap(rtn, name);
2965 PROTO proto = PROTO_Allocate(PIN_PARG(uintptr_t),
2966 CALLINGSTD_STDCALL,
2967 "proto",
2968 PIN_PARG(uintptr_t),
2969 PIN_PARG(uintptr_t),
2970 PIN_PARG(uintptr_t),
2971 PIN_PARG(uintptr_t),
2972 PIN_PARG(uintptr_t),
2973 PIN_PARG_END());
2974 RTN_ReplaceSignature(rtn,
2975 AFUNPTR(replacement_func),
2976 IARG_PROTOTYPE, proto,
2977 IARG_THREAD_ID,
2978 IARG_INST_PTR,
2979 IARG_CONTEXT,
2980 IARG_ORIG_FUNCPTR,
2981 IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
2982 IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
2983 IARG_FUNCARG_ENTRYPOINT_VALUE, 2,
2984 IARG_FUNCARG_ENTRYPOINT_VALUE, 3,
2985 IARG_FUNCARG_ENTRYPOINT_VALUE, 4,
2986 IARG_END);
2987 PROTO_Free(proto);
2988 }
2989 }
2990
WrapStdCallFunc6(RTN rtn,char * name,AFUNPTR replacement_func)2991 void WrapStdCallFunc6(RTN rtn, char *name, AFUNPTR replacement_func) {
2992 if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name)) {
2993 InformAboutFunctionWrap(rtn, name);
2994 PROTO proto = PROTO_Allocate(PIN_PARG(uintptr_t),
2995 CALLINGSTD_STDCALL,
2996 "proto",
2997 PIN_PARG(uintptr_t),
2998 PIN_PARG(uintptr_t),
2999 PIN_PARG(uintptr_t),
3000 PIN_PARG(uintptr_t),
3001 PIN_PARG(uintptr_t),
3002 PIN_PARG(uintptr_t),
3003 PIN_PARG_END());
3004 RTN_ReplaceSignature(rtn,
3005 AFUNPTR(replacement_func),
3006 IARG_PROTOTYPE, proto,
3007 IARG_THREAD_ID,
3008 IARG_INST_PTR,
3009 IARG_CONTEXT,
3010 IARG_ORIG_FUNCPTR,
3011 IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
3012 IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
3013 IARG_FUNCARG_ENTRYPOINT_VALUE, 2,
3014 IARG_FUNCARG_ENTRYPOINT_VALUE, 3,
3015 IARG_FUNCARG_ENTRYPOINT_VALUE, 4,
3016 IARG_FUNCARG_ENTRYPOINT_VALUE, 5,
3017 IARG_END);
3018 PROTO_Free(proto);
3019 }
3020 }
3021
WrapStdCallFunc7(RTN rtn,char * name,AFUNPTR replacement_func)3022 void WrapStdCallFunc7(RTN rtn, char *name, AFUNPTR replacement_func) {
3023 if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name)) {
3024 InformAboutFunctionWrap(rtn, name);
3025 PROTO proto = PROTO_Allocate(PIN_PARG(uintptr_t),
3026 CALLINGSTD_STDCALL,
3027 "proto",
3028 PIN_PARG(uintptr_t),
3029 PIN_PARG(uintptr_t),
3030 PIN_PARG(uintptr_t),
3031 PIN_PARG(uintptr_t),
3032 PIN_PARG(uintptr_t),
3033 PIN_PARG(uintptr_t),
3034 PIN_PARG(uintptr_t),
3035 PIN_PARG_END());
3036 RTN_ReplaceSignature(rtn,
3037 AFUNPTR(replacement_func),
3038 IARG_PROTOTYPE, proto,
3039 IARG_THREAD_ID,
3040 IARG_INST_PTR,
3041 IARG_CONTEXT,
3042 IARG_ORIG_FUNCPTR,
3043 IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
3044 IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
3045 IARG_FUNCARG_ENTRYPOINT_VALUE, 2,
3046 IARG_FUNCARG_ENTRYPOINT_VALUE, 3,
3047 IARG_FUNCARG_ENTRYPOINT_VALUE, 4,
3048 IARG_FUNCARG_ENTRYPOINT_VALUE, 5,
3049 IARG_FUNCARG_ENTRYPOINT_VALUE, 6,
3050 IARG_END);
3051 PROTO_Free(proto);
3052 }
3053 }
3054
WrapStdCallFunc8(RTN rtn,char * name,AFUNPTR replacement_func)3055 void WrapStdCallFunc8(RTN rtn, char *name, AFUNPTR replacement_func) {
3056 if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name)) {
3057 InformAboutFunctionWrap(rtn, name);
3058 PROTO proto = PROTO_Allocate(PIN_PARG(uintptr_t),
3059 CALLINGSTD_STDCALL,
3060 "proto",
3061 PIN_PARG(uintptr_t),
3062 PIN_PARG(uintptr_t),
3063 PIN_PARG(uintptr_t),
3064 PIN_PARG(uintptr_t),
3065 PIN_PARG(uintptr_t),
3066 PIN_PARG(uintptr_t),
3067 PIN_PARG(uintptr_t),
3068 PIN_PARG(uintptr_t),
3069 PIN_PARG_END());
3070 RTN_ReplaceSignature(rtn,
3071 AFUNPTR(replacement_func),
3072 IARG_PROTOTYPE, proto,
3073 IARG_THREAD_ID,
3074 IARG_INST_PTR,
3075 IARG_CONTEXT,
3076 IARG_ORIG_FUNCPTR,
3077 IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
3078 IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
3079 IARG_FUNCARG_ENTRYPOINT_VALUE, 2,
3080 IARG_FUNCARG_ENTRYPOINT_VALUE, 3,
3081 IARG_FUNCARG_ENTRYPOINT_VALUE, 4,
3082 IARG_FUNCARG_ENTRYPOINT_VALUE, 5,
3083 IARG_FUNCARG_ENTRYPOINT_VALUE, 6,
3084 IARG_FUNCARG_ENTRYPOINT_VALUE, 7,
3085 IARG_END);
3086 PROTO_Free(proto);
3087 }
3088 }
3089
WrapStdCallFunc10(RTN rtn,char * name,AFUNPTR replacement_func)3090 void WrapStdCallFunc10(RTN rtn, char *name, AFUNPTR replacement_func) {
3091 if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name)) {
3092 InformAboutFunctionWrap(rtn, name);
3093 PROTO proto = PROTO_Allocate(PIN_PARG(uintptr_t),
3094 CALLINGSTD_STDCALL,
3095 "proto",
3096 PIN_PARG(uintptr_t),
3097 PIN_PARG(uintptr_t),
3098 PIN_PARG(uintptr_t),
3099 PIN_PARG(uintptr_t),
3100 PIN_PARG(uintptr_t),
3101 PIN_PARG(uintptr_t),
3102 PIN_PARG(uintptr_t),
3103 PIN_PARG(uintptr_t),
3104 PIN_PARG(uintptr_t),
3105 PIN_PARG(uintptr_t),
3106 PIN_PARG_END());
3107 RTN_ReplaceSignature(rtn,
3108 AFUNPTR(replacement_func),
3109 IARG_PROTOTYPE, proto,
3110 IARG_THREAD_ID,
3111 IARG_INST_PTR,
3112 IARG_CONTEXT,
3113 IARG_ORIG_FUNCPTR,
3114 IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
3115 IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
3116 IARG_FUNCARG_ENTRYPOINT_VALUE, 2,
3117 IARG_FUNCARG_ENTRYPOINT_VALUE, 3,
3118 IARG_FUNCARG_ENTRYPOINT_VALUE, 4,
3119 IARG_FUNCARG_ENTRYPOINT_VALUE, 5,
3120 IARG_FUNCARG_ENTRYPOINT_VALUE, 6,
3121 IARG_FUNCARG_ENTRYPOINT_VALUE, 7,
3122 IARG_FUNCARG_ENTRYPOINT_VALUE, 8,
3123 IARG_FUNCARG_ENTRYPOINT_VALUE, 9,
3124 IARG_END);
3125 PROTO_Free(proto);
3126 }
3127 }
3128
WrapStdCallFunc11(RTN rtn,char * name,AFUNPTR replacement_func)3129 void WrapStdCallFunc11(RTN rtn, char *name, AFUNPTR replacement_func) {
3130 if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name)) {
3131 InformAboutFunctionWrap(rtn, name);
3132 PROTO proto = PROTO_Allocate(PIN_PARG(uintptr_t),
3133 CALLINGSTD_STDCALL,
3134 "proto",
3135 PIN_PARG(uintptr_t),
3136 PIN_PARG(uintptr_t),
3137 PIN_PARG(uintptr_t),
3138 PIN_PARG(uintptr_t),
3139 PIN_PARG(uintptr_t),
3140 PIN_PARG(uintptr_t),
3141 PIN_PARG(uintptr_t),
3142 PIN_PARG(uintptr_t),
3143 PIN_PARG(uintptr_t),
3144 PIN_PARG(uintptr_t),
3145 PIN_PARG(uintptr_t),
3146 PIN_PARG_END());
3147 RTN_ReplaceSignature(rtn,
3148 AFUNPTR(replacement_func),
3149 IARG_PROTOTYPE, proto,
3150 IARG_THREAD_ID,
3151 IARG_INST_PTR,
3152 IARG_CONTEXT,
3153 IARG_ORIG_FUNCPTR,
3154 IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
3155 IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
3156 IARG_FUNCARG_ENTRYPOINT_VALUE, 2,
3157 IARG_FUNCARG_ENTRYPOINT_VALUE, 3,
3158 IARG_FUNCARG_ENTRYPOINT_VALUE, 4,
3159 IARG_FUNCARG_ENTRYPOINT_VALUE, 5,
3160 IARG_FUNCARG_ENTRYPOINT_VALUE, 6,
3161 IARG_FUNCARG_ENTRYPOINT_VALUE, 7,
3162 IARG_FUNCARG_ENTRYPOINT_VALUE, 8,
3163 IARG_FUNCARG_ENTRYPOINT_VALUE, 9,
3164 IARG_FUNCARG_ENTRYPOINT_VALUE, 10,
3165 IARG_END);
3166 PROTO_Free(proto);
3167 }
3168 }
3169
3170 #endif
3171
MaybeInstrumentOneRoutine(IMG img,RTN rtn)3172 static void MaybeInstrumentOneRoutine(IMG img, RTN rtn) {
3173 if (IgnoreImage(img)) {
3174 return;
3175 }
3176 string rtn_name = RTN_Name(rtn);
3177 string img_name = IMG_Name(img);
3178 if (debug_wrap) {
3179 Printf("%s: %s %s pc=%p\n", __FUNCTION__, rtn_name.c_str(),
3180 img_name.c_str(), RTN_Address(rtn));
3181 }
3182
3183 // malloc/free/etc
3184 const char *malloc_names[] = {
3185 "malloc",
3186 #if defined(__GNUC__)
3187 "_Znwm",
3188 "_Znam",
3189 "_Znwj",
3190 "_Znaj",
3191 "_ZnwmRKSt9nothrow_t",
3192 "_ZnamRKSt9nothrow_t",
3193 "_ZnwjRKSt9nothrow_t",
3194 "_ZnajRKSt9nothrow_t",
3195 #endif
3196 #if defined(_MSC_VER)
3197 "operator new",
3198 "operator new[]",
3199 #endif // _MSC_VER
3200 };
3201
3202 const char *free_names[] = {
3203 "free",
3204 #if defined(__GNUC__)
3205 "_ZdaPv",
3206 "_ZdlPv",
3207 "_ZdlPvRKSt9nothrow_t",
3208 "_ZdaPvRKSt9nothrow_t",
3209 #endif // __GNUC__
3210 #if defined(_MSC_VER)
3211 "operator delete",
3212 "operator delete[]",
3213 #endif // _MSC_VER
3214 };
3215
3216 for (size_t i = 0; i < TS_ARRAY_SIZE(malloc_names); i++) {
3217 const char *name = malloc_names[i];
3218 INSERT_BEFORE_1_SP(name, Before_malloc);
3219 }
3220
3221 for (size_t i = 0; i < TS_ARRAY_SIZE(free_names); i++) {
3222 const char *name = free_names[i];
3223 INSERT_BEFORE_1_SP(name, Before_free);
3224 }
3225
3226 INSERT_BEFORE_2_SP("calloc", Before_calloc);
3227 INSERT_BEFORE_2_SP("realloc", Before_realloc);
3228
3229 #if defined(__GNUC__)
3230 WrapFunc6(img, rtn, "mmap", (AFUNPTR)WRAP_NAME(mmap));
3231 WrapFunc4(img, rtn, "munmap", (AFUNPTR)WRAP_NAME(munmap));
3232
3233 WrapFunc4(img, rtn, "lockf", (AFUNPTR)WRAP_NAME(lockf));
3234 // pthread create/join
3235 WrapFunc4(img, rtn, "pthread_create", (AFUNPTR)WRAP_NAME(pthread_create));
3236 WrapFunc4(img, rtn, "pthread_join", (AFUNPTR)WRAP_NAME(pthread_join));
3237 WrapFunc4(img, rtn, "fwrite", (AFUNPTR)WRAP_NAME(fwrite));
3238
3239 INSERT_FN(IPOINT_BEFORE, "start_thread",
3240 Before_start_thread,
3241 IARG_REG_VALUE, REG_STACK_PTR, IARG_END);
3242
3243 // pthread_cond_*
3244 INSERT_BEFORE_1("pthread_cond_signal", Before_pthread_cond_signal);
3245 WRAP4(pthread_cond_wait);
3246 WRAP4(pthread_cond_timedwait);
3247
3248 // pthread_mutex_*
3249 INSERT_BEFORE_1("pthread_mutex_init", Before_pthread_mutex_init);
3250 INSERT_BEFORE_1("pthread_mutex_destroy", Before_pthread_mutex_destroy);
3251 INSERT_BEFORE_1("pthread_mutex_unlock", Before_pthread_unlock);
3252
3253
3254 INSERT_BEFORE_1_SP("pthread_mutex_lock", Before_pthread_mutex_lock);
3255 WRAP4(pthread_mutex_trylock);
3256 WRAP4(pthread_spin_lock);
3257 WRAP4(pthread_spin_trylock);
3258 WRAP4(pthread_spin_init);
3259 WRAP4(pthread_spin_destroy);
3260 WRAP4(pthread_spin_unlock);
3261 WRAP4(pthread_rwlock_wrlock);
3262 WRAP4(pthread_rwlock_rdlock);
3263 WRAP4(pthread_rwlock_trywrlock);
3264 WRAP4(pthread_rwlock_tryrdlock);
3265
3266 // pthread_rwlock_*
3267 INSERT_BEFORE_1("pthread_rwlock_init", Before_pthread_rwlock_init);
3268 INSERT_BEFORE_1("pthread_rwlock_destroy", Before_pthread_rwlock_destroy);
3269 INSERT_BEFORE_1("pthread_rwlock_unlock", Before_pthread_unlock);
3270
3271 // pthread_barrier_*
3272 WrapFunc4(img, rtn, "pthread_barrier_init",
3273 (AFUNPTR)WRAP_NAME(pthread_barrier_init));
3274 WrapFunc4(img, rtn, "pthread_barrier_wait",
3275 (AFUNPTR)WRAP_NAME(pthread_barrier_wait));
3276
3277 // pthread_once
3278 WrapFunc4(img, rtn, "pthread_once", (AFUNPTR)WRAP_NAME(pthread_once));
3279
3280 // sem_*
3281 INSERT_AFTER_1("sem_open", After_sem_open);
3282 INSERT_BEFORE_1("sem_post", Before_sem_post);
3283 WRAP4(sem_wait);
3284 WRAP4(sem_trywait);
3285
3286 INSERT_BEFORE_0("epoll_ctl", Before_epoll_ctl);
3287 INSERT_AFTER_0("epoll_wait", After_epoll_wait);
3288 #endif // __GNUC__
3289
3290 #ifdef _MSC_VER
3291 WrapStdCallFunc6(rtn, "CreateThread", (AFUNPTR)WRAP_NAME(CreateThread));
3292 WRAPSTD1(ResumeThread);
3293
3294 INSERT_FN(IPOINT_BEFORE, "BaseThreadInitThunk",
3295 Before_BaseThreadInitThunk,
3296 IARG_REG_VALUE, REG_STACK_PTR, IARG_END);
3297
3298 INSERT_BEFORE_0("RtlExitUserThread", Before_RtlExitUserThread);
3299 INSERT_BEFORE_0("ExitThread", Before_RtlExitUserThread);
3300
3301 WRAPSTD1(RtlInitializeCriticalSection);
3302 WRAPSTD2(RtlInitializeCriticalSectionAndSpinCount);
3303 WRAPSTD3(RtlInitializeCriticalSectionEx);
3304 WRAPSTD1(RtlDeleteCriticalSection);
3305 WRAPSTD1(RtlEnterCriticalSection);
3306 WRAPSTD1(RtlTryEnterCriticalSection);
3307 WRAPSTD1(RtlLeaveCriticalSection);
3308 WRAPSTD7(DuplicateHandle);
3309 WRAPSTD1(SetEvent);
3310 WRAPSTD4(CreateSemaphoreA);
3311 WRAPSTD4(CreateSemaphoreW);
3312 WRAPSTD3(ReleaseSemaphore);
3313
3314 WRAPSTD1(RtlInterlockedPopEntrySList);
3315 WRAPSTD2(RtlInterlockedPushEntrySList);
3316
3317 #if 1
3318 WRAPSTD1(RtlAcquireSRWLockExclusive);
3319 WRAPSTD1(RtlAcquireSRWLockShared);
3320 WRAPSTD1(RtlTryAcquireSRWLockExclusive);
3321 WRAPSTD1(RtlTryAcquireSRWLockShared);
3322 WRAPSTD1(RtlReleaseSRWLockExclusive);
3323 WRAPSTD1(RtlReleaseSRWLockShared);
3324 WRAPSTD1(RtlInitializeSRWLock);
3325 // For some reason, RtlInitializeSRWLock is aliased to RtlInitializeSRWLock..
3326 WrapStdCallFunc1(rtn, "RtlRunOnceInitialize",
3327 (AFUNPTR)Wrap_RtlInitializeSRWLock);
3328
3329 /* We haven't seen these syscalls used in the wild yet.
3330 WRAPSTD2(RtlUpdateClonedSRWLock);
3331 WRAPSTD1(RtlAcquireReleaseSRWLockExclusive);
3332 WRAPSTD1(RtlUpdateClonedCriticalSection);
3333 */
3334
3335 WRAPSTD1(RtlWakeConditionVariable);
3336 WRAPSTD1(RtlWakeAllConditionVariable);
3337 WRAPSTD4(RtlSleepConditionVariableSRW);
3338 WRAPSTD3(RtlSleepConditionVariableCS);
3339 #endif // if 1
3340
3341 WRAPSTD3(RtlQueueWorkItem);
3342 WRAPSTD6(RegisterWaitForSingleObject);
3343 WRAPSTD2(UnregisterWaitEx);
3344
3345 WRAPSTD3(WaitForSingleObjectEx);
3346 WRAPSTD5(WaitForMultipleObjectsEx);
3347
3348 WrapStdCallFunc4(rtn, "VirtualAlloc", (AFUNPTR)(WRAP_NAME(VirtualAlloc)));
3349 WrapStdCallFunc6(rtn, "ZwAllocateVirtualMemory", (AFUNPTR)(WRAP_NAME(ZwAllocateVirtualMemory)));
3350 WrapStdCallFunc2(rtn, "GlobalAlloc", (AFUNPTR)WRAP_NAME(GlobalAlloc));
3351 // WrapStdCallFunc3(rtn, "RtlAllocateHeap", (AFUNPTR) WRAP_NAME(AllocateHeap));
3352 // WrapStdCallFunc3(rtn, "HeapCreate", (AFUNPTR) WRAP_NAME(HeapCreate));
3353 #endif // _MSC_VER
3354
3355 // Annotations.
3356 INSERT_BEFORE_4("AnnotateBenignRace", On_AnnotateBenignRace);
3357 INSERT_BEFORE_5("AnnotateBenignRaceSized", On_AnnotateBenignRaceSized);
3358 INSERT_BEFORE_5("WTFAnnotateBenignRaceSized", On_AnnotateBenignRaceSized);
3359 INSERT_BEFORE_4("AnnotateExpectRace", On_AnnotateExpectRace);
3360 INSERT_BEFORE_2("AnnotateFlushExpectedRaces", On_AnnotateFlushExpectedRaces);
3361 INSERT_BEFORE_3("AnnotateTraceMemory", On_AnnotateTraceMemory);
3362 INSERT_BEFORE_4("AnnotateNewMemory", On_AnnotateNewMemory);
3363 INSERT_BEFORE_3("AnnotateNoOp", On_AnnotateNoOp);
3364 INSERT_BEFORE_2("AnnotateFlushState", On_AnnotateFlushState);
3365
3366 INSERT_BEFORE_3("AnnotateCondVarWait", On_AnnotateCondVarWait);
3367 INSERT_BEFORE_3("AnnotateCondVarSignal", On_AnnotateCondVarSignal);
3368 INSERT_BEFORE_3("AnnotateCondVarSignalAll", On_AnnotateCondVarSignal);
3369 INSERT_BEFORE_3("AnnotateHappensBefore", On_AnnotateHappensBefore);
3370 INSERT_BEFORE_3("WTFAnnotateHappensBefore", On_AnnotateHappensBefore);
3371 INSERT_BEFORE_3("AnnotateHappensAfter", On_AnnotateHappensAfter);
3372 INSERT_BEFORE_3("WTFAnnotateHappensAfter", On_AnnotateHappensAfter);
3373
3374 INSERT_BEFORE_3("AnnotateEnableRaceDetection", On_AnnotateEnableRaceDetection);
3375 INSERT_BEFORE_0("AnnotateIgnoreReadsBegin", On_AnnotateIgnoreReadsBegin);
3376 INSERT_BEFORE_0("AnnotateIgnoreReadsEnd", On_AnnotateIgnoreReadsEnd);
3377 INSERT_BEFORE_0("AnnotateIgnoreWritesBegin", On_AnnotateIgnoreWritesBegin);
3378 INSERT_BEFORE_0("AnnotateIgnoreWritesEnd", On_AnnotateIgnoreWritesEnd);
3379 INSERT_BEFORE_3("AnnotateThreadName", On_AnnotateThreadName);
3380 INSERT_BEFORE_4("AnnotatePublishMemoryRange", On_AnnotatePublishMemoryRange);
3381 INSERT_BEFORE_4("AnnotateUnpublishMemoryRange", On_AnnotateUnpublishMemoryRange);
3382 INSERT_BEFORE_3("AnnotateMutexIsUsedAsCondVar", On_AnnotateMutexIsUsedAsCondVar);
3383 INSERT_BEFORE_3("AnnotateMutexIsNotPHB", On_AnnotateMutexIsNotPhb);
3384
3385 INSERT_BEFORE_3("AnnotatePCQCreate", On_AnnotatePCQCreate);
3386 INSERT_BEFORE_3("AnnotatePCQDestroy", On_AnnotatePCQDestroy);
3387 INSERT_BEFORE_3("AnnotatePCQPut", On_AnnotatePCQPut);
3388 INSERT_BEFORE_3("AnnotatePCQGet", On_AnnotatePCQGet);
3389
3390 INSERT_BEFORE_3("AnnotateRWLockCreate", On_AnnotateRWLockCreate);
3391 INSERT_BEFORE_3("AnnotateRWLockDestroy", On_AnnotateRWLockDestroy);
3392 INSERT_BEFORE_4("AnnotateRWLockAcquired", On_AnnotateRWLockAcquired);
3393 INSERT_BEFORE_4("AnnotateRWLockReleased", On_AnnotateRWLockReleased);
3394
3395 // ThreadSanitizerQuery
3396 WrapFunc4(img, rtn, "ThreadSanitizerQuery",
3397 (AFUNPTR)WRAP_NAME(ThreadSanitizerQuery));
3398 WrapFunc4(img, rtn, "RunningOnValgrind",
3399 (AFUNPTR)WRAP_NAME(RunningOnValgrind));
3400
3401 // I/O
3402 INSERT_BEFORE_0("write", Before_SignallingIOCall);
3403 INSERT_BEFORE_0("unlink", Before_SignallingIOCall);
3404 INSERT_BEFORE_0("rmdir", Before_SignallingIOCall);
3405 // INSERT_BEFORE_0("send", Before_SignallingIOCall);
3406 INSERT_AFTER_0("__read_nocancel", After_WaitingIOCall);
3407 INSERT_AFTER_0("fopen", After_WaitingIOCall);
3408 INSERT_AFTER_0("__fopen_internal", After_WaitingIOCall);
3409 INSERT_AFTER_0("open", After_WaitingIOCall);
3410 INSERT_AFTER_0("opendir", After_WaitingIOCall);
3411 // INSERT_AFTER_0("recv", After_WaitingIOCall);
3412
3413 // strlen and friends.
3414 // These wrappers will generate memory access events.
3415 // So, if we don't want to get those events (e.g. memcpy inside
3416 // ld.so or ntdll.dll) we don't wrap them and the regular
3417 // ignore machinery will make sure we don't get the events.
3418 if (ThreadSanitizerWantToInstrumentSblock(RTN_Address(rtn))) {
3419 ReplaceFunc3(img, rtn, "memchr", (AFUNPTR)Replace_memchr);
3420 ReplaceFunc3(img, rtn, "strchr", (AFUNPTR)Replace_strchr);
3421 ReplaceFunc3(img, rtn, "index", (AFUNPTR)Replace_strchr);
3422 ReplaceFunc3(img, rtn, "strrchr", (AFUNPTR)Replace_strrchr);
3423 ReplaceFunc3(img, rtn, "rindex", (AFUNPTR)Replace_strrchr);
3424 ReplaceFunc3(img, rtn, "strlen", (AFUNPTR)Replace_strlen);
3425 ReplaceFunc3(img, rtn, "strcmp", (AFUNPTR)Replace_strcmp);
3426 ReplaceFunc3(img, rtn, "strncmp", (AFUNPTR)Replace_strncmp);
3427 ReplaceFunc3(img, rtn, "memcpy", (AFUNPTR)Replace_memcpy);
3428 ReplaceFunc3(img, rtn, "memcmp", (AFUNPTR)Replace_memcmp);
3429 ReplaceFunc3(img, rtn, "memmove", (AFUNPTR)Replace_memmove);
3430 ReplaceFunc3(img, rtn, "strcpy", (AFUNPTR)Replace_strcpy);
3431 ReplaceFunc3(img, rtn, "strncpy", (AFUNPTR)Replace_strncpy);
3432 ReplaceFunc3(img, rtn, "strcat", (AFUNPTR)Replace_strcat);
3433 ReplaceFunc3(img, rtn, "stpcpy", (AFUNPTR)Replace_stpcpy);
3434 }
3435
3436 // __cxa_guard_acquire / __cxa_guard_release
3437 INSERT_BEFORE_1("__cxa_guard_acquire", Before_cxa_guard_acquire);
3438 INSERT_AFTER_1("__cxa_guard_acquire", After_cxa_guard_acquire);
3439 INSERT_AFTER_0("__cxa_guard_release", After_cxa_guard_release);
3440
3441 INSERT_BEFORE_0("atexit", On_atexit);
3442 INSERT_BEFORE_0("exit", On_exit);
3443 }
3444
3445 // Pin calls this function every time a new img is loaded.
CallbackForIMG(IMG img,void * v)3446 static void CallbackForIMG(IMG img, void *v) {
3447 if (debug_wrap) {
3448 Printf("Started CallbackForIMG %s\n", IMG_Name(img).c_str());
3449 }
3450
3451 string img_name = IMG_Name(img);
3452 for (SEC sec = IMG_SecHead(img); SEC_Valid(sec); sec = SEC_Next(sec)) {
3453 for (RTN rtn = SEC_RtnHead(sec); RTN_Valid(rtn); rtn = RTN_Next(rtn)) {
3454 MaybeInstrumentOneRoutine(img, rtn);
3455 }
3456 }
3457 // In DEBUG_MODE check that we have the debug symbols in the Windows guts.
3458 // We should work w/o them too.
3459 // TODO(timurrrr): I doubt the problem is the missing symbols.
3460 // I have a strong gut feeling that this syscall was added
3461 // in Vista but only used since Windows 7. We had its wrapper wrong
3462 // (found on W7) but the Vista build was fine for months.
3463 // Also, we wrap RtlReleaseSRWLock*, so our TSan assertions would have been
3464 // broken if RtlTryAcquireSRWLock* wasn't wrapped - and we haven't see this.
3465 if (DEBUG_MODE && img_name.find("ntdll.dll") != string::npos) {
3466 if (g_wrapped_functions.count("RtlTryAcquireSRWLockExclusive") == 0) {
3467 Printf("WARNING: Debug symbols for ntdll.dll not found.\n");
3468 }
3469 }
3470 }
3471
3472 // Returns:
3473 // TRUE
3474 // If user is interested to inject Pin (and tool) into child/exec-ed process
3475 // FALSE
3476 // If user is not interested to inject Pin (and tool) into child/exec-ed process
CallbackForExec(CHILD_PROCESS childProcess,VOID * val)3477 static BOOL CallbackForExec(CHILD_PROCESS childProcess, VOID *val) {
3478 int argc = 0;
3479 const CHAR *const * argv = NULL;
3480 CHILD_PROCESS_GetCommandLine(childProcess, &argc, &argv);
3481 CHECK(argc > 0);
3482 CHECK(argv);
3483 bool follow = G_flags->trace_children;
3484 if (DEBUG_MODE) {
3485 Printf("CallbackForExec: follow=%d: ", follow);
3486 for (int i = 0; i < argc; i++) {
3487 Printf("%s ", argv[i]);
3488 }
3489 }
3490 Printf("\n");
3491 return follow;
3492 }
3493
3494 //--------- Fini ---------- {{{1
CallbackForFini(INT32 code,void * v)3495 static void CallbackForFini(INT32 code, void *v) {
3496 DumpEvent(0, THR_END, 0, 0, 0, 0);
3497 ThreadSanitizerFini();
3498 if (g_race_verifier_active) {
3499 RaceVerifierFini();
3500 }
3501 if (G_flags->show_stats) {
3502 TraceInfo::PrintTraceProfile();
3503 }
3504 if (G_flags->error_exitcode && GetNumberOfFoundErrors() > 0) {
3505 exit(G_flags->error_exitcode);
3506 }
3507 }
3508
3509 //--------- Call Coverage ----------------- {{{1
3510 // A simplistic call coverage tool.
3511 // Outputs all pairs <call_site,call_target>.
3512
3513 typedef set<pair<uintptr_t, uintptr_t> > CallCoverageSet;
3514 static CallCoverageSet *call_coverage_set;
3515
3516 static map<uintptr_t, string> *function_names_map;
3517 static uintptr_t symbolized_functions_cache[1023];
3518 static pair<uintptr_t, uintptr_t> registered_pairs_cache[1023];
3519
symbolize_pc(uintptr_t pc)3520 static void symbolize_pc(uintptr_t pc) {
3521 // Check a simple cache if we already symbolized this pc (racey).
3522 size_t idx = pc % TS_ARRAY_SIZE(symbolized_functions_cache);
3523 if (symbolized_functions_cache[idx] == pc) return;
3524
3525 ScopedReentrantClientLock lock(__LINE__);
3526 CHECK(function_names_map);
3527 if (function_names_map->count(pc) == 0) {
3528 (*function_names_map)[pc] = PcToRtnName(pc, false);
3529 }
3530 symbolized_functions_cache[idx] = pc;
3531 }
3532
CallCoverageRegisterCall(uintptr_t from,uintptr_t to)3533 static void CallCoverageRegisterCall(uintptr_t from, uintptr_t to) {
3534 symbolize_pc(from);
3535 symbolize_pc(to);
3536
3537 // Check if we already registered this pair (racey).
3538 size_t idx = (from ^ to) % TS_ARRAY_SIZE(registered_pairs_cache);
3539 if (registered_pairs_cache[idx] == make_pair(from,to)) return;
3540
3541 ScopedReentrantClientLock lock(__LINE__);
3542 call_coverage_set->insert(make_pair(from, to));
3543 registered_pairs_cache[idx] = make_pair(from,to);
3544 }
3545
CallCoverageCallbackForTRACE(TRACE trace,void * v)3546 static void CallCoverageCallbackForTRACE(TRACE trace, void *v) {
3547 RTN rtn = TRACE_Rtn(trace);
3548 if (RTN_Valid(rtn)) {
3549 SEC sec = RTN_Sec(rtn);
3550 IMG img = SEC_Img(sec);
3551 string img_name = IMG_Name(img);
3552 // Don't instrument system libraries.
3553 if (img_name.find("/usr/") == 0) return;
3554 }
3555
3556 if (call_coverage_set == NULL) {
3557 call_coverage_set = new CallCoverageSet;
3558 function_names_map = new map<uintptr_t, string>;
3559 }
3560 for(BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
3561 INS ins = BBL_InsTail(bbl);
3562 if (!INS_IsProcedureCall(ins) || INS_IsSyscall(ins)) continue;
3563 if (INS_IsDirectBranchOrCall(ins)) {
3564 // If <from, to> is know at instrumentation time, don't instrument.
3565 ADDRINT to = INS_DirectBranchOrCallTargetAddress(ins);
3566 ADDRINT from = INS_Address(ins);
3567 CallCoverageRegisterCall(from, to);
3568 } else {
3569 // target is dynamic. Need to instrument.
3570 INS_InsertCall(ins, IPOINT_BEFORE,
3571 (AFUNPTR)CallCoverageRegisterCall,
3572 IARG_INST_PTR,
3573 IARG_BRANCH_TARGET_ADDR,
3574 IARG_END);
3575 }
3576 }
3577 }
3578
3579 // Output all <from,to> pairs.
CallCoverageCallbackForFini(INT32 code,void * v)3580 static void CallCoverageCallbackForFini(INT32 code, void *v) {
3581 CHECK(call_coverage_set);
3582 CHECK(function_names_map);
3583 for (CallCoverageSet::iterator it = call_coverage_set->begin();
3584 it != call_coverage_set->end(); ++it) {
3585 string from_name = (*function_names_map)[it->first];
3586 string to_name = (*function_names_map)[it->second];
3587 if (to_name == ".plt" || to_name == "") continue;
3588 Printf("CallCoverage: %s => %s\n", from_name.c_str(), to_name.c_str());
3589 }
3590 }
3591
3592 //--------- Main -------------------------- {{{1
main(INT32 argc,CHAR ** argv)3593 int main(INT32 argc, CHAR **argv) {
3594 PIN_Init(argc, argv);
3595 PIN_InitSymbols();
3596 G_out = stderr;
3597
3598 // Init ThreadSanitizer.
3599 int first_param = 1;
3600 // skip until '-t something.so'.
3601 for (; first_param < argc && argv[first_param] != string("-t");
3602 first_param++) {
3603 }
3604 first_param += 2;
3605 vector<string> args;
3606 for (; first_param < argc; first_param++) {
3607 string param = argv[first_param];
3608 if (param == "--") break;
3609 if (param == "-short_name") continue;
3610 if (param == "-slow_asserts") continue;
3611 if (param == "1") continue;
3612 args.push_back(param);
3613 }
3614
3615 G_flags = new FLAGS;
3616 ThreadSanitizerParseFlags(&args);
3617
3618 if (G_flags->dry_run >= 2) {
3619 PIN_StartProgram();
3620 return 0;
3621 }
3622
3623 FILE *socket_output = OpenSocketForWriting(G_flags->log_file);
3624 if (socket_output) {
3625 G_out = socket_output;
3626 } else if (!G_flags->log_file.empty()) {
3627 // Replace %p with tool PID
3628 string fname = G_flags->log_file;
3629 char pid_str[100] = "";
3630 sprintf(pid_str, "%u", getpid());
3631 while (fname.find("%p") != fname.npos)
3632 fname.replace(fname.find("%p"), 2, pid_str);
3633
3634 G_out = fopen(fname.c_str(), "w");
3635 CHECK(G_out);
3636 }
3637
3638 ThreadSanitizerInit();
3639
3640 if (G_flags->call_coverage) {
3641 PIN_AddFiniFunction(CallCoverageCallbackForFini, 0);
3642 TRACE_AddInstrumentFunction(CallCoverageCallbackForTRACE, 0);
3643 PIN_StartProgram();
3644 return 0;
3645 }
3646
3647 tls_reg = PIN_ClaimToolRegister();
3648 CHECK(REG_valid(tls_reg));
3649 #if _MSC_VER
3650 g_windows_thread_pool_calback_set = new unordered_set<uintptr_t>;
3651 g_windows_thread_pool_wait_object_map = new unordered_map<uintptr_t, uintptr_t>;
3652 #endif
3653
3654 // Set up PIN callbacks.
3655 PIN_AddThreadStartFunction(CallbackForThreadStart, 0);
3656 PIN_AddThreadFiniFunction(CallbackForThreadFini, 0);
3657 PIN_AddFiniFunction(CallbackForFini, 0);
3658 IMG_AddInstrumentFunction(CallbackForIMG, 0);
3659 TRACE_AddInstrumentFunction(CallbackForTRACE, 0);
3660 PIN_AddFollowChildProcessFunction(CallbackForExec, NULL);
3661
3662 Report("ThreadSanitizerPin r%s pin %d: %s\n",
3663 TS_VERSION, PIN_BUILD_NUMBER,
3664 G_flags->pure_happens_before ? "hybrid=no" : "hybrid=yes");
3665 if (DEBUG_MODE) {
3666 Report("INFO: Debug build\n");
3667 }
3668
3669 if (g_race_verifier_active) {
3670 RaceVerifierInit(G_flags->race_verifier, G_flags->race_verifier_extra);
3671 global_ignore = true;
3672 }
3673
3674 // Fire!
3675 PIN_StartProgram();
3676 return 0;
3677 }
3678
3679 //--------- Questions about PIN -------------------------- {{{1
3680 /* Questions about PIN:
3681
3682 - Names (e.g. pthread_create@... __pthread_mutex_unlock)
3683 - How to get name of a global var by it's address?
3684 - How to get stack pointer at thread creation?
3685 - How to get a stack trace (other than intercepting calls, entries, exits)
3686 - assert with full stack trace?
3687 */
3688 // end. {{{1
3689 // vim:shiftwidth=2:softtabstop=2:expandtab
3690