]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/drd/drd_load_store.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / drd / drd_load_store.c
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
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       VG_(message)(Vg_UserMsg,
97                    "%s 0x%lx size %ld (thread %d / vc %s)\n",
98                    access_type == eLoad
99                    ? "load "
100                    : access_type == eStore
101                    ? "store"
102                    : access_type == eStart
103                    ? "start"
104                    : access_type == eEnd
105                    ? "end  "
106                    : "????",
107                    addr,
108                    size,
109                    DRD_(thread_get_running_tid)(),
110                    vc);
111       VG_(free)(vc);
112       VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
113                                  VG_(clo_backtrace_size));
114       tl_assert(DRD_(DrdThreadIdToVgThreadId)(DRD_(thread_get_running_tid)())
115                 == VG_(get_running_tid)());
116    }
117 }
118
119 static VG_REGPARM(2) void drd_trace_mem_load(const Addr addr, const SizeT size)
120 {
121    return DRD_(trace_mem_access)(addr, size, eLoad);
122 }
123
124 static VG_REGPARM(2) void drd_trace_mem_store(const Addr addr,const SizeT size)
125 {
126    return DRD_(trace_mem_access)(addr, size, eStore);
127 }
128
129 static void drd_report_race(const Addr addr, const SizeT size,
130                             const BmAccessTypeT access_type)
131 {
132    DataRaceErrInfo drei;
133
134    drei.tid  = DRD_(thread_get_running_tid)();
135    drei.addr = addr;
136    drei.size = size;
137    drei.access_type = access_type;
138    VG_(maybe_record_error)(VG_(get_running_tid)(),
139                            DataRaceErr,
140                            VG_(get_IP)(VG_(get_running_tid)()),
141                            "Conflicting accesses",
142                            &drei);
143
144    if (s_first_race_only)
145    {
146       DRD_(start_suppression)(addr, addr + size, "first race only");
147    }
148 }
149
150 VG_REGPARM(2) void DRD_(trace_load)(Addr addr, SizeT size)
151 {
152 #ifdef ENABLE_DRD_CONSISTENCY_CHECKS
153    /* The assert below has been commented out because of performance reasons.*/
154    tl_assert(DRD_(thread_get_running_tid)()
155              == DRD_(VgThreadIdToDrdThreadId)(VG_(get_running_tid())));
156 #endif
157
158    if (DRD_(running_thread_is_recording_loads)()
159        && (s_check_stack_accesses
160            || ! DRD_(thread_address_on_stack)(addr))
161        && bm_access_load_triggers_conflict(addr, addr + size)
162        && ! DRD_(is_suppressed)(addr, addr + size))
163    {
164       drd_report_race(addr, size, eLoad);
165    }
166 }
167
168 static VG_REGPARM(1) void drd_trace_load_1(Addr addr)
169 {
170    if (DRD_(running_thread_is_recording_loads)()
171        && (s_check_stack_accesses
172            || ! DRD_(thread_address_on_stack)(addr))
173        && bm_access_load_1_triggers_conflict(addr)
174        && ! DRD_(is_suppressed)(addr, addr + 1))
175    {
176       drd_report_race(addr, 1, eLoad);
177    }
178 }
179
180 static VG_REGPARM(1) void drd_trace_load_2(Addr addr)
181 {
182    if (DRD_(running_thread_is_recording_loads)()
183        && (s_check_stack_accesses
184            || ! DRD_(thread_address_on_stack)(addr))
185        && bm_access_load_2_triggers_conflict(addr)
186        && ! DRD_(is_suppressed)(addr, addr + 2))
187    {
188       drd_report_race(addr, 2, eLoad);
189    }
190 }
191
192 static VG_REGPARM(1) void drd_trace_load_4(Addr addr)
193 {
194    if (DRD_(running_thread_is_recording_loads)()
195        && (s_check_stack_accesses
196            || ! DRD_(thread_address_on_stack)(addr))
197        && bm_access_load_4_triggers_conflict(addr)
198        && ! DRD_(is_suppressed)(addr, addr + 4))
199    {
200       drd_report_race(addr, 4, eLoad);
201    }
202 }
203
204 static VG_REGPARM(1) void drd_trace_load_8(Addr addr)
205 {
206    if (DRD_(running_thread_is_recording_loads)()
207        && (s_check_stack_accesses
208            || ! DRD_(thread_address_on_stack)(addr))
209        && bm_access_load_8_triggers_conflict(addr)
210        && ! DRD_(is_suppressed)(addr, addr + 8))
211    {
212       drd_report_race(addr, 8, eLoad);
213    }
214 }
215
216 VG_REGPARM(2) void DRD_(trace_store)(Addr addr, SizeT size)
217 {
218 #ifdef ENABLE_DRD_CONSISTENCY_CHECKS
219    /* The assert below has been commented out because of performance reasons.*/
220    tl_assert(DRD_(thread_get_running_tid)()
221              == DRD_(VgThreadIdToDrdThreadId)(VG_(get_running_tid())));
222 #endif
223
224    if (DRD_(running_thread_is_recording_stores)()
225        && (s_check_stack_accesses
226            || ! DRD_(thread_address_on_stack)(addr))
227        && bm_access_store_triggers_conflict(addr, addr + size)
228        && ! DRD_(is_suppressed)(addr, addr + size))
229    {
230       drd_report_race(addr, size, eStore);
231    }
232 }
233
234 static VG_REGPARM(1) void drd_trace_store_1(Addr addr)
235 {
236    if (DRD_(running_thread_is_recording_stores)()
237        && (s_check_stack_accesses
238            || ! DRD_(thread_address_on_stack)(addr))
239        && bm_access_store_1_triggers_conflict(addr)
240        && ! DRD_(is_suppressed)(addr, addr + 1))
241    {
242       drd_report_race(addr, 1, eStore);
243    }
244 }
245
246 static VG_REGPARM(1) void drd_trace_store_2(Addr addr)
247 {
248    if (DRD_(running_thread_is_recording_stores)()
249        && (s_check_stack_accesses
250            || ! DRD_(thread_address_on_stack)(addr))
251        && bm_access_store_2_triggers_conflict(addr)
252        && ! DRD_(is_suppressed)(addr, addr + 2))
253    {
254       drd_report_race(addr, 2, eStore);
255    }
256 }
257
258 static VG_REGPARM(1) void drd_trace_store_4(Addr addr)
259 {
260    if (DRD_(running_thread_is_recording_stores)()
261        && (s_check_stack_accesses
262            || ! DRD_(thread_address_on_stack)(addr))
263        && bm_access_store_4_triggers_conflict(addr)
264        && ! DRD_(is_suppressed)(addr, addr + 4))
265    {
266       drd_report_race(addr, 4, eStore);
267    }
268 }
269
270 static VG_REGPARM(1) void drd_trace_store_8(Addr addr)
271 {
272    if (DRD_(running_thread_is_recording_stores)()
273        && (s_check_stack_accesses
274            || ! DRD_(thread_address_on_stack)(addr))
275        && bm_access_store_8_triggers_conflict(addr)
276        && ! DRD_(is_suppressed)(addr, addr + 8))
277    {
278       drd_report_race(addr, 8, eStore);
279    }
280 }
281
282 /**
283  * Return true if and only if addr_expr matches the pattern (SP) or
284  * <offset>(SP).
285  */
286 static Bool is_stack_access(IRSB* const bb, IRExpr* const addr_expr)
287 {
288    Bool result = False;
289
290    if (addr_expr->tag == Iex_RdTmp)
291    {
292       int i;
293       for (i = 0; i < bb->stmts_size; i++)
294       {
295          if (bb->stmts[i]
296              && bb->stmts[i]->tag == Ist_WrTmp
297              && bb->stmts[i]->Ist.WrTmp.tmp == addr_expr->Iex.RdTmp.tmp)
298          {
299             IRExpr* e = bb->stmts[i]->Ist.WrTmp.data;
300             if (e->tag == Iex_Get && e->Iex.Get.offset == STACK_POINTER_OFFSET)
301             {
302                result = True;
303             }
304
305             //ppIRExpr(e);
306             //VG_(printf)(" (%s)\n", result ? "True" : "False");
307             break;
308          }
309       }
310    }
311    return result;
312 }
313
314 static void instrument_load(IRSB* const bb,
315                             IRExpr* const addr_expr,
316                             const HWord size)
317 {
318    IRExpr* size_expr;
319    IRExpr** argv;
320    IRDirty* di;
321
322    if (UNLIKELY(DRD_(any_address_is_traced)()))
323    {
324       addStmtToIRSB(bb,
325          IRStmt_Dirty(
326             unsafeIRDirty_0_N(/*regparms*/2,
327                               "drd_trace_load",
328                               VG_(fnptr_to_fnentry)
329                               (drd_trace_mem_load),
330                               mkIRExprVec_2(addr_expr,
331                                             mkIRExpr_HWord(size)))));
332    }
333
334    if (! s_check_stack_accesses && is_stack_access(bb, addr_expr))
335       return;
336
337    switch (size)
338    {
339    case 1:
340       argv = mkIRExprVec_1(addr_expr);
341       di = unsafeIRDirty_0_N(/*regparms*/1,
342                              "drd_trace_load_1",
343                              VG_(fnptr_to_fnentry)(drd_trace_load_1),
344                              argv);
345       break;
346    case 2:
347       argv = mkIRExprVec_1(addr_expr);
348       di = unsafeIRDirty_0_N(/*regparms*/1,
349                              "drd_trace_load_2",
350                              VG_(fnptr_to_fnentry)(drd_trace_load_2),
351                              argv);
352       break;
353    case 4:
354       argv = mkIRExprVec_1(addr_expr);
355       di = unsafeIRDirty_0_N(/*regparms*/1,
356                              "drd_trace_load_4",
357                              VG_(fnptr_to_fnentry)(drd_trace_load_4),
358                              argv);
359       break;
360    case 8:
361       argv = mkIRExprVec_1(addr_expr);
362       di = unsafeIRDirty_0_N(/*regparms*/1,
363                              "drd_trace_load_8",
364                              VG_(fnptr_to_fnentry)(drd_trace_load_8),
365                              argv);
366       break;
367    default:
368       size_expr = mkIRExpr_HWord(size);
369       argv = mkIRExprVec_2(addr_expr, size_expr);
370       di = unsafeIRDirty_0_N(/*regparms*/2,
371                              "drd_trace_load",
372                              VG_(fnptr_to_fnentry)(DRD_(trace_load)),
373                              argv);
374       break;
375    }
376    addStmtToIRSB(bb, IRStmt_Dirty(di));
377 }
378
379 static void instrument_store(IRSB* const bb,
380                              IRExpr* const addr_expr,
381                              const HWord size)
382 {
383    IRExpr* size_expr;
384    IRExpr** argv;
385    IRDirty* di;
386
387    if (UNLIKELY(DRD_(any_address_is_traced)()))
388    {
389       addStmtToIRSB(bb,
390                     IRStmt_Dirty(
391                                  unsafeIRDirty_0_N(/*regparms*/2,
392                                                    "drd_trace_store",
393                                                    VG_(fnptr_to_fnentry)
394                                                    (drd_trace_mem_store),
395                                                    mkIRExprVec_2(addr_expr,
396                                                                  mkIRExpr_HWord(size)))));
397    }
398
399    if (! s_check_stack_accesses && is_stack_access(bb, addr_expr))
400       return;
401
402    switch (size)
403    {
404    case 1:
405       argv = mkIRExprVec_1(addr_expr);
406       di = unsafeIRDirty_0_N(/*regparms*/1,
407                              "drd_trace_store_1",
408                              VG_(fnptr_to_fnentry)(drd_trace_store_1),
409                              argv);
410       break;
411    case 2:
412       argv = mkIRExprVec_1(addr_expr);
413       di = unsafeIRDirty_0_N(/*regparms*/1,
414                              "drd_trace_store_2",
415                              VG_(fnptr_to_fnentry)(drd_trace_store_2),
416                              argv);
417       break;
418    case 4:
419       argv = mkIRExprVec_1(addr_expr);
420       di = unsafeIRDirty_0_N(/*regparms*/1,
421                              "drd_trace_store_4",
422                              VG_(fnptr_to_fnentry)(drd_trace_store_4),
423                              argv);
424       break;
425    case 8:
426       argv = mkIRExprVec_1(addr_expr);
427       di = unsafeIRDirty_0_N(/*regparms*/1,
428                              "drd_trace_store_8",
429                              VG_(fnptr_to_fnentry)(drd_trace_store_8),
430                              argv);
431       break;
432    default:
433       size_expr = mkIRExpr_HWord(size);
434       argv = mkIRExprVec_2(addr_expr, size_expr);
435       di = unsafeIRDirty_0_N(/*regparms*/2,
436                              "drd_trace_store",
437                              VG_(fnptr_to_fnentry)(DRD_(trace_store)),
438                              argv);
439       break;
440    }
441    addStmtToIRSB(bb, IRStmt_Dirty(di));
442 }
443
444 IRSB* DRD_(instrument)(VgCallbackClosure* const closure,
445                        IRSB* const bb_in,
446                        VexGuestLayout* const layout,
447                        VexGuestExtents* const vge,
448                        IRType const gWordTy,
449                        IRType const hWordTy)
450 {
451    IRDirty* di;
452    Int      i;
453    IRSB*    bb;
454    IRExpr** argv;
455    Bool     instrument = True;
456
457    /* Set up BB */
458    bb           = emptyIRSB();
459    bb->tyenv    = deepCopyIRTypeEnv(bb_in->tyenv);
460    bb->next     = deepCopyIRExpr(bb_in->next);
461    bb->jumpkind = bb_in->jumpkind;
462
463    for (i = 0; i < bb_in->stmts_used; i++)
464    {
465       IRStmt* const st = bb_in->stmts[i];
466       tl_assert(st);
467       tl_assert(isFlatIRStmt(st));
468
469       switch (st->tag)
470       {
471          /* Note: the code for not instrumenting the code in .plt          */
472          /* sections is only necessary on CentOS 3.0 x86 (kernel 2.4.21    */
473          /* + glibc 2.3.2 + NPTL 0.60 + binutils 2.14.90.0.4).             */
474          /* This is because on this platform dynamic library symbols are   */
475          /* relocated in another way than by later binutils versions. The  */
476          /* linker e.g. does not generate .got.plt sections on CentOS 3.0. */
477       case Ist_IMark:
478          instrument = VG_(DebugInfo_sect_kind)(NULL, 0, st->Ist.IMark.addr)
479             != Vg_SectPLT;
480          addStmtToIRSB(bb, st);
481          break;
482
483       case Ist_MBE:
484          switch (st->Ist.MBE.event)
485          {
486          case Imbe_Fence:
487             break; /* not interesting */
488          default:
489             tl_assert(0);
490          }
491          addStmtToIRSB(bb, st);
492          break;
493
494       case Ist_Store:
495          if (instrument)
496          {
497             instrument_store(bb,
498                              st->Ist.Store.addr,
499                              sizeofIRType(typeOfIRExpr(bb->tyenv,
500                                                        st->Ist.Store.data)));
501          }
502          addStmtToIRSB(bb, st);
503          break;
504
505       case Ist_WrTmp:
506          if (instrument)
507          {
508             const IRExpr* const data = st->Ist.WrTmp.data;
509             if (data->tag == Iex_Load)
510             {
511                instrument_load(bb,
512                                data->Iex.Load.addr,
513                                sizeofIRType(data->Iex.Load.ty));
514             }
515          }
516          addStmtToIRSB(bb, st);
517          break;
518
519       case Ist_Dirty:
520          if (instrument)
521          {
522             IRDirty* d = st->Ist.Dirty.details;
523             IREffect const mFx = d->mFx;
524             switch (mFx) {
525             case Ifx_None:
526                break;
527             case Ifx_Read:
528             case Ifx_Write:
529             case Ifx_Modify:
530                tl_assert(d->mAddr);
531                tl_assert(d->mSize > 0);
532                argv = mkIRExprVec_2(d->mAddr, mkIRExpr_HWord(d->mSize));
533                if (mFx == Ifx_Read || mFx == Ifx_Modify) {
534                   di = unsafeIRDirty_0_N(
535                           /*regparms*/2,
536                           "drd_trace_load",
537                           VG_(fnptr_to_fnentry)(DRD_(trace_load)),
538                           argv);
539                   addStmtToIRSB(bb, IRStmt_Dirty(di));
540                }
541                if (mFx == Ifx_Write || mFx == Ifx_Modify)
542                {
543                   di = unsafeIRDirty_0_N(
544                           /*regparms*/2,
545                           "drd_trace_store",
546                           VG_(fnptr_to_fnentry)(DRD_(trace_store)),
547                           argv);
548                   addStmtToIRSB(bb, IRStmt_Dirty(di));
549                }
550                break;
551             default:
552                tl_assert(0);
553             }
554          }
555          addStmtToIRSB(bb, st);
556          break;
557
558       case Ist_CAS:
559          if (instrument)
560          {
561             /*
562              * Treat compare-and-swap as a read. By handling atomic
563              * instructions as read instructions no data races are reported
564              * between conflicting atomic operations nor between atomic
565              * operations and non-atomic reads. Conflicts between atomic
566              * operations and non-atomic write operations are still reported
567              * however.
568              */
569             Int    dataSize;
570             IRCAS* cas = st->Ist.CAS.details;
571             tl_assert(cas->addr != NULL);
572             tl_assert(cas->dataLo != NULL);
573             dataSize = sizeofIRType(typeOfIRExpr(bb->tyenv, cas->dataLo));
574             if (cas->dataHi != NULL)
575                dataSize *= 2; /* since it's a doubleword-CAS */
576             instrument_load(bb, cas->addr, dataSize);
577          }
578          addStmtToIRSB(bb, st);
579          break;
580
581       case Ist_LLSC: {
582          /* Ignore store-conditionals, and handle load-linked's
583             exactly like normal loads. */
584          IRType dataTy;
585          if (st->Ist.LLSC.storedata == NULL)
586          {
587             /* LL */
588             dataTy = typeOfIRTemp(bb_in->tyenv, st->Ist.LLSC.result);
589             if (instrument) {
590                instrument_load(bb,
591                                st->Ist.LLSC.addr,
592                                sizeofIRType(dataTy));
593             }
594          }
595          else
596          {
597             /* SC */
598             /*ignore */
599          }
600          addStmtToIRSB(bb, st);
601          break;
602       }
603
604       case Ist_NoOp:
605       case Ist_AbiHint:
606       case Ist_Put:
607       case Ist_PutI:
608       case Ist_Exit:
609          /* None of these can contain any memory references. */
610          addStmtToIRSB(bb, st);
611          break;
612
613       default:
614          ppIRStmt(st);
615          tl_assert(0);
616       }
617    }
618
619    return bb;
620 }
621