Home | History | Annotate | Download | only in drd
      1 /*
      2   This file is part of drd, a thread error detector.
      3 
      4   Copyright (C) 2006-2017 Bart Van Assche <bvanassche (at) acm.org>.
      5 
      6   This program is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU General Public License as
      8   published by the Free Software Foundation; either version 2 of the
      9   License, or (at your option) any later version.
     10 
     11   This program is distributed in the hope that it will be useful, but
     12   WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   General Public License for more details.
     15 
     16   You should have received a copy of the GNU General Public License
     17   along with this program; if not, write to the Free Software
     18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     19   02111-1307, USA.
     20 
     21   The GNU General Public License is contained in the file COPYING.
     22 */
     23 
     24 
     25 #include "drd_bitmap.h"
     26 #include "drd_thread_bitmap.h"
     27 #include "drd_vc.h"            /* DRD_(vc_snprint)() */
     28 
     29 /* Include several source files here in order to allow the compiler to */
     30 /* do more inlining.                                                   */
     31 #include "drd_bitmap.c"
     32 #include "drd_load_store.h"
     33 #include "drd_segment.c"
     34 #include "drd_thread.c"
     35 #include "drd_vc.c"
     36 #include "libvex_guest_offsets.h"
     37 
     38 
     39 /* STACK_POINTER_OFFSET: VEX register offset for the stack pointer register. */
     40 #if defined(VGA_x86)
     41 #define STACK_POINTER_OFFSET OFFSET_x86_ESP
     42 #elif defined(VGA_amd64)
     43 #define STACK_POINTER_OFFSET OFFSET_amd64_RSP
     44 #elif defined(VGA_ppc32)
     45 #define STACK_POINTER_OFFSET OFFSET_ppc32_GPR1
     46 #elif defined(VGA_ppc64be) || defined(VGA_ppc64le)
     47 #define STACK_POINTER_OFFSET OFFSET_ppc64_GPR1
     48 #elif defined(VGA_arm)
     49 #define STACK_POINTER_OFFSET OFFSET_arm_R13
     50 #elif defined(VGA_arm64)
     51 #define STACK_POINTER_OFFSET OFFSET_arm64_XSP
     52 #elif defined(VGA_s390x)
     53 #define STACK_POINTER_OFFSET OFFSET_s390x_r15
     54 #elif defined(VGA_mips32)
     55 #define STACK_POINTER_OFFSET OFFSET_mips32_r29
     56 #elif defined(VGA_mips64)
     57 #define STACK_POINTER_OFFSET OFFSET_mips64_r29
     58 #else
     59 #error Unknown architecture.
     60 #endif
     61 
     62 
     63 /* Local variables. */
     64 
     65 static Bool s_check_stack_accesses = False;
     66 static Bool s_first_race_only      = False;
     67 
     68 
     69 /* Function definitions. */
     70 
     71 Bool DRD_(get_check_stack_accesses)()
     72 {
     73    return s_check_stack_accesses;
     74 }
     75 
     76 void DRD_(set_check_stack_accesses)(const Bool c)
     77 {
     78    tl_assert(c == False || c == True);
     79    s_check_stack_accesses = c;
     80 }
     81 
     82 Bool DRD_(get_first_race_only)()
     83 {
     84    return s_first_race_only;
     85 }
     86 
     87 void DRD_(set_first_race_only)(const Bool fro)
     88 {
     89    tl_assert(fro == False || fro == True);
     90    s_first_race_only = fro;
     91 }
     92 
     93 void DRD_(trace_mem_access)(const Addr addr, const SizeT size,
     94                             const BmAccessTypeT access_type,
     95                             const HWord stored_value_hi,
     96                             const HWord stored_value_lo)
     97 {
     98    if (DRD_(is_any_traced)(addr, addr + size))
     99    {
    100       HChar* vc;
    101 
    102       vc = DRD_(vc_aprint)(DRD_(thread_get_vc)(DRD_(thread_get_running_tid)()));
    103       if (access_type == eStore && size <= sizeof(HWord)) {
    104          DRD_(trace_msg_w_bt)("store 0x%lx size %lu val %lu/0x%lx (thread %u /"
    105                               " vc %s)", addr, size, stored_value_lo,
    106                               stored_value_lo, DRD_(thread_get_running_tid)(),
    107                               vc);
    108       } else if (access_type == eStore && size > sizeof(HWord)) {
    109          ULong sv;
    110 
    111          tl_assert(sizeof(HWord) == 4);
    112          sv = ((ULong)stored_value_hi << 32) | stored_value_lo;
    113          DRD_(trace_msg_w_bt)("store 0x%lx size %lu val %llu/0x%llx (thread %u"
    114                               " / vc %s)", addr, size, sv, sv,
    115                               DRD_(thread_get_running_tid)(), vc);
    116       } else {
    117          DRD_(trace_msg_w_bt)("%s 0x%lx size %lu (thread %u / vc %s)",
    118                               access_type == eLoad ? "load "
    119                               : access_type == eStore ? "store"
    120                               : access_type == eStart ? "start"
    121                               : access_type == eEnd ? "end  " : "????",
    122                               addr, size, DRD_(thread_get_running_tid)(), vc);
    123       }
    124       VG_(free)(vc);
    125       tl_assert(DRD_(DrdThreadIdToVgThreadId)(DRD_(thread_get_running_tid)())
    126                 == VG_(get_running_tid)());
    127    }
    128 }
    129 
    130 static VG_REGPARM(2) void drd_trace_mem_load(const Addr addr, const SizeT size)
    131 {
    132    return DRD_(trace_mem_access)(addr, size, eLoad, 0, 0);
    133 }
    134 
    135 static VG_REGPARM(3) void drd_trace_mem_store(const Addr addr,const SizeT size,
    136                                               const HWord stored_value_hi,
    137                                               const HWord stored_value_lo)
    138 {
    139    return DRD_(trace_mem_access)(addr, size, eStore, stored_value_hi,
    140                                  stored_value_lo);
    141 }
    142 
    143 static void drd_report_race(const Addr addr, const SizeT size,
    144                             const BmAccessTypeT access_type)
    145 {
    146    ThreadId vg_tid;
    147 
    148    vg_tid = VG_(get_running_tid)();
    149    if (!DRD_(get_check_stack_accesses)()
    150        && DRD_(thread_address_on_any_stack)(addr)) {
    151 #if 0
    152       GenericErrInfo GEI = {
    153          .tid = DRD_(thread_get_running_tid)(),
    154          .addr = addr,
    155       };
    156       VG_(maybe_record_error)(vg_tid, GenericErr, VG_(get_IP)(vg_tid),
    157                               "--check-stack-var=no skips checking stack"
    158                               " variables shared over threads",
    159                               &GEI);
    160 #endif
    161   } else {
    162       DataRaceErrInfo drei = {
    163          .tid  = DRD_(thread_get_running_tid)(),
    164          .addr = addr,
    165          .size = size,
    166          .access_type = access_type,
    167       };
    168       VG_(maybe_record_error)(vg_tid, DataRaceErr, VG_(get_IP)(vg_tid),
    169                               "Conflicting access", &drei);
    170 
    171       if (s_first_race_only)
    172          DRD_(start_suppression)(addr, addr + size, "first race only");
    173    }
    174 }
    175 
    176 VG_REGPARM(2) void DRD_(trace_load)(Addr addr, SizeT size)
    177 {
    178 #ifdef ENABLE_DRD_CONSISTENCY_CHECKS
    179    /* The assert below has been commented out because of performance reasons.*/
    180    tl_assert(DRD_(thread_get_running_tid)()
    181              == DRD_(VgThreadIdToDrdThreadId)(VG_(get_running_tid)()));
    182 #endif
    183 
    184    if (DRD_(running_thread_is_recording_loads)()
    185        && (s_check_stack_accesses
    186            || ! DRD_(thread_address_on_stack)(addr))
    187        && bm_access_load_triggers_conflict(addr, addr + size)
    188        && ! DRD_(is_suppressed)(addr, addr + size))
    189    {
    190       drd_report_race(addr, size, eLoad);
    191    }
    192 }
    193 
    194 static VG_REGPARM(1) void drd_trace_load_1(Addr addr)
    195 {
    196    if (DRD_(running_thread_is_recording_loads)()
    197        && (s_check_stack_accesses
    198            || ! DRD_(thread_address_on_stack)(addr))
    199        && bm_access_load_1_triggers_conflict(addr)
    200        && ! DRD_(is_suppressed)(addr, addr + 1))
    201    {
    202       drd_report_race(addr, 1, eLoad);
    203    }
    204 }
    205 
    206 static VG_REGPARM(1) void drd_trace_load_2(Addr addr)
    207 {
    208    if (DRD_(running_thread_is_recording_loads)()
    209        && (s_check_stack_accesses
    210            || ! DRD_(thread_address_on_stack)(addr))
    211        && bm_access_load_2_triggers_conflict(addr)
    212        && ! DRD_(is_suppressed)(addr, addr + 2))
    213    {
    214       drd_report_race(addr, 2, eLoad);
    215    }
    216 }
    217 
    218 static VG_REGPARM(1) void drd_trace_load_4(Addr addr)
    219 {
    220    if (DRD_(running_thread_is_recording_loads)()
    221        && (s_check_stack_accesses
    222            || ! DRD_(thread_address_on_stack)(addr))
    223        && bm_access_load_4_triggers_conflict(addr)
    224        && ! DRD_(is_suppressed)(addr, addr + 4))
    225    {
    226       drd_report_race(addr, 4, eLoad);
    227    }
    228 }
    229 
    230 static VG_REGPARM(1) void drd_trace_load_8(Addr addr)
    231 {
    232    if (DRD_(running_thread_is_recording_loads)()
    233        && (s_check_stack_accesses
    234            || ! DRD_(thread_address_on_stack)(addr))
    235        && bm_access_load_8_triggers_conflict(addr)
    236        && ! DRD_(is_suppressed)(addr, addr + 8))
    237    {
    238       drd_report_race(addr, 8, eLoad);
    239    }
    240 }
    241 
    242 VG_REGPARM(2) void DRD_(trace_store)(Addr addr, SizeT size)
    243 {
    244 #ifdef ENABLE_DRD_CONSISTENCY_CHECKS
    245    /* The assert below has been commented out because of performance reasons.*/
    246    tl_assert(DRD_(thread_get_running_tid)()
    247              == DRD_(VgThreadIdToDrdThreadId)(VG_(get_running_tid)()));
    248 #endif
    249 
    250    if (DRD_(running_thread_is_recording_stores)()
    251        && (s_check_stack_accesses
    252            || ! DRD_(thread_address_on_stack)(addr))
    253        && bm_access_store_triggers_conflict(addr, addr + size)
    254        && ! DRD_(is_suppressed)(addr, addr + size))
    255    {
    256       drd_report_race(addr, size, eStore);
    257    }
    258 }
    259 
    260 static VG_REGPARM(1) void drd_trace_store_1(Addr addr)
    261 {
    262    if (DRD_(running_thread_is_recording_stores)()
    263        && (s_check_stack_accesses
    264            || ! DRD_(thread_address_on_stack)(addr))
    265        && bm_access_store_1_triggers_conflict(addr)
    266        && ! DRD_(is_suppressed)(addr, addr + 1))
    267    {
    268       drd_report_race(addr, 1, eStore);
    269    }
    270 }
    271 
    272 static VG_REGPARM(1) void drd_trace_store_2(Addr addr)
    273 {
    274    if (DRD_(running_thread_is_recording_stores)()
    275        && (s_check_stack_accesses
    276            || ! DRD_(thread_address_on_stack)(addr))
    277        && bm_access_store_2_triggers_conflict(addr)
    278        && ! DRD_(is_suppressed)(addr, addr + 2))
    279    {
    280       drd_report_race(addr, 2, eStore);
    281    }
    282 }
    283 
    284 static VG_REGPARM(1) void drd_trace_store_4(Addr addr)
    285 {
    286    if (DRD_(running_thread_is_recording_stores)()
    287        && (s_check_stack_accesses
    288            || !DRD_(thread_address_on_stack)(addr))
    289        && bm_access_store_4_triggers_conflict(addr)
    290        && !DRD_(is_suppressed)(addr, addr + 4))
    291    {
    292       drd_report_race(addr, 4, eStore);
    293    }
    294 }
    295 
    296 static VG_REGPARM(1) void drd_trace_store_8(Addr addr)
    297 {
    298    if (DRD_(running_thread_is_recording_stores)()
    299        && (s_check_stack_accesses
    300            || ! DRD_(thread_address_on_stack)(addr))
    301        && bm_access_store_8_triggers_conflict(addr)
    302        && ! DRD_(is_suppressed)(addr, addr + 8))
    303    {
    304       drd_report_race(addr, 8, eStore);
    305    }
    306 }
    307 
    308 /**
    309  * Return true if and only if addr_expr matches the pattern (SP) or
    310  * <offset>(SP).
    311  */
    312 static Bool is_stack_access(IRSB* const bb, IRExpr* const addr_expr)
    313 {
    314    Bool result = False;
    315 
    316    if (addr_expr->tag == Iex_RdTmp)
    317    {
    318       int i;
    319       for (i = 0; i < bb->stmts_used; i++)
    320       {
    321          if (bb->stmts[i]
    322              && bb->stmts[i]->tag == Ist_WrTmp
    323              && bb->stmts[i]->Ist.WrTmp.tmp == addr_expr->Iex.RdTmp.tmp)
    324          {
    325             IRExpr* e = bb->stmts[i]->Ist.WrTmp.data;
    326             if (e->tag == Iex_Get && e->Iex.Get.offset == STACK_POINTER_OFFSET)
    327             {
    328                result = True;
    329             }
    330 
    331             //ppIRExpr(e);
    332             //VG_(printf)(" (%s)\n", result ? "True" : "False");
    333             break;
    334          }
    335       }
    336    }
    337    return result;
    338 }
    339 
    340 static const IROp u_widen_irop[5][9] = {
    341    [Ity_I1  - Ity_I1] = { [4] = Iop_1Uto32,  [8] = Iop_1Uto64 },
    342    [Ity_I8  - Ity_I1] = { [4] = Iop_8Uto32,  [8] = Iop_8Uto64 },
    343    [Ity_I16 - Ity_I1] = { [4] = Iop_16Uto32, [8] = Iop_16Uto64 },
    344    [Ity_I32 - Ity_I1] = {                    [8] = Iop_32Uto64 },
    345 };
    346 
    347 /**
    348  * Instrument the client code to trace a memory load (--trace-addr).
    349  */
    350 static IRExpr* instr_trace_mem_load(IRSB* const bb, IRExpr* addr_expr,
    351                                     const HWord size,
    352                                     IRExpr* const guard/* NULL => True */)
    353 {
    354    IRTemp tmp;
    355 
    356    tmp = newIRTemp(bb->tyenv, typeOfIRExpr(bb->tyenv, addr_expr));
    357    addStmtToIRSB(bb, IRStmt_WrTmp(tmp, addr_expr));
    358    addr_expr = IRExpr_RdTmp(tmp);
    359    IRDirty* di
    360      = unsafeIRDirty_0_N(/*regparms*/2,
    361                          "drd_trace_mem_load",
    362                          VG_(fnptr_to_fnentry)
    363                          (drd_trace_mem_load),
    364                          mkIRExprVec_2(addr_expr, mkIRExpr_HWord(size)));
    365    if (guard) di->guard = guard;
    366    addStmtToIRSB(bb, IRStmt_Dirty(di));
    367 
    368    return addr_expr;
    369 }
    370 
    371 /**
    372  * Instrument the client code to trace a memory store (--trace-addr).
    373  */
    374 static void instr_trace_mem_store(IRSB* const bb, IRExpr* const addr_expr,
    375                                   IRExpr* data_expr_hi, IRExpr* data_expr_lo,
    376                                   IRExpr* const guard/* NULL => True */)
    377 {
    378    IRType ty_data_expr;
    379    HWord size;
    380 
    381    tl_assert(sizeof(HWord) == 4 || sizeof(HWord) == 8);
    382    tl_assert(!data_expr_hi || typeOfIRExpr(bb->tyenv, data_expr_hi) == Ity_I32);
    383 
    384    ty_data_expr = typeOfIRExpr(bb->tyenv, data_expr_lo);
    385    size = sizeofIRType(ty_data_expr);
    386 
    387 #if 0
    388    // Test code
    389    if (ty_data_expr == Ity_I32) {
    390       IRTemp tmp = newIRTemp(bb->tyenv, Ity_F32);
    391       data_expr_lo = IRExpr_Unop(Iop_ReinterpI32asF32, data_expr_lo);
    392       addStmtToIRSB(bb, IRStmt_WrTmp(tmp, data_expr_lo));
    393       data_expr_lo = IRExpr_RdTmp(tmp);
    394       ty_data_expr = Ity_F32;
    395    } else if (ty_data_expr == Ity_I64) {
    396       IRTemp tmp = newIRTemp(bb->tyenv, Ity_F64);
    397       data_expr_lo = IRExpr_Unop(Iop_ReinterpI64asF64, data_expr_lo);
    398       addStmtToIRSB(bb, IRStmt_WrTmp(tmp, data_expr_lo));
    399       data_expr_lo = IRExpr_RdTmp(tmp);
    400       ty_data_expr = Ity_F64;
    401    }
    402 #endif
    403 
    404    if (ty_data_expr == Ity_F32) {
    405       IRTemp tmp = newIRTemp(bb->tyenv, Ity_I32);
    406       addStmtToIRSB(bb, IRStmt_WrTmp(tmp, IRExpr_Unop(Iop_ReinterpF32asI32,
    407                                                       data_expr_lo)));
    408       data_expr_lo = IRExpr_RdTmp(tmp);
    409       ty_data_expr = Ity_I32;
    410    } else if (ty_data_expr == Ity_F64) {
    411       IRTemp tmp = newIRTemp(bb->tyenv, Ity_I64);
    412       addStmtToIRSB(bb, IRStmt_WrTmp(tmp, IRExpr_Unop(Iop_ReinterpF64asI64,
    413                                                       data_expr_lo)));
    414       data_expr_lo = IRExpr_RdTmp(tmp);
    415       ty_data_expr = Ity_I64;
    416    }
    417 
    418    if (size == sizeof(HWord)
    419        && (ty_data_expr == Ity_I32 || ty_data_expr == Ity_I64))
    420    {
    421       /* No conversion necessary */
    422    } else {
    423       IROp widen_op;
    424 
    425       if (Ity_I1 <= ty_data_expr
    426           && ty_data_expr
    427              < Ity_I1 + sizeof(u_widen_irop)/sizeof(u_widen_irop[0]))
    428       {
    429          widen_op = u_widen_irop[ty_data_expr - Ity_I1][sizeof(HWord)];
    430          if (!widen_op)
    431             widen_op = Iop_INVALID;
    432       } else {
    433          widen_op = Iop_INVALID;
    434       }
    435       if (widen_op != Iop_INVALID) {
    436          IRTemp tmp;
    437 
    438          /* Widen the integer expression to a HWord */
    439          tmp = newIRTemp(bb->tyenv, sizeof(HWord) == 4 ? Ity_I32 : Ity_I64);
    440          addStmtToIRSB(bb,
    441                        IRStmt_WrTmp(tmp, IRExpr_Unop(widen_op, data_expr_lo)));
    442          data_expr_lo = IRExpr_RdTmp(tmp);
    443       } else if (size > sizeof(HWord) && !data_expr_hi
    444                  && ty_data_expr == Ity_I64) {
    445          IRTemp tmp;
    446 
    447          tl_assert(sizeof(HWord) == 4);
    448          tl_assert(size == 8);
    449          tmp = newIRTemp(bb->tyenv, Ity_I32);
    450          addStmtToIRSB(bb,
    451                        IRStmt_WrTmp(tmp,
    452                                     IRExpr_Unop(Iop_64HIto32, data_expr_lo)));
    453          data_expr_hi = IRExpr_RdTmp(tmp);
    454          tmp = newIRTemp(bb->tyenv, Ity_I32);
    455          addStmtToIRSB(bb, IRStmt_WrTmp(tmp,
    456                                         IRExpr_Unop(Iop_64to32, data_expr_lo)));
    457          data_expr_lo = IRExpr_RdTmp(tmp);
    458       } else {
    459          data_expr_lo = mkIRExpr_HWord(0);
    460       }
    461    }
    462    IRDirty* di
    463      = unsafeIRDirty_0_N(/*regparms*/3,
    464                          "drd_trace_mem_store",
    465                          VG_(fnptr_to_fnentry)(drd_trace_mem_store),
    466                          mkIRExprVec_4(addr_expr, mkIRExpr_HWord(size),
    467                                        data_expr_hi ? data_expr_hi
    468                                        : mkIRExpr_HWord(0), data_expr_lo));
    469    if (guard) di->guard = guard;
    470    addStmtToIRSB(bb, IRStmt_Dirty(di) );
    471 }
    472 
    473 static void instrument_load(IRSB* const bb, IRExpr* const addr_expr,
    474                             const HWord size,
    475                             IRExpr* const guard/* NULL => True */)
    476 {
    477    IRExpr* size_expr;
    478    IRExpr** argv;
    479    IRDirty* di;
    480 
    481    if (!s_check_stack_accesses && is_stack_access(bb, addr_expr))
    482       return;
    483 
    484    switch (size)
    485    {
    486    case 1:
    487       argv = mkIRExprVec_1(addr_expr);
    488       di = unsafeIRDirty_0_N(/*regparms*/1,
    489                              "drd_trace_load_1",
    490                              VG_(fnptr_to_fnentry)(drd_trace_load_1),
    491                              argv);
    492       break;
    493    case 2:
    494       argv = mkIRExprVec_1(addr_expr);
    495       di = unsafeIRDirty_0_N(/*regparms*/1,
    496                              "drd_trace_load_2",
    497                              VG_(fnptr_to_fnentry)(drd_trace_load_2),
    498                              argv);
    499       break;
    500    case 4:
    501       argv = mkIRExprVec_1(addr_expr);
    502       di = unsafeIRDirty_0_N(/*regparms*/1,
    503                              "drd_trace_load_4",
    504                              VG_(fnptr_to_fnentry)(drd_trace_load_4),
    505                              argv);
    506       break;
    507    case 8:
    508       argv = mkIRExprVec_1(addr_expr);
    509       di = unsafeIRDirty_0_N(/*regparms*/1,
    510                              "drd_trace_load_8",
    511                              VG_(fnptr_to_fnentry)(drd_trace_load_8),
    512                              argv);
    513       break;
    514    default:
    515       size_expr = mkIRExpr_HWord(size);
    516       argv = mkIRExprVec_2(addr_expr, size_expr);
    517       di = unsafeIRDirty_0_N(/*regparms*/2,
    518                              "drd_trace_load",
    519                              VG_(fnptr_to_fnentry)(DRD_(trace_load)),
    520                              argv);
    521       break;
    522    }
    523    if (guard) di->guard = guard;
    524    addStmtToIRSB(bb, IRStmt_Dirty(di));
    525 }
    526 
    527 static void instrument_store(IRSB* const bb, IRExpr* addr_expr,
    528                              IRExpr* const data_expr,
    529                              IRExpr* const guard_expr/* NULL => True */)
    530 {
    531    IRExpr* size_expr;
    532    IRExpr** argv;
    533    IRDirty* di;
    534    HWord size;
    535 
    536    size = sizeofIRType(typeOfIRExpr(bb->tyenv, data_expr));
    537 
    538    if (UNLIKELY(DRD_(any_address_is_traced)())) {
    539       IRTemp tmp = newIRTemp(bb->tyenv, typeOfIRExpr(bb->tyenv, addr_expr));
    540       addStmtToIRSB(bb, IRStmt_WrTmp(tmp, addr_expr));
    541       addr_expr = IRExpr_RdTmp(tmp);
    542       instr_trace_mem_store(bb, addr_expr, NULL, data_expr, guard_expr);
    543    }
    544 
    545    if (!s_check_stack_accesses && is_stack_access(bb, addr_expr))
    546       return;
    547 
    548    switch (size)
    549    {
    550    case 1:
    551       argv = mkIRExprVec_1(addr_expr);
    552       di = unsafeIRDirty_0_N(/*regparms*/1,
    553                              "drd_trace_store_1",
    554                              VG_(fnptr_to_fnentry)(drd_trace_store_1),
    555                              argv);
    556       break;
    557    case 2:
    558       argv = mkIRExprVec_1(addr_expr);
    559       di = unsafeIRDirty_0_N(/*regparms*/1,
    560                              "drd_trace_store_2",
    561                              VG_(fnptr_to_fnentry)(drd_trace_store_2),
    562                              argv);
    563       break;
    564    case 4:
    565       argv = mkIRExprVec_1(addr_expr);
    566       di = unsafeIRDirty_0_N(/*regparms*/1,
    567                              "drd_trace_store_4",
    568                              VG_(fnptr_to_fnentry)(drd_trace_store_4),
    569                              argv);
    570       break;
    571    case 8:
    572       argv = mkIRExprVec_1(addr_expr);
    573       di = unsafeIRDirty_0_N(/*regparms*/1,
    574                              "drd_trace_store_8",
    575                              VG_(fnptr_to_fnentry)(drd_trace_store_8),
    576                              argv);
    577       break;
    578    default:
    579       size_expr = mkIRExpr_HWord(size);
    580       argv = mkIRExprVec_2(addr_expr, size_expr);
    581       di = unsafeIRDirty_0_N(/*regparms*/2,
    582                              "drd_trace_store",
    583                              VG_(fnptr_to_fnentry)(DRD_(trace_store)),
    584                              argv);
    585       break;
    586    }
    587    if (guard_expr) di->guard = guard_expr;
    588    addStmtToIRSB(bb, IRStmt_Dirty(di));
    589 }
    590 
    591 IRSB* DRD_(instrument)(VgCallbackClosure* const closure,
    592                        IRSB* const bb_in,
    593                        const VexGuestLayout* const layout,
    594                        const VexGuestExtents* const vge,
    595                        const VexArchInfo* archinfo_host,
    596                        IRType const gWordTy,
    597                        IRType const hWordTy)
    598 {
    599    IRDirty* di;
    600    Int      i;
    601    IRSB*    bb;
    602    IRExpr** argv;
    603    Bool     instrument = True;
    604 
    605    /* Set up BB */
    606    bb           = emptyIRSB();
    607    bb->tyenv    = deepCopyIRTypeEnv(bb_in->tyenv);
    608    bb->next     = deepCopyIRExpr(bb_in->next);
    609    bb->jumpkind = bb_in->jumpkind;
    610    bb->offsIP   = bb_in->offsIP;
    611 
    612    for (i = 0; i < bb_in->stmts_used; i++)
    613    {
    614       IRStmt* const st = bb_in->stmts[i];
    615       tl_assert(st);
    616       tl_assert(isFlatIRStmt(st));
    617 
    618       switch (st->tag)
    619       {
    620          /* Note: the code for not instrumenting the code in .plt          */
    621          /* sections is only necessary on CentOS 3.0 x86 (kernel 2.4.21    */
    622          /* + glibc 2.3.2 + NPTL 0.60 + binutils 2.14.90.0.4).             */
    623          /* This is because on this platform dynamic library symbols are   */
    624          /* relocated in another way than by later binutils versions. The  */
    625          /* linker e.g. does not generate .got.plt sections on CentOS 3.0. */
    626       case Ist_IMark:
    627          instrument = VG_(DebugInfo_sect_kind)(NULL, st->Ist.IMark.addr)
    628             != Vg_SectPLT;
    629          addStmtToIRSB(bb, st);
    630          break;
    631 
    632       case Ist_MBE:
    633          switch (st->Ist.MBE.event)
    634          {
    635          case Imbe_Fence:
    636             break; /* not interesting to DRD */
    637          case Imbe_CancelReservation:
    638             break; /* not interesting to DRD */
    639          default:
    640             tl_assert(0);
    641          }
    642          addStmtToIRSB(bb, st);
    643          break;
    644 
    645       case Ist_Store:
    646          if (instrument)
    647             instrument_store(bb, st->Ist.Store.addr, st->Ist.Store.data,
    648                              NULL/* no guard */);
    649          addStmtToIRSB(bb, st);
    650          break;
    651 
    652       case Ist_StoreG: {
    653          IRStoreG* sg   = st->Ist.StoreG.details;
    654          IRExpr*   data = sg->data;
    655          IRExpr*   addr = sg->addr;
    656          if (instrument)
    657             instrument_store(bb, addr, data, sg->guard);
    658          addStmtToIRSB(bb, st);
    659          break;
    660       }
    661 
    662       case Ist_LoadG: {
    663          IRLoadG* lg        = st->Ist.LoadG.details;
    664          IRType   type      = Ity_INVALID; /* loaded type */
    665          IRType   typeWide  = Ity_INVALID; /* after implicit widening */
    666          IRExpr*  addr_expr = lg->addr;
    667          typeOfIRLoadGOp(lg->cvt, &typeWide, &type);
    668          tl_assert(type != Ity_INVALID);
    669          if (UNLIKELY(DRD_(any_address_is_traced)())) {
    670             addr_expr = instr_trace_mem_load(bb, addr_expr,
    671                                              sizeofIRType(type), lg->guard);
    672          }
    673          instrument_load(bb, lg->addr,
    674                          sizeofIRType(type), lg->guard);
    675          addStmtToIRSB(bb, st);
    676          break;
    677       }
    678 
    679       case Ist_WrTmp:
    680          if (instrument) {
    681             const IRExpr* const data = st->Ist.WrTmp.data;
    682             IRExpr* addr_expr = data->Iex.Load.addr;
    683             if (data->tag == Iex_Load) {
    684                if (UNLIKELY(DRD_(any_address_is_traced)())) {
    685                   addr_expr = instr_trace_mem_load(bb, addr_expr,
    686                                        sizeofIRType(data->Iex.Load.ty),
    687                                        NULL/* no guard */);
    688                }
    689                instrument_load(bb, addr_expr, sizeofIRType(data->Iex.Load.ty),
    690                                NULL/* no guard */);
    691             }
    692          }
    693          addStmtToIRSB(bb, st);
    694          break;
    695 
    696       case Ist_Dirty:
    697          if (instrument) {
    698             IRDirty* d = st->Ist.Dirty.details;
    699             IREffect const mFx = d->mFx;
    700             switch (mFx) {
    701             case Ifx_None:
    702                break;
    703             case Ifx_Read:
    704             case Ifx_Write:
    705             case Ifx_Modify:
    706                tl_assert(d->mAddr);
    707                tl_assert(d->mSize > 0);
    708                argv = mkIRExprVec_2(d->mAddr, mkIRExpr_HWord(d->mSize));
    709                if (mFx == Ifx_Read || mFx == Ifx_Modify) {
    710                   di = unsafeIRDirty_0_N(
    711                           /*regparms*/2,
    712                           "drd_trace_load",
    713                           VG_(fnptr_to_fnentry)(DRD_(trace_load)),
    714                           argv);
    715                   addStmtToIRSB(bb, IRStmt_Dirty(di));
    716                }
    717                if (mFx == Ifx_Write || mFx == Ifx_Modify)
    718                {
    719                   di = unsafeIRDirty_0_N(
    720                           /*regparms*/2,
    721                           "drd_trace_store",
    722                           VG_(fnptr_to_fnentry)(DRD_(trace_store)),
    723                           argv);
    724                   addStmtToIRSB(bb, IRStmt_Dirty(di));
    725                }
    726                break;
    727             default:
    728                tl_assert(0);
    729             }
    730          }
    731          addStmtToIRSB(bb, st);
    732          break;
    733 
    734       case Ist_CAS:
    735          if (instrument) {
    736             /*
    737              * Treat compare-and-swap as a read. By handling atomic
    738              * instructions as read instructions no data races are reported
    739              * between conflicting atomic operations nor between atomic
    740              * operations and non-atomic reads. Conflicts between atomic
    741              * operations and non-atomic write operations are still reported
    742              * however.
    743              */
    744             Int    dataSize;
    745             IRCAS* cas = st->Ist.CAS.details;
    746 
    747             tl_assert(cas->addr != NULL);
    748             tl_assert(cas->dataLo != NULL);
    749             dataSize = sizeofIRType(typeOfIRExpr(bb->tyenv, cas->dataLo));
    750             if (cas->dataHi != NULL)
    751                dataSize *= 2; /* since it's a doubleword-CAS */
    752 
    753             if (UNLIKELY(DRD_(any_address_is_traced)()))
    754                instr_trace_mem_store(bb, cas->addr, cas->dataHi, cas->dataLo,
    755                                      NULL/* no guard */);
    756 
    757             instrument_load(bb, cas->addr, dataSize, NULL/*no guard*/);
    758          }
    759          addStmtToIRSB(bb, st);
    760          break;
    761 
    762       case Ist_LLSC: {
    763          /*
    764           * Ignore store-conditionals (except for tracing), and handle
    765           * load-linked's exactly like normal loads.
    766           */
    767          IRType dataTy;
    768 
    769          if (st->Ist.LLSC.storedata == NULL) {
    770             /* LL */
    771             dataTy = typeOfIRTemp(bb_in->tyenv, st->Ist.LLSC.result);
    772             if (instrument) {
    773                IRExpr* addr_expr = st->Ist.LLSC.addr;
    774                if (UNLIKELY(DRD_(any_address_is_traced)()))
    775                   addr_expr = instr_trace_mem_load(bb, addr_expr,
    776                                                    sizeofIRType(dataTy),
    777                                                    NULL /* no guard */);
    778 
    779                instrument_load(bb, addr_expr, sizeofIRType(dataTy),
    780                                NULL/*no guard*/);
    781             }
    782          } else {
    783             /* SC */
    784             instr_trace_mem_store(bb, st->Ist.LLSC.addr, NULL,
    785                                   st->Ist.LLSC.storedata,
    786                                   NULL/* no guard */);
    787          }
    788          addStmtToIRSB(bb, st);
    789          break;
    790       }
    791 
    792       case Ist_NoOp:
    793       case Ist_AbiHint:
    794       case Ist_Put:
    795       case Ist_PutI:
    796       case Ist_Exit:
    797          /* None of these can contain any memory references. */
    798          addStmtToIRSB(bb, st);
    799          break;
    800 
    801       default:
    802          ppIRStmt(st);
    803          tl_assert(0);
    804       }
    805    }
    806 
    807    return bb;
    808 }
    809 
    810