Home | History | Annotate | Download | only in tsan
      1 /*
      2   This file is part of ThreadSanitizer, a dynamic data race detector
      3   based on Valgrind.
      4 
      5   Copyright (C) 2008-2010 Google Inc
      6      opensource (at) google.com
      7   Copyright (C) 2007-2008 OpenWorks LLP
      8       info (at) open-works.co.uk
      9 
     10   This program is free software; you can redistribute it and/or
     11   modify it under the terms of the GNU General Public License as
     12   published by the Free Software Foundation; either version 2 of the
     13   License, or (at your option) any later version.
     14 
     15   This program is distributed in the hope that it will be useful, but
     16   WITHOUT ANY WARRANTY; without even the implied warranty of
     17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     18   General Public License for more details.
     19 
     20   You should have received a copy of the GNU General Public License
     21   along with this program; if not, write to the Free Software
     22   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     23   02111-1307, USA.
     24 
     25   The GNU General Public License is contained in the file COPYING.
     26 */
     27 
     28 // Author: Konstantin Serebryany.
     29 // Parts of the code in this file are derived from Helgrind,
     30 // a data race detector written by Julian Seward.
     31 // Note that the rest of ThreadSanitizer code is not derived from Helgrind
     32 // and is published under the BSD license.
     33 
     34 #include "ts_valgrind.h"
     35 #include "valgrind.h"
     36 #include "ts_valgrind_client_requests.h"
     37 #include "thread_sanitizer.h"
     38 #include "ts_trace_info.h"
     39 #include "ts_race_verifier.h"
     40 #include "common_util.h"
     41 
     42 #include "coregrind/pub_core_basics.h"
     43 #include "coregrind/pub_core_machine.h"
     44 #include "coregrind/pub_core_clreq.h"
     45 #include "pub_tool_libcsetjmp.h"
     46 #include "coregrind/pub_core_threadstate.h"
     47 #include "pub_tool_libcproc.h"
     48 
     49 
     50 //---------------------- C++ malloc support -------------- {{{1
     51 void *operator new (size_t size) {
     52   return VG_(malloc)((HChar*)g_malloc_stack.Top(), size);
     53 }
     54 void *operator new [](size_t size) {
     55   return VG_(malloc)((HChar*)g_malloc_stack.Top(), size);
     56 }
     57 void operator delete (void *p) {
     58   VG_(free)(p);
     59 }
     60 void operator delete [](void *p) {
     61   VG_(free)(p);
     62 }
     63 
     64 extern "C" void *malloc(size_t size) {
     65   return VG_(malloc)((HChar*)g_malloc_stack.Top(), size);
     66 }
     67 
     68 extern "C" void free(void *ptr) {
     69   VG_(free)(ptr);
     70 }
     71 
     72 extern "C" void* realloc(void *ptr, size_t size) {
     73   return VG_(realloc)((HChar*)g_malloc_stack.Top(), ptr, size);
     74 }
     75 
     76 
     77 //---------------------- Utils ------------------- {{{1
     78 
     79 extern "C" int puts(const char *s) {
     80   Printf("%s", s);
     81   return 1;
     82 }
     83 
     84 extern "C" void exit(int e) { VG_(exit)(e); }
     85 
     86 #ifdef VGO_darwin
     87 extern "C" void abort() { CHECK(0); }
     88 #endif
     89 
     90 
     91 // TODO: make this rtn public
     92 extern "C" {
     93   Bool VG_(get_fnname_no_cxx_demangle) ( Addr a, Char* buf, Int nbuf );
     94 }
     95 
     96 
     97 const int kBuffSize = 1024 * 10 - 1;
     98 // not thread-safe.
     99 static char g_buff1[kBuffSize+1];
    100 static char g_buff2[kBuffSize+1];
    101 
    102 string PcToRtnName(uintptr_t pc, bool demangle) {
    103   if (demangle) {
    104     if(VG_(get_fnname)(pc, (Char*)g_buff1, kBuffSize)) {
    105       return g_buff1;
    106     }
    107   } else {
    108     if(VG_(get_fnname_no_cxx_demangle)(pc, (Char*)g_buff1, kBuffSize)) {
    109       return g_buff1;
    110     }
    111   }
    112   return "(no symbols)";
    113 }
    114 
    115 void PcToStrings(uintptr_t pc, bool demangle,
    116                 string *img_name, string *rtn_name,
    117                 string *file_name, int *line_no) {
    118   const int kBuffSize = 1024 * 10 - 1;
    119   Bool has_dirname = False;
    120 
    121   if (VG_(get_filename_linenum)
    122       (pc, (Char*)g_buff1, kBuffSize, (Char*)g_buff2, kBuffSize,
    123        &has_dirname, (UInt*)line_no) &&
    124       has_dirname) {
    125     *file_name = string(g_buff2) + "/" + g_buff1;
    126   } else {
    127     VG_(get_linenum)(pc, (UInt *)line_no);
    128     if (VG_(get_filename)(pc, (Char*)g_buff1, kBuffSize)) {
    129       *file_name = g_buff1;
    130     }
    131   }
    132   *file_name = ConvertToPlatformIndependentPath(*file_name);
    133 
    134   *rtn_name = PcToRtnName(pc, demangle);
    135 
    136   if (VG_(get_objname)(pc, (Char*)g_buff1, kBuffSize)) {
    137     *img_name = g_buff1;
    138   }
    139 }
    140 
    141 
    142 
    143 string Demangle(const char *str) {
    144   return str;
    145 }
    146 
    147 extern "C"
    148 size_t strlen(const char *s) {
    149   return VG_(strlen)((const Char*)s);
    150 }
    151 
    152 static inline ThreadId GetVgTid() {
    153   extern ThreadId VG_(running_tid); // HACK: avoid calling get_running_tid()
    154   ThreadId res = VG_(running_tid);
    155   //DCHECK(res == VG_(get_running_tid)());
    156   return res;
    157 }
    158 
    159 static inline uintptr_t GetVgPc(ThreadId vg_tid) {
    160   Addr pc = VG_(threads)[vg_tid].arch.vex.VG_INSTR_PTR;
    161   DCHECK(pc == VG_(get_IP)(vg_tid));
    162   return pc;
    163   //return (uintptr_t)VG_(get_IP)(vg_tid);
    164 }
    165 
    166 static inline uintptr_t GetVgSp(ThreadId vg_tid) {
    167   Addr sp = VG_(threads)[vg_tid].arch.vex.VG_STACK_PTR;
    168   DCHECK(sp == VG_(get_SP)(vg_tid));
    169   return sp;
    170 }
    171 
    172 #ifdef VGP_arm_linux
    173 static inline uintptr_t GetVgLr(ThreadId vg_tid) {
    174   return (uintptr_t)VG_(threads)[vg_tid].arch.vex.guest_R14;
    175 }
    176 #endif
    177 
    178 static uintptr_t g_current_pc;
    179 
    180 uintptr_t GetPcOfCurrentThread() {
    181   return g_current_pc;
    182 }
    183 
    184 void GetThreadStack(int tid, uintptr_t *min_addr, uintptr_t *max_addr) {
    185   // tid is not used because we call it from the current thread anyway.
    186   uintptr_t stack_max  = VG_(thread_get_stack_max)(GetVgTid());
    187   uintptr_t stack_size = VG_(thread_get_stack_size)(GetVgTid());
    188   uintptr_t stack_min  = stack_max - stack_size;
    189   *min_addr = stack_min;
    190   *max_addr = stack_max;
    191 }
    192 
    193 struct CallStackRecord {
    194   Addr pc;
    195   Addr sp;
    196 #ifdef VGP_arm_linux
    197   // We need to store LR in order to keep the shadow stack consistent.
    198   Addr lr;
    199 #endif
    200 };
    201 
    202 const size_t kMaxMopsPerTrace = 2048;
    203 
    204 struct ValgrindThread {
    205   int32_t zero_based_uniq_tid;
    206   TSanThread *ts_thread;
    207   uint32_t literace_sampling;
    208   vector<CallStackRecord> call_stack;
    209 
    210   int ignore_accesses;
    211   int ignore_sync;
    212   int in_signal_handler;
    213 
    214   // thread-local event buffer (tleb).
    215   uintptr_t tleb[kMaxMopsPerTrace];
    216   TraceInfo *trace_info;
    217 
    218   // PC (as in trace_info->pc()) of the trace currently being verified.
    219   // 0 if outside of the verification sleep loop.
    220   // -1 in the last iteration of the loop.
    221   uintptr_t verifier_current_pc;
    222 
    223   // End time of the current verification loop.
    224   unsigned verifier_wakeup_time_ms;
    225 
    226   ValgrindThread() {
    227     Clear();
    228   }
    229 
    230   void Clear() {
    231     ts_thread = NULL;
    232     zero_based_uniq_tid = -1;
    233     literace_sampling = G_flags->literace_sampling;  // cache it.
    234     ignore_accesses = 0;
    235     ignore_sync = 0;
    236     in_signal_handler = 0;
    237     call_stack.clear();
    238     trace_info = NULL;
    239     verifier_current_pc = 0;
    240     verifier_wakeup_time_ms = 0;
    241   }
    242 };
    243 
    244 // If true, ignore all accesses in all threads.
    245 extern bool global_ignore;
    246 
    247 // Array of VG_N_THREADS
    248 static ValgrindThread *g_valgrind_threads = 0;
    249 static map<uintptr_t, int> *g_ptid_to_ts_tid;
    250 
    251 // maintains a uniq thread id (first thread will have id=0)
    252 static int32_t g_uniq_thread_id_counter = 0;
    253 
    254 static int32_t VgTidToTsTid(ThreadId vg_tid) {
    255   DCHECK(vg_tid < VG_N_THREADS);
    256   DCHECK(vg_tid >= 1);
    257   DCHECK(g_valgrind_threads);
    258   DCHECK(g_valgrind_threads[vg_tid].zero_based_uniq_tid >= 0);
    259   return g_valgrind_threads[vg_tid].zero_based_uniq_tid;
    260 }
    261 
    262 static vector<string> *g_command_line_options = 0;
    263 static void InitCommandLineOptions() {
    264   if(G_flags == NULL) {
    265     G_flags = new FLAGS;
    266   }
    267   if (g_command_line_options == NULL) {
    268     g_command_line_options = new vector<string>;
    269   }
    270 }
    271 
    272 Bool ts_process_cmd_line_option (Char* arg) {
    273   InitCommandLineOptions();
    274   g_command_line_options->push_back((char*)arg);
    275   return True;
    276 }
    277 
    278 void ts_print_usage (void) {
    279   InitCommandLineOptions();
    280   ThreadSanitizerParseFlags(g_command_line_options);
    281 
    282   ThreadSanitizerPrintUsage();
    283 }
    284 
    285 void ts_print_debug_usage(void) {
    286   ThreadSanitizerPrintUsage();
    287 }
    288 
    289 extern int VG_(clo_error_exitcode);
    290 
    291 void ts_post_clo_init(void) {
    292   ScopedMallocCostCenter malloc_cc(__FUNCTION__);
    293   InitCommandLineOptions();
    294   ThreadSanitizerParseFlags(g_command_line_options);
    295 
    296   // we get num-callers from valgrind flags.
    297   G_flags->num_callers = VG_(clo_backtrace_size);
    298   if (!G_flags->error_exitcode)
    299     G_flags->error_exitcode = VG_(clo_error_exitcode);
    300 
    301   extern Int   VG_(clo_n_suppressions);
    302   extern Int   VG_(clo_gen_suppressions);
    303   extern Char* VG_(clo_suppressions)[];
    304   extern Int   VG_(clo_n_fullpath_after);
    305   extern Char* VG_(clo_fullpath_after)[];
    306   // get the suppressions from Valgrind
    307   for (int i = 0; i < VG_(clo_n_suppressions); i++) {
    308     G_flags->suppressions.push_back((char*)VG_(clo_suppressions)[i]);
    309   }
    310   // get the --fullpath-after prefixes from Valgrind and treat them as
    311   // --file-prefix-to-cut arguments.
    312   for (int i = 0; i < VG_(clo_n_fullpath_after); i++) {
    313     G_flags->file_prefix_to_cut.push_back((char*)VG_(clo_fullpath_after)[i]);
    314   }
    315   G_flags->generate_suppressions |= VG_(clo_gen_suppressions) >= 1;
    316 
    317   if (G_flags->html) {
    318     Report("<pre>\n"
    319            "<br id=race0>"
    320            "<a href=\"#race1\">Go to first race report</a>\n");
    321   }
    322   Report("ThreadSanitizerValgrind r%s: %s\n",
    323          TS_VERSION,
    324          G_flags->pure_happens_before ? "hybrid=no" : "hybrid=yes");
    325   if (DEBUG_MODE) {
    326     Report("INFO: Debug build\n");
    327   }
    328   if (G_flags->max_mem_in_mb) {
    329     Report("INFO: ThreadSanitizer memory limit: %dMB\n",
    330            (int)G_flags->max_mem_in_mb);
    331   }
    332   ThreadSanitizerInit();
    333 
    334   g_valgrind_threads = new ValgrindThread[VG_N_THREADS];
    335   g_ptid_to_ts_tid = new map<uintptr_t, int>;
    336 
    337   if (g_race_verifier_active) {
    338     RaceVerifierInit(G_flags->race_verifier, G_flags->race_verifier_extra);
    339     global_ignore = true;
    340   }
    341 }
    342 
    343 // Remember, valgrind is essentially single-threaded.
    344 // Each time we switch to another thread, we set the global g_cur_tleb
    345 // to the tleb of the current thread. This allows to load the tleb in one
    346 // instruction.
    347 static uintptr_t *g_cur_tleb;
    348 static void OnStartClientCode(ThreadId vg_tid, ULong nDisp) {
    349   ValgrindThread *thr = &g_valgrind_threads[vg_tid];
    350   g_cur_tleb = thr->tleb;
    351 }
    352 
    353 INLINE void FlushMops(ValgrindThread *thr, bool keep_trace_info = false) {
    354   DCHECK(!g_race_verifier_active || global_ignore);
    355   TraceInfo *t = thr->trace_info;
    356   if (!t) return;
    357   if (!keep_trace_info) {
    358     thr->trace_info = NULL;
    359   }
    360 
    361   if (global_ignore || thr->ignore_accesses ||
    362        (thr->literace_sampling &&
    363         t->LiteRaceSkipTraceRealTid(thr->zero_based_uniq_tid, thr->literace_sampling))) {
    364     thr->trace_info = NULL;
    365     return;
    366   }
    367 
    368   size_t n = t->n_mops();
    369   DCHECK(n > 0);
    370   uintptr_t *tleb = thr->tleb;
    371   DCHECK(thr->ts_thread);
    372   ThreadSanitizerHandleTrace(thr->ts_thread, t, tleb);
    373 }
    374 
    375 static void ShowCallStack(ValgrindThread *thr) {
    376   size_t n = thr->call_stack.size();
    377   Printf("        ");
    378   for (size_t i = n - 1; i > n - 10 && i >= 0; i--) {
    379     Printf("{pc=%p sp=%p}, ", thr->call_stack[i].pc, thr->call_stack[i].sp);
    380   }
    381   Printf("\n");
    382 }
    383 
    384 static INLINE void UpdateCallStack(ValgrindThread *thr, uintptr_t sp) {
    385   DCHECK(!g_race_verifier_active);
    386   if (thr->trace_info) FlushMops(thr, true /* keep_trace_info */);
    387   vector<CallStackRecord> &call_stack = thr->call_stack;
    388   while (!call_stack.empty()) {
    389     CallStackRecord &record = call_stack.back();
    390     Addr cur_top = record.sp;
    391     if (sp < cur_top) break;
    392     call_stack.pop_back();
    393     int32_t ts_tid = thr->zero_based_uniq_tid;
    394     ThreadSanitizerHandleRtnExit(ts_tid);
    395     if (debug_rtn) {
    396       Printf("T%d: [%ld]<< pc=%p sp=%p cur_sp=%p %s\n",
    397              ts_tid, thr->call_stack.size(), record.pc,
    398              record.sp, sp,
    399              PcToRtnNameAndFilePos(record.pc).c_str());
    400       ShowCallStack(thr);
    401     }
    402   }
    403 }
    404 
    405 VG_REGPARM(1)
    406 static void OnTrace(TraceInfo *trace_info) {
    407   DCHECK(!g_race_verifier_active);
    408   //trace_info->counter()++;
    409   if (global_ignore) return;
    410   ThreadId vg_tid = GetVgTid();
    411   ValgrindThread *thr = &g_valgrind_threads[vg_tid];
    412 
    413   // First, flush the old trace_info.
    414   if (thr->trace_info) {
    415     FlushMops(thr);
    416   }
    417 
    418   UpdateCallStack(thr, GetVgSp(vg_tid));
    419 
    420   // Start the new trace, zero the contents of tleb.
    421   size_t n = trace_info->n_mops();
    422   uintptr_t *tleb = thr->tleb;
    423   for (size_t i = 0; i < n; i++)
    424     tleb[i] = 0;
    425   thr->trace_info = trace_info;
    426   DCHECK(thr->trace_info);
    427   DCHECK(thr->trace_info->n_mops() <= kMaxMopsPerTrace);
    428 }
    429 
    430 static inline void Put(EventType type, int32_t tid, uintptr_t pc,
    431                        uintptr_t a, uintptr_t info) {
    432   if (DEBUG_MODE && G_flags->dry_run >= 1) return;
    433   Event event(type, tid, pc, a, info);
    434   ThreadSanitizerHandleOneEvent(&event);
    435 }
    436 
    437 static void rtn_call(Addr sp_post_call_insn, Addr pc_post_call_insn,
    438                      IGNORE_BELOW_RTN ignore_below) {
    439   DCHECK(!g_race_verifier_active);
    440   if (global_ignore) return;
    441   ThreadId vg_tid = GetVgTid();
    442   ValgrindThread *thr = &g_valgrind_threads[vg_tid];
    443   int ts_tid = thr->zero_based_uniq_tid;
    444   CallStackRecord record;
    445   record.pc = pc_post_call_insn;
    446   record.sp = sp_post_call_insn + 4;  // sp before call.
    447   UpdateCallStack(thr, record.sp);
    448 #ifdef VGP_arm_linux
    449   record.lr = GetVgLr(vg_tid);
    450 #endif
    451   thr->call_stack.push_back(record);
    452   // If the shadow stack grows too high this usually means it is not cleaned
    453   // properly. Or this may be a very deep recursion.
    454   DCHECK(thr->call_stack.size() < 10000);
    455   uintptr_t call_pc = GetVgPc(vg_tid);
    456   if (thr->trace_info) FlushMops(thr);
    457   ThreadSanitizerHandleRtnCall(ts_tid, call_pc, record.pc,
    458                                ignore_below);
    459 
    460   if (debug_rtn) {
    461     Printf("T%d: [%ld]>> pc=%p sp=%p %s\n",
    462            ts_tid, thr->call_stack.size(), (void*)record.pc,
    463            (void*)record.sp,
    464            PcToRtnNameAndFilePos(record.pc).c_str());
    465     ShowCallStack(thr);
    466   }
    467 }
    468 
    469 VG_REGPARM(2) void evh__rtn_call_ignore_unknown ( Addr sp, Addr pc) {
    470   rtn_call(sp, pc, IGNORE_BELOW_RTN_UNKNOWN);
    471 }
    472 VG_REGPARM(2) void evh__rtn_call_ignore_yes ( Addr sp, Addr pc) {
    473   rtn_call(sp, pc, IGNORE_BELOW_RTN_YES);
    474 }
    475 VG_REGPARM(2) void evh__rtn_call_ignore_no ( Addr sp, Addr pc) {
    476   rtn_call(sp, pc, IGNORE_BELOW_RTN_NO);
    477 }
    478 
    479 #ifdef VGP_arm_linux
    480 // Handle shadow stack frame deletion on ARM.
    481 // Instrumented code calls this function for each non-call jump out of
    482 // a superblock. If the |sp_post_call_insn| (the jump target address) is equal
    483 // to a link register value of one or more frames on top of the shadow stack,
    484 // those frames are popped out.
    485 // TODO(glider): there may be problems with optimized recursive functions that
    486 // don't change PC, SP and LR.
    487 VG_REGPARM(2)
    488 void evh__delete_frame ( Addr sp_post_call_insn,
    489                          Addr pc_post_call_insn) {
    490   DCHECK(!g_race_verifier_active);
    491   ThreadId vg_tid = GetVgTid();
    492   ValgrindThread *thr = &g_valgrind_threads[vg_tid];
    493   if (thr->trace_info) FlushMops(thr);
    494   vector<CallStackRecord> &call_stack = thr->call_stack;
    495   int32_t ts_tid = VgTidToTsTid(vg_tid);
    496   while (!call_stack.empty()) {
    497     CallStackRecord &record = call_stack.back();
    498     if (record.lr != pc_post_call_insn) break;
    499     call_stack.pop_back();
    500     ThreadSanitizerHandleRtnExit(ts_tid);
    501   }
    502 }
    503 #endif
    504 
    505 void ts_fini(Int exitcode) {
    506   ThreadSanitizerFini();
    507   if (g_race_verifier_active) {
    508     RaceVerifierFini();
    509   }
    510   if (G_flags->error_exitcode && GetNumberOfFoundErrors() > 0) {
    511     exit(G_flags->error_exitcode);
    512   }
    513 }
    514 
    515 
    516 void evh__pre_thread_ll_create ( ThreadId parent, ThreadId child ) {
    517   tl_assert(parent != child);
    518   ValgrindThread *thr = &g_valgrind_threads[child];
    519   //  Printf("thread_create: %d->%d\n", parent, child);
    520   if (thr->zero_based_uniq_tid != -1) {
    521     Printf("ThreadSanitizer WARNING: reusing TID %d w/o exiting thread\n",
    522            child);
    523   }
    524   thr->Clear();
    525   thr->zero_based_uniq_tid = g_uniq_thread_id_counter++;
    526   // Printf("VG: T%d: VG_THR_START: parent=%d\n", VgTidToTsTid(child), VgTidToTsTid(parent));
    527   Put(THR_START, VgTidToTsTid(child), 0, 0,
    528       parent > 0 ? VgTidToTsTid(parent) : 0);
    529   thr->ts_thread = ThreadSanitizerGetThreadByTid(thr->zero_based_uniq_tid);
    530   CHECK(thr->ts_thread);
    531 }
    532 
    533 void evh__pre_workq_task_start(ThreadId vg_tid, Addr workitem) {
    534   uintptr_t pc = GetVgPc(vg_tid);
    535   int32_t ts_tid = VgTidToTsTid(vg_tid);
    536   ValgrindThread *thr = &g_valgrind_threads[vg_tid];
    537   FlushMops(thr);
    538   Put(WAIT, ts_tid, pc, workitem, 0);
    539 }
    540 
    541 void evh__pre_thread_first_insn(const ThreadId vg_tid) {
    542   ValgrindThread *thr = &g_valgrind_threads[vg_tid];
    543   FlushMops(thr);
    544   Put(THR_FIRST_INSN, VgTidToTsTid(vg_tid), GetVgPc(vg_tid), 0, 0);
    545 }
    546 
    547 
    548 void evh__pre_thread_ll_exit ( ThreadId quit_tid ) {
    549 //  Printf("thread_exit: %d\n", quit_tid);
    550 //  Printf("T%d quiting thread; stack size=%ld\n",
    551 //         VgTidToTsTid(quit_tid),
    552 //         (int)g_valgrind_threads[quit_tid].call_stack.size());
    553   ValgrindThread *thr = &g_valgrind_threads[quit_tid];
    554   FlushMops(thr);
    555   Put(THR_END, VgTidToTsTid(quit_tid), 0, 0, 0);
    556   g_valgrind_threads[quit_tid].zero_based_uniq_tid = -1;
    557 }
    558 
    559   extern "C" void VG_(show_all_errors)();
    560 
    561 // Whether we are currently ignoring sync events for the given thread at the
    562 // given address.
    563 static inline Bool ignoring_sync(ThreadId vg_tid, uintptr_t addr) {
    564   // We ignore locking events if ignore_sync != 0 and if we are not
    565   // inside a signal handler.
    566   return (g_valgrind_threads[vg_tid].ignore_sync &&
    567           !g_valgrind_threads[vg_tid].in_signal_handler) ||
    568       ThreadSanitizerIgnoreForNacl(addr);
    569 }
    570 
    571 Bool ts_handle_client_request(ThreadId vg_tid, UWord* args, UWord* ret) {
    572   if (args[0] == VG_USERREQ__NACL_MEM_START) {
    573     // This will get truncated on x86-32, but we don't support it with NaCl
    574     // anyway.
    575     const uintptr_t kFourGig = (uintptr_t)0x100000000ULL;
    576     uintptr_t mem_start = args[1];
    577     uintptr_t mem_end = mem_start + kFourGig;
    578     ThreadSanitizerNaclUntrustedRegion(mem_start, mem_end);
    579     return True;
    580   }
    581   if (!VG_IS_TOOL_USERREQ('T', 'S', args[0]))
    582     return False;
    583   int32_t ts_tid = VgTidToTsTid(vg_tid);
    584   // Ignore almost everything in race verifier mode.
    585   if (g_race_verifier_active) {
    586     if (args[0] == TSREQ_EXPECT_RACE) {
    587       Put(EXPECT_RACE, ts_tid, /*descr=*/args[2],
    588           /*p=*/args[1], 0);
    589     }
    590     *ret = 0;
    591     return True;
    592   }
    593   ValgrindThread *thr = &g_valgrind_threads[vg_tid];
    594   if (thr->trace_info) FlushMops(thr);
    595   UpdateCallStack(thr, GetVgSp(vg_tid));
    596   *ret = 0;
    597   uintptr_t pc = GetVgPc(vg_tid);
    598   switch (args[0]) {
    599     case TSREQ_SET_MY_PTHREAD_T:
    600       (*g_ptid_to_ts_tid)[args[1]] = ts_tid;
    601       break;
    602     case TSREQ_THR_STACK_TOP:
    603       Put(THR_STACK_TOP, ts_tid, pc, args[1], 0);
    604       break;
    605     case TSREQ_PTHREAD_JOIN_POST:
    606       Put(THR_JOIN_AFTER, ts_tid, pc, (*g_ptid_to_ts_tid)[args[1]], 0);
    607       break;
    608     case TSREQ_CLEAN_MEMORY:
    609       Put(MALLOC, ts_tid, pc, /*ptr=*/args[1], /*size=*/args[2]);
    610       break;
    611     case TSREQ_MAIN_IN:
    612       g_has_entered_main = true;
    613       // Report("INFO: Entred main(); argc=%d\n", (int)args[1]);
    614       break;
    615     case TSREQ_MAIN_OUT:
    616       g_has_exited_main = true;
    617       if (G_flags->exit_after_main) {
    618         Report("INFO: Exited main(); ret=%d\n", (int)args[1]);
    619         VG_(show_all_errors)();
    620         ThreadSanitizerFini();
    621         if (g_race_verifier_active) {
    622           RaceVerifierFini();
    623         }
    624         exit((int)args[1]);
    625       }
    626       break;
    627     case TSREQ_MALLOC:
    628       // Printf("Malloc: %p %ld\n", args[1], args[2]);
    629       Put(MALLOC, ts_tid, pc, /*ptr=*/args[1], /*size=*/args[2]);
    630       break;
    631     case TSREQ_FREE:
    632       // Printf("Free: %p\n", args[1]);
    633       Put(FREE, ts_tid, pc, /*ptr=*/args[1], 0);
    634       break;
    635     case TSREQ_MMAP:
    636       Put(MMAP, ts_tid, pc, /*ptr=*/args[1], /*size=*/args[2]);
    637       break;
    638     case TSREQ_MUNMAP:
    639       Put(MUNMAP, ts_tid, pc, /*ptr=*/args[1], /*size=*/args[2]);
    640       break;
    641     case TSREQ_BENIGN_RACE:
    642       Put(BENIGN_RACE, ts_tid, /*descr=*/args[3],
    643           /*p=*/args[1], /*size=*/args[2]);
    644       break;
    645     case TSREQ_EXPECT_RACE:
    646       Put(EXPECT_RACE, ts_tid, /*descr=*/args[2], /*p=*/args[1], 0);
    647       break;
    648     case TSREQ_FLUSH_EXPECTED_RACES:
    649       Put(FLUSH_EXPECTED_RACES, ts_tid, 0, 0, 0);
    650       break;
    651     case TSREQ_PCQ_CREATE:
    652       Put(PCQ_CREATE, ts_tid, pc, /*pcq=*/args[1], 0);
    653       break;
    654     case TSREQ_PCQ_DESTROY:
    655       Put(PCQ_DESTROY, ts_tid, pc, /*pcq=*/args[1], 0);
    656       break;
    657     case TSREQ_PCQ_PUT:
    658       Put(PCQ_PUT, ts_tid, pc, /*pcq=*/args[1], 0);
    659       break;
    660     case TSREQ_PCQ_GET:
    661       Put(PCQ_GET, ts_tid, pc, /*pcq=*/args[1], 0);
    662       break;
    663     case TSREQ_TRACE_MEM:
    664       Put(TRACE_MEM, ts_tid, pc, /*mem=*/args[1], 0);
    665       break;
    666     case TSREQ_MUTEX_IS_USED_AS_CONDVAR:
    667       Put(HB_LOCK, ts_tid, pc, /*lock=*/args[1], 0);
    668       break;
    669     case TSREQ_MUTEX_IS_NOT_PHB:
    670       Put(NON_HB_LOCK, ts_tid, pc, /*lock=*/args[1], 0);
    671       break;
    672     case TSREQ_GLOBAL_IGNORE_ON:
    673       Report("INFO: GLOBAL IGNORE ON\n");
    674       global_ignore = true;
    675       break;
    676     case TSREQ_GLOBAL_IGNORE_OFF:
    677       Report("INFO: GLOBAL IGNORE OFF\n");
    678       global_ignore = false;
    679       break;
    680     case TSREQ_IGNORE_READS_BEGIN:
    681       Put(IGNORE_READS_BEG, ts_tid, pc, 0, 0);
    682       break;
    683     case TSREQ_IGNORE_READS_END:
    684       Put(IGNORE_READS_END, ts_tid, pc, 0, 0);
    685       break;
    686     case TSREQ_IGNORE_WRITES_BEGIN:
    687       Put(IGNORE_WRITES_BEG, ts_tid, pc, 0, 0);
    688       break;
    689     case TSREQ_IGNORE_WRITES_END:
    690       Put(IGNORE_WRITES_END, ts_tid, pc, 0, 0);
    691       break;
    692     case TSREQ_SET_THREAD_NAME:
    693       Put(SET_THREAD_NAME, ts_tid, pc, /*name=*/args[1], 0);
    694       break;
    695     case TSREQ_SET_STACKTOP_STACKSIZE:
    696       Put(THR_STACK_TOP, ts_tid, pc, /*addr=*/args[1], /*size=*/args[2]);
    697       break;
    698     case TSREQ_IGNORE_ALL_ACCESSES_BEGIN:
    699       g_valgrind_threads[vg_tid].ignore_accesses++;
    700       break;
    701     case TSREQ_IGNORE_ALL_ACCESSES_END:
    702       g_valgrind_threads[vg_tid].ignore_accesses--;
    703       CHECK(g_valgrind_threads[vg_tid].ignore_accesses >= 0);
    704       break;
    705     case TSREQ_IGNORE_ALL_SYNC_BEGIN:
    706       g_valgrind_threads[vg_tid].ignore_sync++;
    707       break;
    708     case TSREQ_IGNORE_ALL_SYNC_END:
    709       g_valgrind_threads[vg_tid].ignore_sync--;
    710       CHECK(g_valgrind_threads[vg_tid].ignore_sync >= 0);
    711       break;
    712     case TSREQ_PUBLISH_MEMORY_RANGE:
    713       Put(PUBLISH_RANGE, ts_tid, pc, /*mem=*/args[1], /*size=*/args[2]);
    714       break;
    715     case TSREQ_UNPUBLISH_MEMORY_RANGE:
    716       Put(UNPUBLISH_RANGE, ts_tid, pc, /*mem=*/args[1], /*size=*/args[2]);
    717       break;
    718     case TSREQ_PRINT_MEMORY_USAGE:
    719     case TSREQ_PRINT_STATS:
    720     case TSREQ_RESET_STATS:
    721     case TSREQ_PTH_API_ERROR:
    722       break;
    723     case TSREQ_PTHREAD_RWLOCK_CREATE_POST:
    724       if (ignoring_sync(vg_tid, args[1]))
    725         break;
    726       Put(LOCK_CREATE, ts_tid, pc, /*lock=*/args[1], 0);
    727       break;
    728     case TSREQ_PTHREAD_RWLOCK_DESTROY_PRE:
    729       if (ignoring_sync(vg_tid, args[1]))
    730         break;
    731       Put(LOCK_DESTROY, ts_tid, pc, /*lock=*/args[1], 0);
    732       break;
    733     case TSREQ_PTHREAD_RWLOCK_LOCK_POST:
    734       if (ignoring_sync(vg_tid, args[1]))
    735         break;
    736       Put(args[2] ? WRITER_LOCK : READER_LOCK, ts_tid, pc, /*lock=*/args[1], 0);
    737       break;
    738     case TSREQ_PTHREAD_RWLOCK_UNLOCK_PRE:
    739       if (ignoring_sync(vg_tid, args[1]))
    740         break;
    741       Put(UNLOCK, ts_tid, pc, /*lock=*/args[1], 0);
    742       break;
    743     case TSREQ_PTHREAD_SPIN_LOCK_INIT_OR_UNLOCK:
    744       Put(UNLOCK_OR_INIT, ts_tid, pc, /*lock=*/args[1], 0);
    745       break;
    746     case TSREQ_POSIX_SEM_INIT_POST:
    747     case TSREQ_POSIX_SEM_DESTROY_PRE:
    748       break;
    749     case TSREQ_SIGNAL:
    750       if (ignoring_sync(vg_tid, args[1]))
    751         break;
    752       Put(SIGNAL, ts_tid, pc, args[1], 0);
    753       break;
    754     case TSREQ_WAIT:
    755       if (ignoring_sync(vg_tid, args[1]))
    756         break;
    757       Put(WAIT, ts_tid, pc, args[1], 0);
    758       break;
    759     case TSREQ_CYCLIC_BARRIER_INIT:
    760       Put(CYCLIC_BARRIER_INIT, ts_tid, pc, args[1], args[2]);
    761       break;
    762     case TSREQ_CYCLIC_BARRIER_WAIT_BEFORE:
    763       Put(CYCLIC_BARRIER_WAIT_BEFORE, ts_tid, pc, args[1], 0);
    764       break;
    765     case TSREQ_CYCLIC_BARRIER_WAIT_AFTER:
    766       Put(CYCLIC_BARRIER_WAIT_AFTER, ts_tid, pc, args[1], 0);
    767       break;
    768     case TSREQ_GET_MY_SEGMENT:
    769       break;
    770     case TSREQ_GET_THREAD_ID:
    771       *ret = ts_tid;
    772       break;
    773     case TSREQ_GET_VG_THREAD_ID:
    774       *ret = vg_tid;
    775       break;
    776     case TSREQ_GET_SEGMENT_ID:
    777       break;
    778     case TSREQ_THREAD_SANITIZER_QUERY:
    779       *ret = (UWord)ThreadSanitizerQuery((const char *)args[1]);
    780       break;
    781     case TSREQ_FLUSH_STATE:
    782       Put(FLUSH_STATE, ts_tid, pc, 0, 0);
    783       break;
    784     default: CHECK(0);
    785   }
    786   return True;
    787 }
    788 
    789 static void SignalIn(ThreadId vg_tid, Int sigNo, Bool alt_stack) {
    790   g_valgrind_threads[vg_tid].in_signal_handler++;
    791   DCHECK(g_valgrind_threads[vg_tid].in_signal_handler == 1);
    792 //  int32_t ts_tid = VgTidToTsTid(vg_tid);
    793 //  Printf("T%d %s\n", ts_tid, __FUNCTION__);
    794 }
    795 
    796 static void SignalOut(ThreadId vg_tid, Int sigNo) {
    797   g_valgrind_threads[vg_tid].in_signal_handler--;
    798   CHECK(g_valgrind_threads[vg_tid].in_signal_handler >= 0);
    799   DCHECK(g_valgrind_threads[vg_tid].in_signal_handler == 0);
    800 //  int32_t ts_tid = VgTidToTsTid(vg_tid);
    801 //  Printf("T%d %s\n", ts_tid, __FUNCTION__);
    802 }
    803 
    804 
    805 // ---------------------------- RaceVerifier    ---------------------------{{{1
    806 
    807 /**
    808  * In race verifier mode _every_ IRSB is instrumented with a sleep loop at the
    809  * beginning (but, of course, in most cases it is not executed).
    810  * Its code logically looks like
    811  *  irsb_start:
    812  *   bool need_sleep = OnTraceVerify1();
    813  *   if (need_sleep) {
    814  *     sched_yield();
    815  *     goto irsb_start;
    816  *   }
    817  *   OnTraceVerify2(trace_info);
    818  *
    819  * This loop verifies mops from the _previous_ trace_info and sets up the new
    820  * trace info in OnTraceVerify2. Only IRSBs with "interesting" mops have
    821  * non-zero trace_info.
    822  */
    823 
    824 /**
    825  * Race verification loop.
    826  * On the first pass (for a trace_info), if there are mops to be verified,
    827  * register them with RaceVerifier and calculate the wake up time.
    828  * On the following passes, check the wake up time against the clock.
    829  * The loop state is kept in ValgrindThread.
    830  * Returns true if need to sleep more, false if the loop must be ended.
    831  */
    832 VG_REGPARM(1)
    833 static uint32_t OnTraceVerify1() {
    834   DCHECK(g_race_verifier_active);
    835   ThreadId vg_tid = GetVgTid();
    836 
    837   // First, flush the old trace_info.
    838   ValgrindThread *thr = &g_valgrind_threads[vg_tid];
    839 
    840   // thr->trace_info is the trace info for the previous superblock.
    841   if (!thr->trace_info)
    842     // Nothing to do here.
    843     return 0;
    844 
    845   if (!thr->verifier_current_pc) {
    846     // This is the first iteration of the sleep loop.
    847     // Register memory accesses.
    848     int sleep_time_ms = RaceVerifierGetSleepTime(thr->trace_info->pc());
    849     if (!sleep_time_ms) {
    850       thr->trace_info = NULL;
    851       return 0;
    852     }
    853     size_t n = thr->trace_info->n_mops();
    854     uintptr_t* tleb = thr->tleb;
    855     int need_sleep = 0;
    856     for (size_t i = 0; i < n; ++i) {
    857       uintptr_t addr = tleb[i];
    858       if (addr) {
    859         MopInfo *mop = thr->trace_info->GetMop(i);
    860         need_sleep += RaceVerifierStartAccess(thr->zero_based_uniq_tid, addr,
    861             mop->pc(), mop->is_write());
    862       }
    863     }
    864     // Setup the sleep timer.
    865     thr->verifier_current_pc = thr->trace_info->pc();
    866     if (need_sleep) {
    867       unsigned now = VG_(read_millisecond_timer)();
    868       thr->verifier_wakeup_time_ms = now + sleep_time_ms;
    869       return 1;
    870     } else {
    871       thr->verifier_current_pc = (unsigned)-1;
    872       return 0;
    873     }
    874   } else {
    875     // Continuation of the sleep loop.
    876     DCHECK(thr->verifier_current_pc == thr->trace_info->pc());
    877     unsigned now = VG_(read_millisecond_timer)();
    878     if (now < thr->verifier_wakeup_time_ms) {
    879       // sleep more
    880       return 1;
    881     } else {
    882       // done, go straight to OnTraceVerify2
    883       thr->verifier_current_pc = (unsigned)-1;
    884       return 0;
    885     }
    886   }
    887 }
    888 
    889 /**
    890  * Race verification loop exit.
    891  * Unregisters mops with the RaceVerifier.
    892  * Sets up the new trace_info.
    893  */
    894 VG_REGPARM(1)
    895 static void OnTraceVerify2(TraceInfo *trace_info) {
    896   DCHECK(g_race_verifier_active);
    897   ThreadId vg_tid = GetVgTid();
    898   ValgrindThread *thr = &g_valgrind_threads[vg_tid];
    899 
    900   DCHECK(!thr->trace_info || thr->verifier_current_pc == (unsigned)-1);
    901   thr->verifier_current_pc = 0;
    902   thr->verifier_wakeup_time_ms = 0;
    903 
    904   if (thr->trace_info) {
    905     // Unregister accesses from the old trace_info.
    906     size_t n = thr->trace_info->n_mops();
    907     uintptr_t* tleb = thr->tleb;
    908     for (size_t i = 0; i < n; ++i) {
    909       uintptr_t addr = tleb[i];
    910       if (addr) {
    911         MopInfo *mop = thr->trace_info->GetMop(i);
    912         RaceVerifierEndAccess(thr->zero_based_uniq_tid, addr,
    913             mop->pc(), mop->is_write());
    914       }
    915     }
    916   }
    917 
    918   // Start the new trace, zero the contents of tleb.
    919   thr->trace_info = trace_info;
    920   if (trace_info) {
    921     size_t n = trace_info->n_mops();
    922     uintptr_t *tleb = thr->tleb;
    923     for (size_t i = 0; i < n; i++)
    924       tleb[i] = 0;
    925     DCHECK(thr->trace_info->n_mops() <= kMaxMopsPerTrace);
    926   }
    927 }
    928 
    929 /**
    930  * Add a race verification preamble to the IRSB.
    931  */
    932 static void ts_instrument_trace_entry_verify(IRSB *bbOut,
    933     VexGuestLayout* layout, TraceInfo *trace_info, uintptr_t cur_pc) {
    934    HChar*   hName = (HChar*)"OnTraceVerify1";
    935    void *callback = (void*)OnTraceVerify1;
    936    IRExpr **args = mkIRExprVec_0();
    937    IRTemp need_sleep = newIRTemp(bbOut->tyenv, Ity_I32);
    938    IRDirty* di = unsafeIRDirty_1_N(need_sleep, 0, hName,
    939        VG_(fnptr_to_fnentry)(callback), args);
    940    addStmtToIRSB( bbOut, IRStmt_Dirty(di));
    941 
    942    IRTemp need_sleep_i1 = newIRTemp(bbOut->tyenv, Ity_I1);
    943    IRStmt* cmp_stmt = IRStmt_WrTmp(need_sleep_i1,
    944        IRExpr_Binop(Iop_CmpNE32,
    945            IRExpr_RdTmp(need_sleep),
    946            IRExpr_Const(IRConst_U32(0))));
    947    addStmtToIRSB(bbOut, cmp_stmt);
    948 
    949    IRConst* exit_dst = layout->sizeof_IP == 8 ?
    950        IRConst_U64(cur_pc) : IRConst_U32(cur_pc);
    951    IRStmt* exit_stmt = IRStmt_Exit(IRExpr_RdTmp(need_sleep_i1),
    952        Ijk_YieldNoRedir, exit_dst);
    953    addStmtToIRSB(bbOut, exit_stmt);
    954 
    955    hName = (HChar*)"OnTraceVerify2";
    956    callback = (void*)OnTraceVerify2;
    957    args = mkIRExprVec_1(mkIRExpr_HWord((HWord)trace_info));
    958    di = unsafeIRDirty_0_N(1, hName, VG_(fnptr_to_fnentry)(callback), args);
    959    addStmtToIRSB( bbOut, IRStmt_Dirty(di));
    960 }
    961 
    962 
    963 // ---------------------------- Instrumentation ---------------------------{{{1
    964 
    965 static IRTemp gen_Get_SP ( IRSB*           bbOut,
    966                            VexGuestLayout* layout,
    967                            Int             hWordTy_szB )
    968 {
    969   IRExpr* sp_expr;
    970   IRTemp  sp_temp;
    971   IRType  sp_type;
    972   /* This in effect forces the host and guest word sizes to be the
    973      same. */
    974   tl_assert(hWordTy_szB == layout->sizeof_SP);
    975   sp_type = layout->sizeof_SP == 8 ? Ity_I64 : Ity_I32;
    976   sp_expr = IRExpr_Get( layout->offset_SP, sp_type );
    977   sp_temp = newIRTemp( bbOut->tyenv, sp_type );
    978   addStmtToIRSB( bbOut, IRStmt_WrTmp( sp_temp, sp_expr ) );
    979   return sp_temp;
    980 }
    981 
    982 static void ts_instrument_trace_entry(IRSB *bbOut, TraceInfo *trace_info) {
    983    CHECK(trace_info);
    984    HChar*   hName = (HChar*)"OnTrace";
    985    void *callback = (void*)OnTrace;
    986    IRExpr **args = mkIRExprVec_1(mkIRExpr_HWord((HWord)trace_info));
    987    IRDirty* di = unsafeIRDirty_0_N( 1,
    988                            hName,
    989                            VG_(fnptr_to_fnentry)(callback),
    990                            args);
    991    addStmtToIRSB( bbOut, IRStmt_Dirty(di));
    992 }
    993 
    994 static void ts_instrument_final_jump (
    995                                 /*MOD*/IRSB* sbOut,
    996                                 IRExpr* next,
    997                                 IRJumpKind jumpkind,
    998                                 VexGuestLayout* layout,
    999                                 IRType gWordTy, IRType hWordTy ) {
   1000 
   1001 #ifndef VGP_arm_linux
   1002   // On non-ARM systems we instrument only function calls.
   1003   if (jumpkind != Ijk_Call) return;
   1004 #else
   1005   if (jumpkind != Ijk_Call) {
   1006     // On an ARM system a non-call jump may possibly exit a function.
   1007     IRTemp sp_post_call_insn
   1008         = gen_Get_SP( sbOut, layout, sizeofIRType(hWordTy) );
   1009     IRExpr **args = mkIRExprVec_2(
   1010         IRExpr_RdTmp(sp_post_call_insn),
   1011         next
   1012         );
   1013     IRDirty* di = unsafeIRDirty_0_N(
   1014         2/*regparms*/,
   1015         (char*)"evh__delete_frame",
   1016         VG_(fnptr_to_fnentry)((void*) &evh__delete_frame ),
   1017         args );
   1018     addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
   1019     return;  // do not fall through
   1020   }
   1021 #endif
   1022   {
   1023     const char *fn_name = "evh__rtn_call_ignore_unknown";
   1024     void *fn = (void*)&evh__rtn_call_ignore_unknown;
   1025     // Instrument the call instruction to keep the shadow stack consistent.
   1026     IRTemp sp_post_call_insn
   1027         = gen_Get_SP( sbOut, layout, sizeofIRType(hWordTy) );
   1028     IRExpr **args = mkIRExprVec_2(
   1029         IRExpr_RdTmp(sp_post_call_insn),
   1030         next
   1031         );
   1032     if (next->tag == Iex_Const) {
   1033       IRConst *con = next->Iex.Const.con;
   1034       uintptr_t target = 0;
   1035       if (con->tag == Ico_U32 || con->tag == Ico_U64) {
   1036         target = con->tag == Ico_U32 ? con->Ico.U32 : con->Ico.U64;
   1037         bool ignore = ThreadSanitizerIgnoreAccessesBelowFunction(target);
   1038         if (ignore) {
   1039           fn_name = "evh__rtn_call_ignore_yes";
   1040           fn = (void*)&evh__rtn_call_ignore_yes;
   1041         } else {
   1042           fn_name = "evh__rtn_call_ignore_no";
   1043           fn = (void*)&evh__rtn_call_ignore_no;
   1044         }
   1045       }
   1046     }
   1047     IRDirty* di = unsafeIRDirty_0_N(
   1048         2/*regparms*/,
   1049         (char*)fn_name,
   1050         VG_(fnptr_to_fnentry)(fn),
   1051         args );
   1052     addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
   1053   }
   1054 }
   1055 
   1056 // Generate exprs/stmts that make g_cur_tleb[idx] = x.
   1057 static void gen_store_to_tleb(IRSB *bbOut, IRTemp tleb_temp,
   1058                               uintptr_t idx, IRExpr *x, IRType tyAddr) {
   1059   CHECK(tleb_temp != IRTemp_INVALID);
   1060   IRExpr *idx_expr  = mkIRExpr_HWord(idx * sizeof(uintptr_t));
   1061   IRExpr *tleb_plus_idx_expr = IRExpr_Binop(
   1062       sizeof(uintptr_t) == 8 ? Iop_Add64 : Iop_Add32,
   1063       IRExpr_RdTmp(tleb_temp), idx_expr);
   1064   IRTemp temp = newIRTemp(bbOut->tyenv, tyAddr);
   1065   IRStmt *temp_stmt = IRStmt_WrTmp(temp, tleb_plus_idx_expr);
   1066   IRStmt *store_stmt = IRStmt_Store(Iend_LE, IRExpr_RdTmp(temp), x);
   1067 
   1068   addStmtToIRSB(bbOut, temp_stmt);
   1069   addStmtToIRSB(bbOut, store_stmt);
   1070 }
   1071 
   1072 static void instrument_mem_access ( TraceInfo *trace_info,
   1073                                     IRTemp tleb_temp,
   1074                                     uintptr_t pc,
   1075                                     size_t  *trace_idx,
   1076                                     IRSB*   bbOut,
   1077                                     IRStmt* st,
   1078                                     IRExpr* addr,
   1079                                     Int     szB,
   1080                                     Bool    isStore,
   1081                                     Bool    dtor_head,
   1082                                     Int     hWordTy_szB ) {
   1083   IRType   tyAddr   = Ity_INVALID;
   1084 
   1085   tl_assert(isIRAtom(addr));
   1086   tl_assert(hWordTy_szB == 4 || hWordTy_szB == 8);
   1087 
   1088   tyAddr = typeOfIRExpr( bbOut->tyenv, addr );
   1089   tl_assert(tyAddr == Ity_I32 || tyAddr == Ity_I64);
   1090 
   1091   if (szB == 28) {
   1092     // Ignore weird-sized accesses for now.
   1093     // See http://code.google.com/p/data-race-test/issues/detail?id=36
   1094     return;
   1095   }
   1096 
   1097   bool check_ident_store = false;
   1098 
   1099   if (st->tag == Ist_Store && dtor_head &&
   1100       typeOfIRExpr(bbOut->tyenv, st->Ist.Store.data) == tyAddr) {
   1101     check_ident_store = true;
   1102   }
   1103 
   1104   size_t next_trace_idx = *trace_idx + 1;
   1105 
   1106   if (next_trace_idx > kMaxMopsPerTrace) {
   1107     if (next_trace_idx == kMaxMopsPerTrace) {
   1108       Report("INFO: too many mops in trace: %p %s\n", pc,
   1109              PcToRtnName(pc, true).c_str());
   1110     }
   1111     return;
   1112   }
   1113 
   1114   if (!trace_info) {
   1115     // not instrumenting yet.
   1116     *trace_idx = next_trace_idx;
   1117     return;
   1118   }
   1119 
   1120   IRExpr *expr_to_store = NULL;
   1121 
   1122   if (check_ident_store) {
   1123     int is_64 = (sizeof(void*) == 8);
   1124     // generate expression (*addr == new_value ? 0 : addr):
   1125 
   1126     // old_value = *addr
   1127     IRExpr *addr_load_expr = IRExpr_Load(Iend_LE, tyAddr, addr);
   1128     IRTemp star_addr = newIRTemp(bbOut->tyenv, tyAddr);
   1129     IRStmt *star_addr_stmt = IRStmt_WrTmp(star_addr, addr_load_expr);
   1130     addStmtToIRSB(bbOut, star_addr_stmt);
   1131     // sub = (old_value - new_value)
   1132     IRTemp sub = newIRTemp(bbOut->tyenv, tyAddr);
   1133     IRExpr *sub_expr = IRExpr_Binop((IROp)(Iop_Sub32 + is_64),
   1134                                     IRExpr_RdTmp(star_addr),
   1135                                     st->Ist.Store.data);
   1136     IRStmt *sub_stmt = IRStmt_WrTmp(sub, sub_expr);
   1137     addStmtToIRSB(bbOut, sub_stmt);
   1138     // mask = (sub==0) ? 0 : -1
   1139     IRTemp mask = newIRTemp(bbOut->tyenv, tyAddr);
   1140     IRExpr *mask_expr = IRExpr_Unop((IROp)(Iop_CmpwNEZ32 + is_64),
   1141                                     IRExpr_RdTmp(sub));
   1142     IRStmt *mask_stmt = IRStmt_WrTmp(mask, mask_expr);
   1143     addStmtToIRSB(bbOut, mask_stmt);
   1144 
   1145     // res = mask & addr
   1146     IRTemp and_tmp = newIRTemp(bbOut->tyenv, tyAddr);
   1147     IRExpr *and_expr = IRExpr_Binop((IROp)(Iop_And32 + is_64),
   1148                                     IRExpr_RdTmp(mask), addr);
   1149     IRStmt *and_stmt = IRStmt_WrTmp(and_tmp, and_expr);
   1150     addStmtToIRSB(bbOut, and_stmt);
   1151 
   1152     expr_to_store = IRExpr_RdTmp(and_tmp);
   1153   } else {
   1154     expr_to_store = addr;
   1155   }
   1156 
   1157   // OnMop: g_cur_tleb[idx] = expr_to_store
   1158   gen_store_to_tleb(bbOut, tleb_temp, *trace_idx, expr_to_store, tyAddr);
   1159   // Create a mop {pc, size, is_write}
   1160   MopInfo *mop = trace_info->GetMop(*trace_idx);
   1161   new (mop) MopInfo(pc, szB, isStore, false);
   1162   (*trace_idx)++;
   1163 
   1164   CHECK(*trace_idx == next_trace_idx);
   1165 }
   1166 
   1167 void instrument_statement (IRStmt* st, IRSB* bbIn, IRSB* bbOut, IRType hWordTy,
   1168                            TraceInfo *trace_info, IRTemp tleb_temp,
   1169                            size_t *idx, uintptr_t *cur_pc, bool dtor_head) {
   1170   switch (st->tag) {
   1171     case Ist_NoOp:
   1172     case Ist_AbiHint:
   1173     case Ist_Put:
   1174     case Ist_PutI:
   1175     case Ist_Exit:
   1176       /* None of these can contain any memory references. */
   1177       break;
   1178 
   1179     case Ist_IMark:
   1180       *cur_pc = st->Ist.IMark.addr;
   1181       break;
   1182 
   1183     case Ist_MBE:
   1184       //instrument_memory_bus_event( bbOut, st->Ist.MBE.event );
   1185       switch (st->Ist.MBE.event) {
   1186         case Imbe_Fence:
   1187           break; /* not interesting */
   1188         default:
   1189           ppIRStmt(st);
   1190           tl_assert(0);
   1191       }
   1192       break;
   1193 
   1194     case Ist_CAS:
   1195       break;
   1196 
   1197     case Ist_Store:
   1198       instrument_mem_access(trace_info, tleb_temp, *cur_pc, idx,
   1199         bbOut, st,
   1200         st->Ist.Store.addr,
   1201         sizeofIRType(typeOfIRExpr(bbIn->tyenv, st->Ist.Store.data)),
   1202         True/*isStore*/, dtor_head,
   1203         sizeofIRType(hWordTy)
   1204       );
   1205       break;
   1206 
   1207     case Ist_WrTmp: {
   1208       IRExpr* data = st->Ist.WrTmp.data;
   1209       if (data->tag == Iex_Load) {
   1210         instrument_mem_access(trace_info, tleb_temp, *cur_pc, idx,
   1211             bbOut, st,
   1212             data->Iex.Load.addr,
   1213             sizeofIRType(data->Iex.Load.ty),
   1214             False/*!isStore*/, dtor_head,
   1215             sizeofIRType(hWordTy)
   1216             );
   1217       }
   1218       break;
   1219     }
   1220 
   1221     case Ist_LLSC: {
   1222       /* Ignore load-linked's and store-conditionals. */
   1223       break;
   1224     }
   1225 
   1226     case Ist_Dirty: {
   1227       Int      dataSize;
   1228       IRDirty* d = st->Ist.Dirty.details;
   1229       if (d->mFx != Ifx_None) {
   1230         /* This dirty helper accesses memory.  Collect the
   1231            details. */
   1232         tl_assert(d->mAddr != NULL);
   1233         tl_assert(d->mSize != 0);
   1234         dataSize = d->mSize;
   1235         if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify) {
   1236           instrument_mem_access(trace_info, tleb_temp, *cur_pc, idx,
   1237             bbOut, st, d->mAddr, dataSize, False/*!isStore*/, dtor_head,
   1238             sizeofIRType(hWordTy)
   1239           );
   1240         }
   1241         if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify) {
   1242           instrument_mem_access(trace_info, tleb_temp, *cur_pc, idx,
   1243             bbOut, st, d->mAddr, dataSize, True/*isStore*/, dtor_head,
   1244             sizeofIRType(hWordTy)
   1245           );
   1246         }
   1247       } else {
   1248         tl_assert(d->mAddr == NULL);
   1249         tl_assert(d->mSize == 0);
   1250       }
   1251       break;
   1252     }
   1253 
   1254     default:
   1255       ppIRStmt(st);
   1256       tl_assert(0);
   1257   } /* switch (st->tag) */
   1258 }
   1259 
   1260 static IRSB* ts_instrument ( VgCallbackClosure* closure,
   1261                              IRSB* bbIn,
   1262                              VexGuestLayout* layout,
   1263                              VexGuestExtents* vge,
   1264                              IRType gWordTy, IRType hWordTy) {
   1265   if (G_flags->dry_run >= 2) return bbIn;
   1266   Int   i;
   1267   IRSB* bbOut;
   1268   uintptr_t pc = closure->readdr;
   1269 
   1270   char objname[kBuffSize];
   1271   if (VG_(get_objname)(pc, (Char*)objname, kBuffSize)) {
   1272     if (StringMatch("*/ld-2*", objname)) {
   1273       // we want to completely ignore ld-so.
   1274       return bbIn;
   1275     }
   1276   }
   1277 
   1278   bool instrument_memory = ThreadSanitizerWantToInstrumentSblock(pc);
   1279 
   1280   if (gWordTy != hWordTy) {
   1281     /* We don't currently support this case. */
   1282     VG_(tool_panic)((Char*)"host/guest word size mismatch");
   1283   }
   1284 
   1285   /* Set up BB */
   1286   bbOut           = emptyIRSB();
   1287   bbOut->tyenv    = deepCopyIRTypeEnv(bbIn->tyenv);
   1288   bbOut->next     = deepCopyIRExpr(bbIn->next);
   1289   bbOut->jumpkind = bbIn->jumpkind;
   1290 
   1291   // Copy verbatim any IR preamble preceding the first IMark
   1292   i = 0;
   1293   while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) {
   1294     addStmtToIRSB( bbOut, bbIn->stmts[i] );
   1295     i++;
   1296   }
   1297   int first = i;
   1298   size_t n_mops = 0;
   1299   uintptr_t cur_pc = pc;
   1300 
   1301   IRTemp tleb_temp = IRTemp_INVALID;
   1302 
   1303   bool dtor_head = false;
   1304   char buff[1000];
   1305   // get_fnname_w_offset returns demangled name with optional "+offset" prefix.
   1306   // If we have "::~" and don't have "+", this SB is the first in this dtor.
   1307   // We do all this stuff to avoid benign races on vptr:
   1308   // http://code.google.com/p/data-race-test/wiki/PopularDataRaces#Data_race_on_vptr
   1309   if (VG_(get_fnname_w_offset)(pc, (Char*)buff, sizeof(buff)) &&
   1310       VG_(strstr)((Char*)buff, (Char*)"::~") != NULL) {
   1311     char *offset_str = (char*)VG_(strchr)((Char*)buff, '+');
   1312     if (offset_str == NULL) {
   1313       // we are in the first BB of DTOR.
   1314       dtor_head = true;
   1315     } else {
   1316       // We are not in the first BB.
   1317       // On x86_64 (it seems like) the vfptr is updated only in the first BB.
   1318       // On x86 with -fPIC, the vfptr may be updated in the second BB
   1319       // (because -fPIC adds a call which splits the first BB).
   1320       // See http://code.google.com/p/chromium/issues/detail?id=61199
   1321 #ifdef VGA_x86
   1322       char *end;
   1323       size_t offset = my_strtol(offset_str + 1, &end, 10);
   1324       if (offset <= 32) {
   1325         dtor_head = true;
   1326       }
   1327 #endif
   1328     }
   1329   }
   1330 
   1331 
   1332   uintptr_t instrument_pc = 0; // if != 0, instrument only the instruction at this address
   1333   if (g_race_verifier_active) {
   1334     uintptr_t min_pc = vge->base[0];
   1335     uintptr_t max_pc = min_pc + vge->len[0];
   1336     bool verify_trace = RaceVerifierGetAddresses(min_pc, max_pc, &instrument_pc);
   1337     if (!verify_trace)
   1338       instrument_memory = false;
   1339   }
   1340 
   1341   // count mops
   1342   if (instrument_memory) {
   1343     for (i = first; i < bbIn->stmts_used; i++) {
   1344       IRStmt* st = bbIn->stmts[i];
   1345       tl_assert(st);
   1346       tl_assert(isFlatIRStmt(st));
   1347       if (st->tag == Ist_IMark)
   1348         cur_pc = st->Ist.IMark.addr;
   1349       if (!instrument_pc || cur_pc == instrument_pc)
   1350         instrument_statement(st, bbIn, bbOut, hWordTy,
   1351             NULL, tleb_temp, &n_mops, &cur_pc, dtor_head);
   1352     } /* iterate over bbIn->stmts */
   1353   }
   1354   TraceInfo *trace_info = NULL;
   1355   if (n_mops > 0) {
   1356     trace_info = TraceInfo::NewTraceInfo(n_mops, pc);
   1357   }
   1358   size_t n_mops_done = 0;
   1359   bool need_to_insert_on_trace = n_mops > 0 || g_race_verifier_active;
   1360   // instrument mops and copy the rest of BB to the new one.
   1361   for (i = first; i < bbIn->stmts_used; i++) {
   1362     IRStmt* st = bbIn->stmts[i];
   1363     tl_assert(st);
   1364     tl_assert(isFlatIRStmt(st));
   1365     if (st->tag != Ist_IMark && need_to_insert_on_trace) {
   1366       if (g_race_verifier_active) {
   1367         ts_instrument_trace_entry_verify(bbOut, layout, trace_info,
   1368             closure->readdr);
   1369       } else {
   1370         ts_instrument_trace_entry(bbOut, trace_info);
   1371       }
   1372       need_to_insert_on_trace = false;
   1373       // Generate temp for *g_cur_tleb.
   1374       IRType   tyAddr = sizeof(uintptr_t) == 8 ?  Ity_I64 : Ity_I32;
   1375       IRExpr *tleb_ptr_expr = mkIRExpr_HWord((HWord)&g_cur_tleb);
   1376       IRExpr *tleb_expr = IRExpr_Load(Iend_LE, tyAddr, tleb_ptr_expr);
   1377       tleb_temp = newIRTemp(bbOut->tyenv, tyAddr);
   1378       IRStmt *stmt = IRStmt_WrTmp(tleb_temp, tleb_expr);
   1379       addStmtToIRSB(bbOut, stmt);
   1380     }
   1381     if (instrument_memory) {
   1382       if (st->tag == Ist_IMark)
   1383         cur_pc = st->Ist.IMark.addr;
   1384       if (!instrument_pc || cur_pc == instrument_pc)
   1385         instrument_statement(st, bbIn, bbOut, hWordTy,
   1386             trace_info, tleb_temp, &n_mops_done, &cur_pc, dtor_head);
   1387     }
   1388     addStmtToIRSB( bbOut, st );
   1389   } /* iterate over bbIn->stmts */
   1390   CHECK(n_mops == n_mops_done);
   1391   if (!g_race_verifier_active)
   1392     ts_instrument_final_jump(bbOut, bbIn->next, bbIn->jumpkind, layout, gWordTy, hWordTy);
   1393   return bbOut;
   1394 }
   1395 
   1396 extern "C"
   1397 void ts_pre_clo_init(void) {
   1398   VG_(details_name)            ((Char*)"ThreadSanitizer");
   1399   VG_(details_version)         ((Char*)NULL);
   1400   VG_(details_description)     ((Char*)"a data race detector");
   1401   VG_(details_copyright_author)(
   1402       (Char*)"Copyright (C) 2008-2010, and GNU GPL'd, by Google Inc.");
   1403   VG_(details_bug_reports_to)  ((Char*)"data-race-test (at) googlegroups.com");
   1404 
   1405   VG_(basic_tool_funcs)        (ts_post_clo_init,
   1406                                 ts_instrument,
   1407                                 ts_fini);
   1408 
   1409   VG_(needs_client_requests)     (ts_handle_client_request);
   1410 
   1411   VG_(needs_command_line_options)(ts_process_cmd_line_option,
   1412                                   ts_print_usage,
   1413                                   ts_print_debug_usage);
   1414    VG_(track_pre_thread_ll_create)( evh__pre_thread_ll_create );
   1415    VG_(track_pre_thread_ll_exit)  ( evh__pre_thread_ll_exit );
   1416 
   1417    if (!g_race_verifier_active) {
   1418      VG_(track_workq_task_start)( evh__pre_workq_task_start );
   1419      VG_(track_pre_thread_first_insn)( evh__pre_thread_first_insn );
   1420    }
   1421 
   1422    VG_(clo_vex_control).iropt_unroll_thresh = 0;
   1423    VG_(clo_vex_control).guest_chase_thresh = 0;
   1424 
   1425    VG_(track_pre_deliver_signal) (&SignalIn);
   1426    VG_(track_post_deliver_signal)(&SignalOut);
   1427 
   1428    VG_(track_start_client_code)( OnStartClientCode );
   1429 }
   1430 
   1431 VG_DETERMINE_INTERFACE_VERSION(ts_pre_clo_init)
   1432 
   1433 // {{{1 end
   1434 // vim:shiftwidth=2:softtabstop=2:expandtab
   1435