• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
DRD_(get_check_stack_accesses)66 Bool DRD_(get_check_stack_accesses)()
67 {
68    return s_check_stack_accesses;
69 }
70 
DRD_(set_check_stack_accesses)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 
DRD_(get_first_race_only)77 Bool DRD_(get_first_race_only)()
78 {
79    return s_first_race_only;
80 }
81 
DRD_(set_first_race_only)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 
DRD_(trace_mem_access)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 
drd_trace_mem_load(const Addr addr,const SizeT size)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 
drd_trace_mem_store(const Addr addr,const SizeT size)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 
drd_report_race(const Addr addr,const SizeT size,const BmAccessTypeT access_type)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 
DRD_(trace_load)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 
drd_trace_load_1(Addr addr)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 
drd_trace_load_2(Addr addr)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 
drd_trace_load_4(Addr addr)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 
drd_trace_load_8(Addr addr)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 
DRD_(trace_store)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 
drd_trace_store_1(Addr addr)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 
drd_trace_store_2(Addr addr)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 
drd_trace_store_4(Addr addr)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 
drd_trace_store_8(Addr addr)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  */
is_stack_access(IRSB * const bb,IRExpr * const addr_expr)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 
instrument_load(IRSB * const bb,IRExpr * const addr_expr,const HWord size)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 
instrument_store(IRSB * const bb,IRExpr * const addr_expr,const HWord size)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 
DRD_(instrument)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