Home | History | Annotate | Download | only in drd
      1 /* -*- mode: C; c-basic-offset: 3; indent-tabs-mode: nil; -*- */
      2 /*
      3   This file is part of drd, a thread error detector.
      4 
      5   Copyright (C) 2006-2011 Bart Van Assche <bvanassche (at) acm.org>.
      6 
      7   This program is free software; you can redistribute it and/or
      8   modify it under the terms of the GNU General Public License as
      9   published by the Free Software Foundation; either version 2 of the
     10   License, or (at your option) any later version.
     11 
     12   This program is distributed in the hope that it will be useful, but
     13   WITHOUT ANY WARRANTY; without even the implied warranty of
     14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15   General Public License for more details.
     16 
     17   You should have received a copy of the GNU General Public License
     18   along with this program; if not, write to the Free Software
     19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     20   02111-1307, USA.
     21 
     22   The GNU General Public License is contained in the file COPYING.
     23 */
     24 
     25 
     26 #include "drd_bitmap.h"
     27 #include "drd_thread_bitmap.h"
     28 #include "drd_vc.h"            /* DRD_(vc_snprint)() */
     29 
     30 /* Include several source files here in order to allow the compiler to */
     31 /* do more inlining.                                                   */
     32 #include "drd_bitmap.c"
     33 #include "drd_load_store.h"
     34 #include "drd_segment.c"
     35 #include "drd_thread.c"
     36 #include "drd_vc.c"
     37 #include "libvex_guest_offsets.h"
     38 
     39 
     40 /* STACK_POINTER_OFFSET: VEX register offset for the stack pointer register. */
     41 #if defined(VGA_x86)
     42 #define STACK_POINTER_OFFSET OFFSET_x86_ESP
     43 #elif defined(VGA_amd64)
     44 #define STACK_POINTER_OFFSET OFFSET_amd64_RSP
     45 #elif defined(VGA_ppc32)
     46 #define STACK_POINTER_OFFSET OFFSET_ppc32_GPR1
     47 #elif defined(VGA_ppc64)
     48 #define STACK_POINTER_OFFSET OFFSET_ppc64_GPR1
     49 #elif defined(VGA_arm)
     50 #define STACK_POINTER_OFFSET OFFSET_arm_R13
     51 #elif defined(VGA_s390x)
     52 #define STACK_POINTER_OFFSET OFFSET_s390x_r15
     53 #else
     54 #error Unknown architecture.
     55 #endif
     56 
     57 
     58 /* Local variables. */
     59 
     60 static Bool s_check_stack_accesses = False;
     61 static Bool s_first_race_only      = False;
     62 
     63 
     64 /* Function definitions. */
     65 
     66 Bool DRD_(get_check_stack_accesses)()
     67 {
     68    return s_check_stack_accesses;
     69 }
     70 
     71 void DRD_(set_check_stack_accesses)(const Bool c)
     72 {
     73    tl_assert(c == False || c == True);
     74    s_check_stack_accesses = c;
     75 }
     76 
     77 Bool DRD_(get_first_race_only)()
     78 {
     79    return s_first_race_only;
     80 }
     81 
     82 void DRD_(set_first_race_only)(const Bool fro)
     83 {
     84    tl_assert(fro == False || fro == True);
     85    s_first_race_only = fro;
     86 }
     87 
     88 void DRD_(trace_mem_access)(const Addr addr, const SizeT size,
     89                             const BmAccessTypeT access_type)
     90 {
     91    if (DRD_(is_any_traced)(addr, addr + size))
     92    {
     93       char* vc;
     94 
     95       vc = DRD_(vc_aprint)(DRD_(thread_get_vc)(DRD_(thread_get_running_tid)()));
     96       DRD_(trace_msg_w_bt)("%s 0x%lx size %ld (thread %d / vc %s)",
     97                            access_type == eLoad ? "load "
     98                            : access_type == eStore ? "store"
     99                            : access_type == eStart ? "start"
    100                            : access_type == eEnd ? "end  " : "????",
    101                            addr, size, DRD_(thread_get_running_tid)(), vc);
    102       VG_(free)(vc);
    103       tl_assert(DRD_(DrdThreadIdToVgThreadId)(DRD_(thread_get_running_tid)())
    104                 == VG_(get_running_tid)());
    105    }
    106 }
    107 
    108 static VG_REGPARM(2) void drd_trace_mem_load(const Addr addr, const SizeT size)
    109 {
    110    return DRD_(trace_mem_access)(addr, size, eLoad);
    111 }
    112 
    113 static VG_REGPARM(2) void drd_trace_mem_store(const Addr addr,const SizeT size)
    114 {
    115    return DRD_(trace_mem_access)(addr, size, eStore);
    116 }
    117 
    118 static void drd_report_race(const Addr addr, const SizeT size,
    119                             const BmAccessTypeT access_type)
    120 {
    121    DataRaceErrInfo drei;
    122 
    123    drei.tid  = DRD_(thread_get_running_tid)();
    124    drei.addr = addr;
    125    drei.size = size;
    126    drei.access_type = access_type;
    127    VG_(maybe_record_error)(VG_(get_running_tid)(),
    128                            DataRaceErr,
    129                            VG_(get_IP)(VG_(get_running_tid)()),
    130                            "Conflicting access",
    131                            &drei);
    132 
    133    if (s_first_race_only)
    134    {
    135       DRD_(start_suppression)(addr, addr + size, "first race only");
    136    }
    137 }
    138 
    139 VG_REGPARM(2) void DRD_(trace_load)(Addr addr, SizeT size)
    140 {
    141 #ifdef ENABLE_DRD_CONSISTENCY_CHECKS
    142    /* The assert below has been commented out because of performance reasons.*/
    143    tl_assert(DRD_(thread_get_running_tid)()
    144              == DRD_(VgThreadIdToDrdThreadId)(VG_(get_running_tid())));
    145 #endif
    146 
    147    if (DRD_(running_thread_is_recording_loads)()
    148        && (s_check_stack_accesses
    149            || ! DRD_(thread_address_on_stack)(addr))
    150        && bm_access_load_triggers_conflict(addr, addr + size)
    151        && ! DRD_(is_suppressed)(addr, addr + size))
    152    {
    153       drd_report_race(addr, size, eLoad);
    154    }
    155 }
    156 
    157 static VG_REGPARM(1) void drd_trace_load_1(Addr addr)
    158 {
    159    if (DRD_(running_thread_is_recording_loads)()
    160        && (s_check_stack_accesses
    161            || ! DRD_(thread_address_on_stack)(addr))
    162        && bm_access_load_1_triggers_conflict(addr)
    163        && ! DRD_(is_suppressed)(addr, addr + 1))
    164    {
    165       drd_report_race(addr, 1, eLoad);
    166    }
    167 }
    168 
    169 static VG_REGPARM(1) void drd_trace_load_2(Addr addr)
    170 {
    171    if (DRD_(running_thread_is_recording_loads)()
    172        && (s_check_stack_accesses
    173            || ! DRD_(thread_address_on_stack)(addr))
    174        && bm_access_load_2_triggers_conflict(addr)
    175        && ! DRD_(is_suppressed)(addr, addr + 2))
    176    {
    177       drd_report_race(addr, 2, eLoad);
    178    }
    179 }
    180 
    181 static VG_REGPARM(1) void drd_trace_load_4(Addr addr)
    182 {
    183    if (DRD_(running_thread_is_recording_loads)()
    184        && (s_check_stack_accesses
    185            || ! DRD_(thread_address_on_stack)(addr))
    186        && bm_access_load_4_triggers_conflict(addr)
    187        && ! DRD_(is_suppressed)(addr, addr + 4))
    188    {
    189       drd_report_race(addr, 4, eLoad);
    190    }
    191 }
    192 
    193 static VG_REGPARM(1) void drd_trace_load_8(Addr addr)
    194 {
    195    if (DRD_(running_thread_is_recording_loads)()
    196        && (s_check_stack_accesses
    197            || ! DRD_(thread_address_on_stack)(addr))
    198        && bm_access_load_8_triggers_conflict(addr)
    199        && ! DRD_(is_suppressed)(addr, addr + 8))
    200    {
    201       drd_report_race(addr, 8, eLoad);
    202    }
    203 }
    204 
    205 VG_REGPARM(2) void DRD_(trace_store)(Addr addr, SizeT size)
    206 {
    207 #ifdef ENABLE_DRD_CONSISTENCY_CHECKS
    208    /* The assert below has been commented out because of performance reasons.*/
    209    tl_assert(DRD_(thread_get_running_tid)()
    210              == DRD_(VgThreadIdToDrdThreadId)(VG_(get_running_tid())));
    211 #endif
    212 
    213    if (DRD_(running_thread_is_recording_stores)()
    214        && (s_check_stack_accesses
    215            || ! DRD_(thread_address_on_stack)(addr))
    216        && bm_access_store_triggers_conflict(addr, addr + size)
    217        && ! DRD_(is_suppressed)(addr, addr + size))
    218    {
    219       drd_report_race(addr, size, eStore);
    220    }
    221 }
    222 
    223 static VG_REGPARM(1) void drd_trace_store_1(Addr addr)
    224 {
    225    if (DRD_(running_thread_is_recording_stores)()
    226        && (s_check_stack_accesses
    227            || ! DRD_(thread_address_on_stack)(addr))
    228        && bm_access_store_1_triggers_conflict(addr)
    229        && ! DRD_(is_suppressed)(addr, addr + 1))
    230    {
    231       drd_report_race(addr, 1, eStore);
    232    }
    233 }
    234 
    235 static VG_REGPARM(1) void drd_trace_store_2(Addr addr)
    236 {
    237    if (DRD_(running_thread_is_recording_stores)()
    238        && (s_check_stack_accesses
    239            || ! DRD_(thread_address_on_stack)(addr))
    240        && bm_access_store_2_triggers_conflict(addr)
    241        && ! DRD_(is_suppressed)(addr, addr + 2))
    242    {
    243       drd_report_race(addr, 2, eStore);
    244    }
    245 }
    246 
    247 static VG_REGPARM(1) void drd_trace_store_4(Addr addr)
    248 {
    249    if (DRD_(running_thread_is_recording_stores)()
    250        && (s_check_stack_accesses
    251            || ! DRD_(thread_address_on_stack)(addr))
    252        && bm_access_store_4_triggers_conflict(addr)
    253        && ! DRD_(is_suppressed)(addr, addr + 4))
    254    {
    255       drd_report_race(addr, 4, eStore);
    256    }
    257 }
    258 
    259 static VG_REGPARM(1) void drd_trace_store_8(Addr addr)
    260 {
    261    if (DRD_(running_thread_is_recording_stores)()
    262        && (s_check_stack_accesses
    263            || ! DRD_(thread_address_on_stack)(addr))
    264        && bm_access_store_8_triggers_conflict(addr)
    265        && ! DRD_(is_suppressed)(addr, addr + 8))
    266    {
    267       drd_report_race(addr, 8, eStore);
    268    }
    269 }
    270 
    271 /**
    272  * Return true if and only if addr_expr matches the pattern (SP) or
    273  * <offset>(SP).
    274  */
    275 static Bool is_stack_access(IRSB* const bb, IRExpr* const addr_expr)
    276 {
    277    Bool result = False;
    278 
    279    if (addr_expr->tag == Iex_RdTmp)
    280    {
    281       int i;
    282       for (i = 0; i < bb->stmts_size; i++)
    283       {
    284          if (bb->stmts[i]
    285              && bb->stmts[i]->tag == Ist_WrTmp
    286              && bb->stmts[i]->Ist.WrTmp.tmp == addr_expr->Iex.RdTmp.tmp)
    287          {
    288             IRExpr* e = bb->stmts[i]->Ist.WrTmp.data;
    289             if (e->tag == Iex_Get && e->Iex.Get.offset == STACK_POINTER_OFFSET)
    290             {
    291                result = True;
    292             }
    293 
    294             //ppIRExpr(e);
    295             //VG_(printf)(" (%s)\n", result ? "True" : "False");
    296             break;
    297          }
    298       }
    299    }
    300    return result;
    301 }
    302 
    303 static void instrument_load(IRSB* const bb,
    304                             IRExpr* const addr_expr,
    305                             const HWord size)
    306 {
    307    IRExpr* size_expr;
    308    IRExpr** argv;
    309    IRDirty* di;
    310 
    311    if (UNLIKELY(DRD_(any_address_is_traced)()))
    312    {
    313       addStmtToIRSB(bb,
    314          IRStmt_Dirty(
    315             unsafeIRDirty_0_N(/*regparms*/2,
    316                               "drd_trace_load",
    317                               VG_(fnptr_to_fnentry)
    318                               (drd_trace_mem_load),
    319                               mkIRExprVec_2(addr_expr,
    320                                             mkIRExpr_HWord(size)))));
    321    }
    322 
    323    if (! s_check_stack_accesses && is_stack_access(bb, addr_expr))
    324       return;
    325 
    326    switch (size)
    327    {
    328    case 1:
    329       argv = mkIRExprVec_1(addr_expr);
    330       di = unsafeIRDirty_0_N(/*regparms*/1,
    331                              "drd_trace_load_1",
    332                              VG_(fnptr_to_fnentry)(drd_trace_load_1),
    333                              argv);
    334       break;
    335    case 2:
    336       argv = mkIRExprVec_1(addr_expr);
    337       di = unsafeIRDirty_0_N(/*regparms*/1,
    338                              "drd_trace_load_2",
    339                              VG_(fnptr_to_fnentry)(drd_trace_load_2),
    340                              argv);
    341       break;
    342    case 4:
    343       argv = mkIRExprVec_1(addr_expr);
    344       di = unsafeIRDirty_0_N(/*regparms*/1,
    345                              "drd_trace_load_4",
    346                              VG_(fnptr_to_fnentry)(drd_trace_load_4),
    347                              argv);
    348       break;
    349    case 8:
    350       argv = mkIRExprVec_1(addr_expr);
    351       di = unsafeIRDirty_0_N(/*regparms*/1,
    352                              "drd_trace_load_8",
    353                              VG_(fnptr_to_fnentry)(drd_trace_load_8),
    354                              argv);
    355       break;
    356    default:
    357       size_expr = mkIRExpr_HWord(size);
    358       argv = mkIRExprVec_2(addr_expr, size_expr);
    359       di = unsafeIRDirty_0_N(/*regparms*/2,
    360                              "drd_trace_load",
    361                              VG_(fnptr_to_fnentry)(DRD_(trace_load)),
    362                              argv);
    363       break;
    364    }
    365    addStmtToIRSB(bb, IRStmt_Dirty(di));
    366 }
    367 
    368 static void instrument_store(IRSB* const bb,
    369                              IRExpr* const addr_expr,
    370                              const HWord size)
    371 {
    372    IRExpr* size_expr;
    373    IRExpr** argv;
    374    IRDirty* di;
    375 
    376    if (UNLIKELY(DRD_(any_address_is_traced)()))
    377    {
    378       addStmtToIRSB(bb,
    379                     IRStmt_Dirty(
    380                                  unsafeIRDirty_0_N(/*regparms*/2,
    381                                                    "drd_trace_store",
    382                                                    VG_(fnptr_to_fnentry)
    383                                                    (drd_trace_mem_store),
    384                                                    mkIRExprVec_2(addr_expr,
    385                                                                  mkIRExpr_HWord(size)))));
    386    }
    387 
    388    if (! s_check_stack_accesses && is_stack_access(bb, addr_expr))
    389       return;
    390 
    391    switch (size)
    392    {
    393    case 1:
    394       argv = mkIRExprVec_1(addr_expr);
    395       di = unsafeIRDirty_0_N(/*regparms*/1,
    396                              "drd_trace_store_1",
    397                              VG_(fnptr_to_fnentry)(drd_trace_store_1),
    398                              argv);
    399       break;
    400    case 2:
    401       argv = mkIRExprVec_1(addr_expr);
    402       di = unsafeIRDirty_0_N(/*regparms*/1,
    403                              "drd_trace_store_2",
    404                              VG_(fnptr_to_fnentry)(drd_trace_store_2),
    405                              argv);
    406       break;
    407    case 4:
    408       argv = mkIRExprVec_1(addr_expr);
    409       di = unsafeIRDirty_0_N(/*regparms*/1,
    410                              "drd_trace_store_4",
    411                              VG_(fnptr_to_fnentry)(drd_trace_store_4),
    412                              argv);
    413       break;
    414    case 8:
    415       argv = mkIRExprVec_1(addr_expr);
    416       di = unsafeIRDirty_0_N(/*regparms*/1,
    417                              "drd_trace_store_8",
    418                              VG_(fnptr_to_fnentry)(drd_trace_store_8),
    419                              argv);
    420       break;
    421    default:
    422       size_expr = mkIRExpr_HWord(size);
    423       argv = mkIRExprVec_2(addr_expr, size_expr);
    424       di = unsafeIRDirty_0_N(/*regparms*/2,
    425                              "drd_trace_store",
    426                              VG_(fnptr_to_fnentry)(DRD_(trace_store)),
    427                              argv);
    428       break;
    429    }
    430    addStmtToIRSB(bb, IRStmt_Dirty(di));
    431 }
    432 
    433 IRSB* DRD_(instrument)(VgCallbackClosure* const closure,
    434                        IRSB* const bb_in,
    435                        VexGuestLayout* const layout,
    436                        VexGuestExtents* const vge,
    437                        IRType const gWordTy,
    438                        IRType const hWordTy)
    439 {
    440    IRDirty* di;
    441    Int      i;
    442    IRSB*    bb;
    443    IRExpr** argv;
    444    Bool     instrument = True;
    445 
    446    /* Set up BB */
    447    bb           = emptyIRSB();
    448    bb->tyenv    = deepCopyIRTypeEnv(bb_in->tyenv);
    449    bb->next     = deepCopyIRExpr(bb_in->next);
    450    bb->jumpkind = bb_in->jumpkind;
    451 
    452    for (i = 0; i < bb_in->stmts_used; i++)
    453    {
    454       IRStmt* const st = bb_in->stmts[i];
    455       tl_assert(st);
    456       tl_assert(isFlatIRStmt(st));
    457 
    458       switch (st->tag)
    459       {
    460          /* Note: the code for not instrumenting the code in .plt          */
    461          /* sections is only necessary on CentOS 3.0 x86 (kernel 2.4.21    */
    462          /* + glibc 2.3.2 + NPTL 0.60 + binutils 2.14.90.0.4).             */
    463          /* This is because on this platform dynamic library symbols are   */
    464          /* relocated in another way than by later binutils versions. The  */
    465          /* linker e.g. does not generate .got.plt sections on CentOS 3.0. */
    466       case Ist_IMark:
    467          instrument = VG_(DebugInfo_sect_kind)(NULL, 0, st->Ist.IMark.addr)
    468             != Vg_SectPLT;
    469          addStmtToIRSB(bb, st);
    470          break;
    471 
    472       case Ist_MBE:
    473          switch (st->Ist.MBE.event)
    474          {
    475          case Imbe_Fence:
    476             break; /* not interesting */
    477          default:
    478             tl_assert(0);
    479          }
    480          addStmtToIRSB(bb, st);
    481          break;
    482 
    483       case Ist_Store:
    484          if (instrument)
    485          {
    486             instrument_store(bb,
    487                              st->Ist.Store.addr,
    488                              sizeofIRType(typeOfIRExpr(bb->tyenv,
    489                                                        st->Ist.Store.data)));
    490          }
    491          addStmtToIRSB(bb, st);
    492          break;
    493 
    494       case Ist_WrTmp:
    495          if (instrument)
    496          {
    497             const IRExpr* const data = st->Ist.WrTmp.data;
    498             if (data->tag == Iex_Load)
    499             {
    500                instrument_load(bb,
    501                                data->Iex.Load.addr,
    502                                sizeofIRType(data->Iex.Load.ty));
    503             }
    504          }
    505          addStmtToIRSB(bb, st);
    506          break;
    507 
    508       case Ist_Dirty:
    509          if (instrument)
    510          {
    511             IRDirty* d = st->Ist.Dirty.details;
    512             IREffect const mFx = d->mFx;
    513             switch (mFx) {
    514             case Ifx_None:
    515                break;
    516             case Ifx_Read:
    517             case Ifx_Write:
    518             case Ifx_Modify:
    519                tl_assert(d->mAddr);
    520                tl_assert(d->mSize > 0);
    521                argv = mkIRExprVec_2(d->mAddr, mkIRExpr_HWord(d->mSize));
    522                if (mFx == Ifx_Read || mFx == Ifx_Modify) {
    523                   di = unsafeIRDirty_0_N(
    524                           /*regparms*/2,
    525                           "drd_trace_load",
    526                           VG_(fnptr_to_fnentry)(DRD_(trace_load)),
    527                           argv);
    528                   addStmtToIRSB(bb, IRStmt_Dirty(di));
    529                }
    530                if (mFx == Ifx_Write || mFx == Ifx_Modify)
    531                {
    532                   di = unsafeIRDirty_0_N(
    533                           /*regparms*/2,
    534                           "drd_trace_store",
    535                           VG_(fnptr_to_fnentry)(DRD_(trace_store)),
    536                           argv);
    537                   addStmtToIRSB(bb, IRStmt_Dirty(di));
    538                }
    539                break;
    540             default:
    541                tl_assert(0);
    542             }
    543          }
    544          addStmtToIRSB(bb, st);
    545          break;
    546 
    547       case Ist_CAS:
    548          if (instrument)
    549          {
    550             /*
    551              * Treat compare-and-swap as a read. By handling atomic
    552              * instructions as read instructions no data races are reported
    553              * between conflicting atomic operations nor between atomic
    554              * operations and non-atomic reads. Conflicts between atomic
    555              * operations and non-atomic write operations are still reported
    556              * however.
    557              */
    558             Int    dataSize;
    559             IRCAS* cas = st->Ist.CAS.details;
    560             tl_assert(cas->addr != NULL);
    561             tl_assert(cas->dataLo != NULL);
    562             dataSize = sizeofIRType(typeOfIRExpr(bb->tyenv, cas->dataLo));
    563             if (cas->dataHi != NULL)
    564                dataSize *= 2; /* since it's a doubleword-CAS */
    565             instrument_load(bb, cas->addr, dataSize);
    566          }
    567          addStmtToIRSB(bb, st);
    568          break;
    569 
    570       case Ist_LLSC: {
    571          /* Ignore store-conditionals, and handle load-linked's
    572             exactly like normal loads. */
    573          IRType dataTy;
    574          if (st->Ist.LLSC.storedata == NULL)
    575          {
    576             /* LL */
    577             dataTy = typeOfIRTemp(bb_in->tyenv, st->Ist.LLSC.result);
    578             if (instrument) {
    579                instrument_load(bb,
    580                                st->Ist.LLSC.addr,
    581                                sizeofIRType(dataTy));
    582             }
    583          }
    584          else
    585          {
    586             /* SC */
    587             /*ignore */
    588          }
    589          addStmtToIRSB(bb, st);
    590          break;
    591       }
    592 
    593       case Ist_NoOp:
    594       case Ist_AbiHint:
    595       case Ist_Put:
    596       case Ist_PutI:
    597       case Ist_Exit:
    598          /* None of these can contain any memory references. */
    599          addStmtToIRSB(bb, st);
    600          break;
    601 
    602       default:
    603          ppIRStmt(st);
    604          tl_assert(0);
    605       }
    606    }
    607 
    608    return bb;
    609 }
    610 
    611