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