2 This file is part of drd, a thread error detector.
4 Copyright (C) 2006-2017 Bart Van Assche <bvanassche@acm.org>.
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.
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.
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
21 The GNU General Public License is contained in the file COPYING.
25 #include "drd_bitmap.h"
26 #include "drd_thread_bitmap.h"
27 #include "drd_vc.h" /* DRD_(vc_snprint)() */
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"
36 #include "libvex_guest_offsets.h"
39 /* STACK_POINTER_OFFSET: VEX register offset for the stack pointer register. */
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
59 #error Unknown architecture.
63 /* Local variables. */
65 static Bool s_check_stack_accesses
= False
;
66 static Bool s_first_race_only
= False
;
69 /* Function definitions. */
71 Bool
DRD_(get_check_stack_accesses
)()
73 return s_check_stack_accesses
;
76 void DRD_(set_check_stack_accesses
)(const Bool c
)
78 tl_assert(c
== False
|| c
== True
);
79 s_check_stack_accesses
= c
;
82 Bool
DRD_(get_first_race_only
)()
84 return s_first_race_only
;
87 void DRD_(set_first_race_only
)(const Bool fro
)
89 tl_assert(fro
== False
|| fro
== True
);
90 s_first_race_only
= fro
;
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
)
98 if (DRD_(is_any_traced
)(addr
, addr
+ size
))
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
)(),
108 } else if (access_type
== eStore
&& size
> sizeof(HWord
)) {
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
);
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
);
125 tl_assert(DRD_(DrdThreadIdToVgThreadId
)(DRD_(thread_get_running_tid
)())
126 == VG_(get_running_tid
)());
130 static VG_REGPARM(2) void drd_trace_mem_load(const Addr addr
, const SizeT size
)
132 return DRD_(trace_mem_access
)(addr
, size
, eLoad
, 0, 0);
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
)
139 return DRD_(trace_mem_access
)(addr
, size
, eStore
, stored_value_hi
,
143 static void drd_report_race(const Addr addr
, const SizeT size
,
144 const BmAccessTypeT access_type
)
148 vg_tid
= VG_(get_running_tid
)();
149 if (!DRD_(get_check_stack_accesses
)()
150 && DRD_(thread_address_on_any_stack
)(addr
)) {
152 GenericErrInfo GEI
= {
153 .tid
= DRD_(thread_get_running_tid
)(),
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",
162 DataRaceErrInfo drei
= {
163 .tid
= DRD_(thread_get_running_tid
)(),
166 .access_type
= access_type
,
168 VG_(maybe_record_error
)(vg_tid
, DataRaceErr
, VG_(get_IP
)(vg_tid
),
169 "Conflicting access", &drei
);
171 if (s_first_race_only
)
172 DRD_(start_suppression
)(addr
, addr
+ size
, "first race only");
176 VG_REGPARM(2) void DRD_(trace_load
)(Addr addr
, SizeT size
)
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
)()));
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
))
190 drd_report_race(addr
, size
, eLoad
);
194 static VG_REGPARM(1) void drd_trace_load_1(Addr addr
)
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))
202 drd_report_race(addr
, 1, eLoad
);
206 static VG_REGPARM(1) void drd_trace_load_2(Addr addr
)
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))
214 drd_report_race(addr
, 2, eLoad
);
218 static VG_REGPARM(1) void drd_trace_load_4(Addr addr
)
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))
226 drd_report_race(addr
, 4, eLoad
);
230 static VG_REGPARM(1) void drd_trace_load_8(Addr addr
)
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))
238 drd_report_race(addr
, 8, eLoad
);
242 VG_REGPARM(2) void DRD_(trace_store
)(Addr addr
, SizeT size
)
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
)()));
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
))
256 drd_report_race(addr
, size
, eStore
);
260 static VG_REGPARM(1) void drd_trace_store_1(Addr addr
)
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))
268 drd_report_race(addr
, 1, eStore
);
272 static VG_REGPARM(1) void drd_trace_store_2(Addr addr
)
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))
280 drd_report_race(addr
, 2, eStore
);
284 static VG_REGPARM(1) void drd_trace_store_4(Addr addr
)
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))
292 drd_report_race(addr
, 4, eStore
);
296 static VG_REGPARM(1) void drd_trace_store_8(Addr addr
)
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))
304 drd_report_race(addr
, 8, eStore
);
309 * Return true if and only if addr_expr matches the pattern (SP) or
312 static Bool
is_stack_access(IRSB
* const bb
, IRExpr
* const addr_expr
)
316 if (addr_expr
->tag
== Iex_RdTmp
)
319 for (i
= 0; i
< bb
->stmts_used
; i
++)
322 && bb
->stmts
[i
]->tag
== Ist_WrTmp
323 && bb
->stmts
[i
]->Ist
.WrTmp
.tmp
== addr_expr
->Iex
.RdTmp
.tmp
)
325 IRExpr
* e
= bb
->stmts
[i
]->Ist
.WrTmp
.data
;
326 if (e
->tag
== Iex_Get
&& e
->Iex
.Get
.offset
== STACK_POINTER_OFFSET
)
332 //VG_(printf)(" (%s)\n", result ? "True" : "False");
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
},
348 * Instrument the client code to trace a memory load (--trace-addr).
350 static IRExpr
* instr_trace_mem_load(IRSB
* const bb
, IRExpr
* addr_expr
,
352 IRExpr
* const guard
/* NULL => True */)
356 tmp
= newIRTemp(bb
->tyenv
, typeOfIRExpr(bb
->tyenv
, addr_expr
));
357 addStmtToIRSB(bb
, IRStmt_WrTmp(tmp
, addr_expr
));
358 addr_expr
= IRExpr_RdTmp(tmp
);
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
));
372 * Instrument the client code to trace a memory store (--trace-addr).
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 */)
381 tl_assert(sizeof(HWord
) == 4 || sizeof(HWord
) == 8);
382 tl_assert(!data_expr_hi
|| typeOfIRExpr(bb
->tyenv
, data_expr_hi
) == Ity_I32
);
384 ty_data_expr
= typeOfIRExpr(bb
->tyenv
, data_expr_lo
);
385 size
= sizeofIRType(ty_data_expr
);
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
;
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
,
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
,
414 data_expr_lo
= IRExpr_RdTmp(tmp
);
415 ty_data_expr
= Ity_I64
;
418 if (size
== sizeof(HWord
)
419 && (ty_data_expr
== Ity_I32
|| ty_data_expr
== Ity_I64
))
421 /* No conversion necessary */
425 if (Ity_I1
<= ty_data_expr
427 < Ity_I1
+ sizeof(u_widen_irop
)/sizeof(u_widen_irop
[0]))
429 widen_op
= u_widen_irop
[ty_data_expr
- Ity_I1
][sizeof(HWord
)];
431 widen_op
= Iop_INVALID
;
433 widen_op
= Iop_INVALID
;
435 if (widen_op
!= Iop_INVALID
) {
438 /* Widen the integer expression to a HWord */
439 tmp
= newIRTemp(bb
->tyenv
, sizeof(HWord
) == 4 ? Ity_I32
: Ity_I64
);
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
) {
447 tl_assert(sizeof(HWord
) == 4);
448 tl_assert(size
== 8);
449 tmp
= newIRTemp(bb
->tyenv
, Ity_I32
);
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
);
459 data_expr_lo
= mkIRExpr_HWord(0);
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
) );
473 static void instrument_load(IRSB
* const bb
, IRExpr
* const addr_expr
,
475 IRExpr
* const guard
/* NULL => True */)
481 if (!s_check_stack_accesses
&& is_stack_access(bb
, addr_expr
))
487 argv
= mkIRExprVec_1(addr_expr
);
488 di
= unsafeIRDirty_0_N(/*regparms*/1,
490 VG_(fnptr_to_fnentry
)(drd_trace_load_1
),
494 argv
= mkIRExprVec_1(addr_expr
);
495 di
= unsafeIRDirty_0_N(/*regparms*/1,
497 VG_(fnptr_to_fnentry
)(drd_trace_load_2
),
501 argv
= mkIRExprVec_1(addr_expr
);
502 di
= unsafeIRDirty_0_N(/*regparms*/1,
504 VG_(fnptr_to_fnentry
)(drd_trace_load_4
),
508 argv
= mkIRExprVec_1(addr_expr
);
509 di
= unsafeIRDirty_0_N(/*regparms*/1,
511 VG_(fnptr_to_fnentry
)(drd_trace_load_8
),
515 size_expr
= mkIRExpr_HWord(size
);
516 argv
= mkIRExprVec_2(addr_expr
, size_expr
);
517 di
= unsafeIRDirty_0_N(/*regparms*/2,
519 VG_(fnptr_to_fnentry
)(DRD_(trace_load
)),
523 if (guard
) di
->guard
= guard
;
524 addStmtToIRSB(bb
, IRStmt_Dirty(di
));
527 static void instrument_store(IRSB
* const bb
, IRExpr
* addr_expr
,
528 IRExpr
* const data_expr
,
529 IRExpr
* const guard_expr
/* NULL => True */)
536 size
= sizeofIRType(typeOfIRExpr(bb
->tyenv
, data_expr
));
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
);
545 if (!s_check_stack_accesses
&& is_stack_access(bb
, addr_expr
))
551 argv
= mkIRExprVec_1(addr_expr
);
552 di
= unsafeIRDirty_0_N(/*regparms*/1,
554 VG_(fnptr_to_fnentry
)(drd_trace_store_1
),
558 argv
= mkIRExprVec_1(addr_expr
);
559 di
= unsafeIRDirty_0_N(/*regparms*/1,
561 VG_(fnptr_to_fnentry
)(drd_trace_store_2
),
565 argv
= mkIRExprVec_1(addr_expr
);
566 di
= unsafeIRDirty_0_N(/*regparms*/1,
568 VG_(fnptr_to_fnentry
)(drd_trace_store_4
),
572 argv
= mkIRExprVec_1(addr_expr
);
573 di
= unsafeIRDirty_0_N(/*regparms*/1,
575 VG_(fnptr_to_fnentry
)(drd_trace_store_8
),
579 size_expr
= mkIRExpr_HWord(size
);
580 argv
= mkIRExprVec_2(addr_expr
, size_expr
);
581 di
= unsafeIRDirty_0_N(/*regparms*/2,
583 VG_(fnptr_to_fnentry
)(DRD_(trace_store
)),
587 if (guard_expr
) di
->guard
= guard_expr
;
588 addStmtToIRSB(bb
, IRStmt_Dirty(di
));
591 IRSB
* DRD_(instrument
)(VgCallbackClosure
* const closure
,
593 const VexGuestLayout
* const layout
,
594 const VexGuestExtents
* const vge
,
595 const VexArchInfo
* archinfo_host
,
596 IRType
const gWordTy
,
597 IRType
const hWordTy
)
603 Bool instrument
= True
;
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
;
612 for (i
= 0; i
< bb_in
->stmts_used
; i
++)
614 IRStmt
* const st
= bb_in
->stmts
[i
];
616 tl_assert(isFlatIRStmt(st
));
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. */
627 instrument
= VG_(DebugInfo_sect_kind
)(NULL
, st
->Ist
.IMark
.addr
)
629 addStmtToIRSB(bb
, st
);
633 switch (st
->Ist
.MBE
.event
)
636 break; /* not interesting to DRD */
637 case Imbe_CancelReservation
:
638 break; /* not interesting to DRD */
642 addStmtToIRSB(bb
, st
);
647 instrument_store(bb
, st
->Ist
.Store
.addr
, st
->Ist
.Store
.data
,
649 addStmtToIRSB(bb
, st
);
653 IRStoreG
* sg
= st
->Ist
.StoreG
.details
;
654 IRExpr
* data
= sg
->data
;
655 IRExpr
* addr
= sg
->addr
;
657 instrument_store(bb
, addr
, data
, sg
->guard
);
658 addStmtToIRSB(bb
, st
);
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
);
673 instrument_load(bb
, lg
->addr
,
674 sizeofIRType(type
), lg
->guard
);
675 addStmtToIRSB(bb
, st
);
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
),
689 instrument_load(bb
, addr_expr
, sizeofIRType(data
->Iex
.Load
.ty
),
693 addStmtToIRSB(bb
, st
);
698 IRDirty
* d
= st
->Ist
.Dirty
.details
;
699 IREffect
const mFx
= d
->mFx
;
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(
713 VG_(fnptr_to_fnentry
)(DRD_(trace_load
)),
715 addStmtToIRSB(bb
, IRStmt_Dirty(di
));
717 if (mFx
== Ifx_Write
|| mFx
== Ifx_Modify
)
719 di
= unsafeIRDirty_0_N(
722 VG_(fnptr_to_fnentry
)(DRD_(trace_store
)),
724 addStmtToIRSB(bb
, IRStmt_Dirty(di
));
731 addStmtToIRSB(bb
, st
);
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
745 IRCAS
* cas
= st
->Ist
.CAS
.details
;
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 */
753 if (UNLIKELY(DRD_(any_address_is_traced
)()))
754 instr_trace_mem_store(bb
, cas
->addr
, cas
->dataHi
, cas
->dataLo
,
757 instrument_load(bb
, cas
->addr
, dataSize
, NULL
/*no guard*/);
759 addStmtToIRSB(bb
, st
);
764 * Ignore store-conditionals (except for tracing), and handle
765 * load-linked's exactly like normal loads.
769 if (st
->Ist
.LLSC
.storedata
== NULL
) {
771 dataTy
= typeOfIRTemp(bb_in
->tyenv
, st
->Ist
.LLSC
.result
);
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 */);
779 instrument_load(bb
, addr_expr
, sizeofIRType(dataTy
),
784 instr_trace_mem_store(bb
, st
->Ist
.LLSC
.addr
, NULL
,
785 st
->Ist
.LLSC
.storedata
,
788 addStmtToIRSB(bb
, st
);
797 /* None of these can contain any memory references. */
798 addStmtToIRSB(bb
, st
);