blob: 990082046194be8e8f3ddfba68e20566f4e279b7 [file] [log] [blame]
bart09dc13f2009-02-14 15:13:31 +00001/*
bart86562bd2009-02-16 19:43:56 +00002 This file is part of drd, a thread error detector.
bart09dc13f2009-02-14 15:13:31 +00003
sewardj03f8d3f2012-08-05 15:46:46 +00004 Copyright (C) 2006-2012 Bart Van Assche <bvanassche@acm.org>.
bart09dc13f2009-02-14 15:13:31 +00005
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"
bart41b226c2009-02-14 16:55:19 +000027#include "drd_vc.h" /* DRD_(vc_snprint)() */
bart09dc13f2009-02-14 15:13:31 +000028
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)
sewardj4cb6bf72010-01-01 18:31:41 +000045#define STACK_POINTER_OFFSET OFFSET_ppc32_GPR1
bart09dc13f2009-02-14 15:13:31 +000046#elif defined(VGA_ppc64)
sewardj4cb6bf72010-01-01 18:31:41 +000047#define STACK_POINTER_OFFSET OFFSET_ppc64_GPR1
48#elif defined(VGA_arm)
49#define STACK_POINTER_OFFSET OFFSET_arm_R13
sewardjb5b87402011-03-07 16:05:35 +000050#elif defined(VGA_s390x)
51#define STACK_POINTER_OFFSET OFFSET_s390x_r15
sewardj5db15402012-06-07 09:13:21 +000052#elif defined(VGA_mips32)
53#define STACK_POINTER_OFFSET OFFSET_mips32_r29
bart09dc13f2009-02-14 15:13:31 +000054#else
55#error Unknown architecture.
56#endif
57
58
59/* Local variables. */
60
bartf98a5692009-05-03 17:17:37 +000061static Bool s_check_stack_accesses = False;
62static Bool s_first_race_only = False;
bart09dc13f2009-02-14 15:13:31 +000063
64
65/* Function definitions. */
66
67Bool DRD_(get_check_stack_accesses)()
68{
bartf98a5692009-05-03 17:17:37 +000069 return s_check_stack_accesses;
bart09dc13f2009-02-14 15:13:31 +000070}
71
72void DRD_(set_check_stack_accesses)(const Bool c)
73{
bartbedfd232009-03-26 19:07:15 +000074 tl_assert(c == False || c == True);
bartf98a5692009-05-03 17:17:37 +000075 s_check_stack_accesses = c;
76}
77
78Bool DRD_(get_first_race_only)()
79{
80 return s_first_race_only;
81}
82
83void DRD_(set_first_race_only)(const Bool fro)
84{
85 tl_assert(fro == False || fro == True);
86 s_first_race_only = fro;
bart09dc13f2009-02-14 15:13:31 +000087}
88
bart1335ecc2009-02-14 16:10:53 +000089void DRD_(trace_mem_access)(const Addr addr, const SizeT size,
bart7826acb2011-12-11 18:49:39 +000090 const BmAccessTypeT access_type,
bart42f32632011-12-13 11:12:05 +000091 const HWord stored_value_hi,
92 const HWord stored_value_lo)
bart09dc13f2009-02-14 15:13:31 +000093{
bartbedfd232009-03-26 19:07:15 +000094 if (DRD_(is_any_traced)(addr, addr + size))
95 {
bart8f822af2009-06-08 18:20:42 +000096 char* vc;
97
98 vc = DRD_(vc_aprint)(DRD_(thread_get_vc)(DRD_(thread_get_running_tid)()));
bart7826acb2011-12-11 18:49:39 +000099 if (access_type == eStore && size <= sizeof(HWord)) {
bart5cda1b52011-12-12 19:37:10 +0000100 DRD_(trace_msg_w_bt)("store 0x%lx size %ld val %ld/0x%lx (thread %d /"
bart42f32632011-12-13 11:12:05 +0000101 " vc %s)", addr, size, stored_value_lo,
102 stored_value_lo, DRD_(thread_get_running_tid)(),
103 vc);
104 } else if (access_type == eStore && size > sizeof(HWord)) {
105 ULong sv;
106
107 tl_assert(sizeof(HWord) == 4);
108 sv = ((ULong)stored_value_hi << 32) | stored_value_lo;
109 DRD_(trace_msg_w_bt)("store 0x%lx size %ld val %lld/0x%llx (thread %d"
110 " / vc %s)", addr, size, sv, sv,
bart7826acb2011-12-11 18:49:39 +0000111 DRD_(thread_get_running_tid)(), vc);
112 } else {
113 DRD_(trace_msg_w_bt)("%s 0x%lx size %ld (thread %d / vc %s)",
114 access_type == eLoad ? "load "
115 : access_type == eStore ? "store"
116 : access_type == eStart ? "start"
117 : access_type == eEnd ? "end " : "????",
118 addr, size, DRD_(thread_get_running_tid)(), vc);
119 }
bart8f822af2009-06-08 18:20:42 +0000120 VG_(free)(vc);
bartbedfd232009-03-26 19:07:15 +0000121 tl_assert(DRD_(DrdThreadIdToVgThreadId)(DRD_(thread_get_running_tid)())
122 == VG_(get_running_tid)());
123 }
bart09dc13f2009-02-14 15:13:31 +0000124}
125
bart07595032010-08-29 09:51:06 +0000126static VG_REGPARM(2) void drd_trace_mem_load(const Addr addr, const SizeT size)
bart09dc13f2009-02-14 15:13:31 +0000127{
bart42f32632011-12-13 11:12:05 +0000128 return DRD_(trace_mem_access)(addr, size, eLoad, 0, 0);
bart09dc13f2009-02-14 15:13:31 +0000129}
130
bart7826acb2011-12-11 18:49:39 +0000131static VG_REGPARM(3) void drd_trace_mem_store(const Addr addr,const SizeT size,
bart42f32632011-12-13 11:12:05 +0000132 const HWord stored_value_hi,
133 const HWord stored_value_lo)
bart09dc13f2009-02-14 15:13:31 +0000134{
bart42f32632011-12-13 11:12:05 +0000135 return DRD_(trace_mem_access)(addr, size, eStore, stored_value_hi,
136 stored_value_lo);
bart09dc13f2009-02-14 15:13:31 +0000137}
138
139static void drd_report_race(const Addr addr, const SizeT size,
140 const BmAccessTypeT access_type)
141{
bart7a9db0f2012-04-01 14:40:16 +0000142 ThreadId vg_tid;
bart09dc13f2009-02-14 15:13:31 +0000143
bart7a9db0f2012-04-01 14:40:16 +0000144 vg_tid = VG_(get_running_tid)();
bart7886dd32012-04-01 15:06:57 +0000145 if (!DRD_(get_check_stack_accesses)()
146 && DRD_(thread_address_on_any_stack)(addr)) {
bart7a9db0f2012-04-01 14:40:16 +0000147#if 0
148 GenericErrInfo GEI = {
149 .tid = DRD_(thread_get_running_tid)(),
150 .addr = addr,
151 };
152 VG_(maybe_record_error)(vg_tid, GenericErr, VG_(get_IP)(vg_tid),
153 "--check-stack-var=no skips checking stack"
154 " variables shared over threads",
155 &GEI);
156#endif
157 } else {
158 DataRaceErrInfo drei = {
159 .tid = DRD_(thread_get_running_tid)(),
160 .addr = addr,
161 .size = size,
162 .access_type = access_type,
163 };
164 VG_(maybe_record_error)(vg_tid, DataRaceErr, VG_(get_IP)(vg_tid),
165 "Conflicting access", &drei);
bartf98a5692009-05-03 17:17:37 +0000166
bart7a9db0f2012-04-01 14:40:16 +0000167 if (s_first_race_only)
168 DRD_(start_suppression)(addr, addr + size, "first race only");
bartf98a5692009-05-03 17:17:37 +0000169 }
bart09dc13f2009-02-14 15:13:31 +0000170}
171
bart99edb292009-02-15 15:59:20 +0000172VG_REGPARM(2) void DRD_(trace_load)(Addr addr, SizeT size)
bart09dc13f2009-02-14 15:13:31 +0000173{
174#ifdef ENABLE_DRD_CONSISTENCY_CHECKS
bartbedfd232009-03-26 19:07:15 +0000175 /* The assert below has been commented out because of performance reasons.*/
bartd5bbc612010-09-02 14:44:17 +0000176 tl_assert(DRD_(thread_get_running_tid)()
177 == DRD_(VgThreadIdToDrdThreadId)(VG_(get_running_tid())));
bart09dc13f2009-02-14 15:13:31 +0000178#endif
179
bartd45d9952009-05-31 18:53:54 +0000180 if (DRD_(running_thread_is_recording_loads)()
bartf98a5692009-05-03 17:17:37 +0000181 && (s_check_stack_accesses
bartbedfd232009-03-26 19:07:15 +0000182 || ! DRD_(thread_address_on_stack)(addr))
183 && bm_access_load_triggers_conflict(addr, addr + size)
184 && ! DRD_(is_suppressed)(addr, addr + size))
185 {
186 drd_report_race(addr, size, eLoad);
187 }
bart09dc13f2009-02-14 15:13:31 +0000188}
189
190static VG_REGPARM(1) void drd_trace_load_1(Addr addr)
191{
bartd45d9952009-05-31 18:53:54 +0000192 if (DRD_(running_thread_is_recording_loads)()
bartf98a5692009-05-03 17:17:37 +0000193 && (s_check_stack_accesses
bartbedfd232009-03-26 19:07:15 +0000194 || ! DRD_(thread_address_on_stack)(addr))
195 && bm_access_load_1_triggers_conflict(addr)
196 && ! DRD_(is_suppressed)(addr, addr + 1))
197 {
198 drd_report_race(addr, 1, eLoad);
199 }
bart09dc13f2009-02-14 15:13:31 +0000200}
201
202static VG_REGPARM(1) void drd_trace_load_2(Addr addr)
203{
bartd45d9952009-05-31 18:53:54 +0000204 if (DRD_(running_thread_is_recording_loads)()
bartf98a5692009-05-03 17:17:37 +0000205 && (s_check_stack_accesses
bartbedfd232009-03-26 19:07:15 +0000206 || ! DRD_(thread_address_on_stack)(addr))
207 && bm_access_load_2_triggers_conflict(addr)
208 && ! DRD_(is_suppressed)(addr, addr + 2))
209 {
210 drd_report_race(addr, 2, eLoad);
211 }
bart09dc13f2009-02-14 15:13:31 +0000212}
213
214static VG_REGPARM(1) void drd_trace_load_4(Addr addr)
215{
bartd45d9952009-05-31 18:53:54 +0000216 if (DRD_(running_thread_is_recording_loads)()
bartf98a5692009-05-03 17:17:37 +0000217 && (s_check_stack_accesses
bartbedfd232009-03-26 19:07:15 +0000218 || ! DRD_(thread_address_on_stack)(addr))
219 && bm_access_load_4_triggers_conflict(addr)
220 && ! DRD_(is_suppressed)(addr, addr + 4))
221 {
222 drd_report_race(addr, 4, eLoad);
223 }
bart09dc13f2009-02-14 15:13:31 +0000224}
225
226static VG_REGPARM(1) void drd_trace_load_8(Addr addr)
227{
bartd45d9952009-05-31 18:53:54 +0000228 if (DRD_(running_thread_is_recording_loads)()
bartf98a5692009-05-03 17:17:37 +0000229 && (s_check_stack_accesses
bartbedfd232009-03-26 19:07:15 +0000230 || ! DRD_(thread_address_on_stack)(addr))
231 && bm_access_load_8_triggers_conflict(addr)
232 && ! DRD_(is_suppressed)(addr, addr + 8))
233 {
234 drd_report_race(addr, 8, eLoad);
235 }
bart09dc13f2009-02-14 15:13:31 +0000236}
237
bart99edb292009-02-15 15:59:20 +0000238VG_REGPARM(2) void DRD_(trace_store)(Addr addr, SizeT size)
bart09dc13f2009-02-14 15:13:31 +0000239{
240#ifdef ENABLE_DRD_CONSISTENCY_CHECKS
bartbedfd232009-03-26 19:07:15 +0000241 /* The assert below has been commented out because of performance reasons.*/
bartd5bbc612010-09-02 14:44:17 +0000242 tl_assert(DRD_(thread_get_running_tid)()
243 == DRD_(VgThreadIdToDrdThreadId)(VG_(get_running_tid())));
bart09dc13f2009-02-14 15:13:31 +0000244#endif
245
bartd45d9952009-05-31 18:53:54 +0000246 if (DRD_(running_thread_is_recording_stores)()
bartf98a5692009-05-03 17:17:37 +0000247 && (s_check_stack_accesses
bartbedfd232009-03-26 19:07:15 +0000248 || ! DRD_(thread_address_on_stack)(addr))
249 && bm_access_store_triggers_conflict(addr, addr + size)
250 && ! DRD_(is_suppressed)(addr, addr + size))
251 {
252 drd_report_race(addr, size, eStore);
253 }
bart09dc13f2009-02-14 15:13:31 +0000254}
255
256static VG_REGPARM(1) void drd_trace_store_1(Addr addr)
257{
bartd45d9952009-05-31 18:53:54 +0000258 if (DRD_(running_thread_is_recording_stores)()
bartf98a5692009-05-03 17:17:37 +0000259 && (s_check_stack_accesses
bartbedfd232009-03-26 19:07:15 +0000260 || ! DRD_(thread_address_on_stack)(addr))
261 && bm_access_store_1_triggers_conflict(addr)
262 && ! DRD_(is_suppressed)(addr, addr + 1))
263 {
264 drd_report_race(addr, 1, eStore);
265 }
bart09dc13f2009-02-14 15:13:31 +0000266}
267
268static VG_REGPARM(1) void drd_trace_store_2(Addr addr)
269{
bartd45d9952009-05-31 18:53:54 +0000270 if (DRD_(running_thread_is_recording_stores)()
bartf98a5692009-05-03 17:17:37 +0000271 && (s_check_stack_accesses
bartbedfd232009-03-26 19:07:15 +0000272 || ! DRD_(thread_address_on_stack)(addr))
273 && bm_access_store_2_triggers_conflict(addr)
274 && ! DRD_(is_suppressed)(addr, addr + 2))
275 {
276 drd_report_race(addr, 2, eStore);
277 }
bart09dc13f2009-02-14 15:13:31 +0000278}
279
280static VG_REGPARM(1) void drd_trace_store_4(Addr addr)
281{
bartd45d9952009-05-31 18:53:54 +0000282 if (DRD_(running_thread_is_recording_stores)()
bartf98a5692009-05-03 17:17:37 +0000283 && (s_check_stack_accesses
bart71ce1322011-12-11 17:54:17 +0000284 || !DRD_(thread_address_on_stack)(addr))
bartbedfd232009-03-26 19:07:15 +0000285 && bm_access_store_4_triggers_conflict(addr)
bart71ce1322011-12-11 17:54:17 +0000286 && !DRD_(is_suppressed)(addr, addr + 4))
bartbedfd232009-03-26 19:07:15 +0000287 {
288 drd_report_race(addr, 4, eStore);
289 }
bart09dc13f2009-02-14 15:13:31 +0000290}
291
292static VG_REGPARM(1) void drd_trace_store_8(Addr addr)
293{
bartd45d9952009-05-31 18:53:54 +0000294 if (DRD_(running_thread_is_recording_stores)()
bartf98a5692009-05-03 17:17:37 +0000295 && (s_check_stack_accesses
bartbedfd232009-03-26 19:07:15 +0000296 || ! DRD_(thread_address_on_stack)(addr))
297 && bm_access_store_8_triggers_conflict(addr)
298 && ! DRD_(is_suppressed)(addr, addr + 8))
299 {
300 drd_report_race(addr, 8, eStore);
301 }
bart09dc13f2009-02-14 15:13:31 +0000302}
303
304/**
305 * Return true if and only if addr_expr matches the pattern (SP) or
306 * <offset>(SP).
307 */
308static Bool is_stack_access(IRSB* const bb, IRExpr* const addr_expr)
309{
bartbedfd232009-03-26 19:07:15 +0000310 Bool result = False;
bart09dc13f2009-02-14 15:13:31 +0000311
bartbedfd232009-03-26 19:07:15 +0000312 if (addr_expr->tag == Iex_RdTmp)
313 {
314 int i;
315 for (i = 0; i < bb->stmts_size; i++)
bart09dc13f2009-02-14 15:13:31 +0000316 {
bartbedfd232009-03-26 19:07:15 +0000317 if (bb->stmts[i]
318 && bb->stmts[i]->tag == Ist_WrTmp
319 && bb->stmts[i]->Ist.WrTmp.tmp == addr_expr->Iex.RdTmp.tmp)
320 {
321 IRExpr* e = bb->stmts[i]->Ist.WrTmp.data;
322 if (e->tag == Iex_Get && e->Iex.Get.offset == STACK_POINTER_OFFSET)
323 {
324 result = True;
325 }
bart09dc13f2009-02-14 15:13:31 +0000326
bartbedfd232009-03-26 19:07:15 +0000327 //ppIRExpr(e);
328 //VG_(printf)(" (%s)\n", result ? "True" : "False");
329 break;
330 }
bart09dc13f2009-02-14 15:13:31 +0000331 }
bartbedfd232009-03-26 19:07:15 +0000332 }
333 return result;
bart09dc13f2009-02-14 15:13:31 +0000334}
335
bartea692152011-12-11 20:17:57 +0000336static const IROp u_widen_irop[5][9] = {
bart9ad8d802011-12-12 19:54:32 +0000337 [Ity_I1 - Ity_I1] = { [4] = Iop_1Uto32, [8] = Iop_1Uto64 },
338 [Ity_I8 - Ity_I1] = { [4] = Iop_8Uto32, [8] = Iop_8Uto64 },
339 [Ity_I16 - Ity_I1] = { [4] = Iop_16Uto32, [8] = Iop_16Uto64 },
340 [Ity_I32 - Ity_I1] = { [8] = Iop_32Uto64 },
bartea692152011-12-11 20:17:57 +0000341};
342
bartb63dc782011-12-12 19:18:26 +0000343/**
344 * Instrument the client code to trace a memory load (--trace-addr).
345 */
bart25026ef2011-12-17 12:59:45 +0000346static IRExpr* instr_trace_mem_load(IRSB* const bb, IRExpr* addr_expr,
347 const HWord size)
bartea692152011-12-11 20:17:57 +0000348{
bart25026ef2011-12-17 12:59:45 +0000349 IRTemp tmp;
350
351 tmp = newIRTemp(bb->tyenv, typeOfIRExpr(bb->tyenv, addr_expr));
352 addStmtToIRSB(bb, IRStmt_WrTmp(tmp, addr_expr));
353 addr_expr = IRExpr_RdTmp(tmp);
354
bartb63dc782011-12-12 19:18:26 +0000355 addStmtToIRSB(bb,
356 IRStmt_Dirty(
357 unsafeIRDirty_0_N(/*regparms*/2,
358 "drd_trace_mem_load",
359 VG_(fnptr_to_fnentry)
360 (drd_trace_mem_load),
361 mkIRExprVec_2(addr_expr, mkIRExpr_HWord(size)))));
bart25026ef2011-12-17 12:59:45 +0000362
363 return addr_expr;
bartb63dc782011-12-12 19:18:26 +0000364}
365
366/**
367 * Instrument the client code to trace a memory store (--trace-addr).
368 */
369static void instr_trace_mem_store(IRSB* const bb, IRExpr* const addr_expr,
bart42f32632011-12-13 11:12:05 +0000370 IRExpr* data_expr_hi, IRExpr* data_expr_lo)
bartb63dc782011-12-12 19:18:26 +0000371{
372 IRType ty_data_expr;
bartea692152011-12-11 20:17:57 +0000373 HWord size;
374
bartb63dc782011-12-12 19:18:26 +0000375 tl_assert(sizeof(HWord) == 4 || sizeof(HWord) == 8);
bart42f32632011-12-13 11:12:05 +0000376 tl_assert(!data_expr_hi || typeOfIRExpr(bb->tyenv, data_expr_hi) == Ity_I32);
bartea692152011-12-11 20:17:57 +0000377
bart42f32632011-12-13 11:12:05 +0000378 ty_data_expr = typeOfIRExpr(bb->tyenv, data_expr_lo);
bartb63dc782011-12-12 19:18:26 +0000379 size = sizeofIRType(ty_data_expr);
380
bart7ca75ed2011-12-13 08:53:23 +0000381#if 0
382 // Test code
383 if (ty_data_expr == Ity_I32) {
384 IRTemp tmp = newIRTemp(bb->tyenv, Ity_F32);
bart42f32632011-12-13 11:12:05 +0000385 data_expr_lo = IRExpr_Unop(Iop_ReinterpI32asF32, data_expr_lo);
386 addStmtToIRSB(bb, IRStmt_WrTmp(tmp, data_expr_lo));
387 data_expr_lo = IRExpr_RdTmp(tmp);
bart7ca75ed2011-12-13 08:53:23 +0000388 ty_data_expr = Ity_F32;
389 } else if (ty_data_expr == Ity_I64) {
390 IRTemp tmp = newIRTemp(bb->tyenv, Ity_F64);
bart42f32632011-12-13 11:12:05 +0000391 data_expr_lo = IRExpr_Unop(Iop_ReinterpI64asF64, data_expr_lo);
392 addStmtToIRSB(bb, IRStmt_WrTmp(tmp, data_expr_lo));
393 data_expr_lo = IRExpr_RdTmp(tmp);
bart7ca75ed2011-12-13 08:53:23 +0000394 ty_data_expr = Ity_F64;
395 }
396#endif
397
398 if (ty_data_expr == Ity_F32) {
399 IRTemp tmp = newIRTemp(bb->tyenv, Ity_I32);
400 addStmtToIRSB(bb, IRStmt_WrTmp(tmp, IRExpr_Unop(Iop_ReinterpF32asI32,
bart42f32632011-12-13 11:12:05 +0000401 data_expr_lo)));
402 data_expr_lo = IRExpr_RdTmp(tmp);
bart7ca75ed2011-12-13 08:53:23 +0000403 ty_data_expr = Ity_I32;
404 } else if (ty_data_expr == Ity_F64) {
405 IRTemp tmp = newIRTemp(bb->tyenv, Ity_I64);
406 addStmtToIRSB(bb, IRStmt_WrTmp(tmp, IRExpr_Unop(Iop_ReinterpF64asI64,
bart42f32632011-12-13 11:12:05 +0000407 data_expr_lo)));
408 data_expr_lo = IRExpr_RdTmp(tmp);
bart7ca75ed2011-12-13 08:53:23 +0000409 ty_data_expr = Ity_I64;
410 }
411
bartb63dc782011-12-12 19:18:26 +0000412 if (size == sizeof(HWord)
413 && (ty_data_expr == Ity_I32 || ty_data_expr == Ity_I64))
414 {
415 /* No conversion necessary */
bartea692152011-12-11 20:17:57 +0000416 } else {
417 IROp widen_op;
418
bartb63dc782011-12-12 19:18:26 +0000419 if (Ity_I1 <= ty_data_expr
420 && ty_data_expr
421 < Ity_I1 + sizeof(u_widen_irop)/sizeof(u_widen_irop[0]))
422 {
423 widen_op = u_widen_irop[ty_data_expr - Ity_I1][sizeof(HWord)];
bartea692152011-12-11 20:17:57 +0000424 if (!widen_op)
425 widen_op = Iop_INVALID;
426 } else {
427 widen_op = Iop_INVALID;
428 }
429 if (widen_op != Iop_INVALID) {
430 IRTemp tmp;
431
bartb63dc782011-12-12 19:18:26 +0000432 /* Widen the integer expression to a HWord */
bartea692152011-12-11 20:17:57 +0000433 tmp = newIRTemp(bb->tyenv, sizeof(HWord) == 4 ? Ity_I32 : Ity_I64);
434 addStmtToIRSB(bb,
bart42f32632011-12-13 11:12:05 +0000435 IRStmt_WrTmp(tmp, IRExpr_Unop(widen_op, data_expr_lo)));
436 data_expr_lo = IRExpr_RdTmp(tmp);
437 } else if (size > sizeof(HWord) && !data_expr_hi
438 && ty_data_expr == Ity_I64) {
439 IRTemp tmp;
440
441 tl_assert(sizeof(HWord) == 4);
442 tl_assert(size == 8);
443 tmp = newIRTemp(bb->tyenv, Ity_I32);
444 addStmtToIRSB(bb,
445 IRStmt_WrTmp(tmp,
446 IRExpr_Unop(Iop_64HIto32, data_expr_lo)));
447 data_expr_hi = IRExpr_RdTmp(tmp);
448 tmp = newIRTemp(bb->tyenv, Ity_I32);
449 addStmtToIRSB(bb, IRStmt_WrTmp(tmp,
450 IRExpr_Unop(Iop_64to32, data_expr_lo)));
451 data_expr_lo = IRExpr_RdTmp(tmp);
bartea692152011-12-11 20:17:57 +0000452 } else {
bart42f32632011-12-13 11:12:05 +0000453 data_expr_lo = mkIRExpr_HWord(0);
bartea692152011-12-11 20:17:57 +0000454 }
455 }
456 addStmtToIRSB(bb,
457 IRStmt_Dirty(
458 unsafeIRDirty_0_N(/*regparms*/3,
459 "drd_trace_mem_store",
bart42f32632011-12-13 11:12:05 +0000460 VG_(fnptr_to_fnentry)(drd_trace_mem_store),
461 mkIRExprVec_4(addr_expr, mkIRExpr_HWord(size),
462 data_expr_hi ? data_expr_hi
463 : mkIRExpr_HWord(0), data_expr_lo))));
bartea692152011-12-11 20:17:57 +0000464}
465
466static void instrument_load(IRSB* const bb, IRExpr* const addr_expr,
bartb63dc782011-12-12 19:18:26 +0000467 const HWord size)
bart09dc13f2009-02-14 15:13:31 +0000468{
bartbedfd232009-03-26 19:07:15 +0000469 IRExpr* size_expr;
470 IRExpr** argv;
471 IRDirty* di;
bart09dc13f2009-02-14 15:13:31 +0000472
bartea692152011-12-11 20:17:57 +0000473 if (!s_check_stack_accesses && is_stack_access(bb, addr_expr))
bartbedfd232009-03-26 19:07:15 +0000474 return;
bart09dc13f2009-02-14 15:13:31 +0000475
bartbedfd232009-03-26 19:07:15 +0000476 switch (size)
477 {
478 case 1:
479 argv = mkIRExprVec_1(addr_expr);
480 di = unsafeIRDirty_0_N(/*regparms*/1,
481 "drd_trace_load_1",
482 VG_(fnptr_to_fnentry)(drd_trace_load_1),
483 argv);
484 break;
485 case 2:
486 argv = mkIRExprVec_1(addr_expr);
487 di = unsafeIRDirty_0_N(/*regparms*/1,
488 "drd_trace_load_2",
489 VG_(fnptr_to_fnentry)(drd_trace_load_2),
490 argv);
491 break;
492 case 4:
493 argv = mkIRExprVec_1(addr_expr);
494 di = unsafeIRDirty_0_N(/*regparms*/1,
495 "drd_trace_load_4",
496 VG_(fnptr_to_fnentry)(drd_trace_load_4),
497 argv);
498 break;
499 case 8:
500 argv = mkIRExprVec_1(addr_expr);
501 di = unsafeIRDirty_0_N(/*regparms*/1,
502 "drd_trace_load_8",
503 VG_(fnptr_to_fnentry)(drd_trace_load_8),
504 argv);
505 break;
506 default:
507 size_expr = mkIRExpr_HWord(size);
508 argv = mkIRExprVec_2(addr_expr, size_expr);
509 di = unsafeIRDirty_0_N(/*regparms*/2,
510 "drd_trace_load",
511 VG_(fnptr_to_fnentry)(DRD_(trace_load)),
512 argv);
513 break;
514 }
515 addStmtToIRSB(bb, IRStmt_Dirty(di));
bart09dc13f2009-02-14 15:13:31 +0000516}
517
bart25026ef2011-12-17 12:59:45 +0000518static void instrument_store(IRSB* const bb, IRExpr* addr_expr,
bart7826acb2011-12-11 18:49:39 +0000519 IRExpr* const data_expr)
bart09dc13f2009-02-14 15:13:31 +0000520{
bartbedfd232009-03-26 19:07:15 +0000521 IRExpr* size_expr;
522 IRExpr** argv;
523 IRDirty* di;
bart7826acb2011-12-11 18:49:39 +0000524 HWord size;
525
526 size = sizeofIRType(typeOfIRExpr(bb->tyenv, data_expr));
bart09dc13f2009-02-14 15:13:31 +0000527
bart25026ef2011-12-17 12:59:45 +0000528 if (UNLIKELY(DRD_(any_address_is_traced)())) {
529 IRTemp tmp = newIRTemp(bb->tyenv, typeOfIRExpr(bb->tyenv, addr_expr));
530 addStmtToIRSB(bb, IRStmt_WrTmp(tmp, addr_expr));
531 addr_expr = IRExpr_RdTmp(tmp);
bart42f32632011-12-13 11:12:05 +0000532 instr_trace_mem_store(bb, addr_expr, NULL, data_expr);
bart25026ef2011-12-17 12:59:45 +0000533 }
bart09dc13f2009-02-14 15:13:31 +0000534
bart71ce1322011-12-11 17:54:17 +0000535 if (!s_check_stack_accesses && is_stack_access(bb, addr_expr))
bartbedfd232009-03-26 19:07:15 +0000536 return;
bart09dc13f2009-02-14 15:13:31 +0000537
bartbedfd232009-03-26 19:07:15 +0000538 switch (size)
539 {
540 case 1:
541 argv = mkIRExprVec_1(addr_expr);
542 di = unsafeIRDirty_0_N(/*regparms*/1,
543 "drd_trace_store_1",
544 VG_(fnptr_to_fnentry)(drd_trace_store_1),
545 argv);
546 break;
547 case 2:
548 argv = mkIRExprVec_1(addr_expr);
549 di = unsafeIRDirty_0_N(/*regparms*/1,
550 "drd_trace_store_2",
551 VG_(fnptr_to_fnentry)(drd_trace_store_2),
552 argv);
553 break;
554 case 4:
555 argv = mkIRExprVec_1(addr_expr);
556 di = unsafeIRDirty_0_N(/*regparms*/1,
557 "drd_trace_store_4",
558 VG_(fnptr_to_fnentry)(drd_trace_store_4),
559 argv);
560 break;
561 case 8:
562 argv = mkIRExprVec_1(addr_expr);
563 di = unsafeIRDirty_0_N(/*regparms*/1,
564 "drd_trace_store_8",
565 VG_(fnptr_to_fnentry)(drd_trace_store_8),
566 argv);
567 break;
568 default:
569 size_expr = mkIRExpr_HWord(size);
570 argv = mkIRExprVec_2(addr_expr, size_expr);
571 di = unsafeIRDirty_0_N(/*regparms*/2,
572 "drd_trace_store",
573 VG_(fnptr_to_fnentry)(DRD_(trace_store)),
574 argv);
575 break;
576 }
577 addStmtToIRSB(bb, IRStmt_Dirty(di));
bart09dc13f2009-02-14 15:13:31 +0000578}
579
bart1335ecc2009-02-14 16:10:53 +0000580IRSB* DRD_(instrument)(VgCallbackClosure* const closure,
bartbedfd232009-03-26 19:07:15 +0000581 IRSB* const bb_in,
582 VexGuestLayout* const layout,
bart31b983d2010-02-21 14:52:59 +0000583 VexGuestExtents* const vge,
bartbedfd232009-03-26 19:07:15 +0000584 IRType const gWordTy,
585 IRType const hWordTy)
bart09dc13f2009-02-14 15:13:31 +0000586{
bartbedfd232009-03-26 19:07:15 +0000587 IRDirty* di;
588 Int i;
589 IRSB* bb;
590 IRExpr** argv;
591 Bool instrument = True;
bart09dc13f2009-02-14 15:13:31 +0000592
bartbedfd232009-03-26 19:07:15 +0000593 /* Set up BB */
594 bb = emptyIRSB();
595 bb->tyenv = deepCopyIRTypeEnv(bb_in->tyenv);
596 bb->next = deepCopyIRExpr(bb_in->next);
597 bb->jumpkind = bb_in->jumpkind;
sewardj291849f2012-04-20 23:58:55 +0000598 bb->offsIP = bb_in->offsIP;
bart09dc13f2009-02-14 15:13:31 +0000599
bartbedfd232009-03-26 19:07:15 +0000600 for (i = 0; i < bb_in->stmts_used; i++)
601 {
602 IRStmt* const st = bb_in->stmts[i];
603 tl_assert(st);
sewardjdb5907d2009-11-26 17:20:21 +0000604 tl_assert(isFlatIRStmt(st));
bart09dc13f2009-02-14 15:13:31 +0000605
bartbedfd232009-03-26 19:07:15 +0000606 switch (st->tag)
bart09dc13f2009-02-14 15:13:31 +0000607 {
bartbedfd232009-03-26 19:07:15 +0000608 /* Note: the code for not instrumenting the code in .plt */
609 /* sections is only necessary on CentOS 3.0 x86 (kernel 2.4.21 */
610 /* + glibc 2.3.2 + NPTL 0.60 + binutils 2.14.90.0.4). */
611 /* This is because on this platform dynamic library symbols are */
612 /* relocated in another way than by later binutils versions. The */
613 /* linker e.g. does not generate .got.plt sections on CentOS 3.0. */
614 case Ist_IMark:
sewardje3f1e592009-07-31 09:41:29 +0000615 instrument = VG_(DebugInfo_sect_kind)(NULL, 0, st->Ist.IMark.addr)
bartbedfd232009-03-26 19:07:15 +0000616 != Vg_SectPLT;
617 addStmtToIRSB(bb, st);
618 break;
619
620 case Ist_MBE:
621 switch (st->Ist.MBE.event)
622 {
623 case Imbe_Fence:
624 break; /* not interesting */
bartbedfd232009-03-26 19:07:15 +0000625 default:
626 tl_assert(0);
627 }
628 addStmtToIRSB(bb, st);
629 break;
630
631 case Ist_Store:
sewardjdb5907d2009-11-26 17:20:21 +0000632 if (instrument)
bart7826acb2011-12-11 18:49:39 +0000633 instrument_store(bb, st->Ist.Store.addr, st->Ist.Store.data);
bartbedfd232009-03-26 19:07:15 +0000634 addStmtToIRSB(bb, st);
635 break;
636
637 case Ist_WrTmp:
bartea692152011-12-11 20:17:57 +0000638 if (instrument) {
bartbedfd232009-03-26 19:07:15 +0000639 const IRExpr* const data = st->Ist.WrTmp.data;
bart25026ef2011-12-17 12:59:45 +0000640 IRExpr* addr_expr = data->Iex.Load.addr;
bartb63dc782011-12-12 19:18:26 +0000641 if (data->tag == Iex_Load) {
bart25026ef2011-12-17 12:59:45 +0000642 if (UNLIKELY(DRD_(any_address_is_traced)())) {
643 addr_expr = instr_trace_mem_load(bb, addr_expr,
bartb63dc782011-12-12 19:18:26 +0000644 sizeofIRType(data->Iex.Load.ty));
bart25026ef2011-12-17 12:59:45 +0000645 }
bartea692152011-12-11 20:17:57 +0000646 instrument_load(bb, data->Iex.Load.addr,
bartb63dc782011-12-12 19:18:26 +0000647 sizeofIRType(data->Iex.Load.ty));
648 }
bartbedfd232009-03-26 19:07:15 +0000649 }
650 addStmtToIRSB(bb, st);
651 break;
652
653 case Ist_Dirty:
bartb63dc782011-12-12 19:18:26 +0000654 if (instrument) {
bartbedfd232009-03-26 19:07:15 +0000655 IRDirty* d = st->Ist.Dirty.details;
656 IREffect const mFx = d->mFx;
657 switch (mFx) {
658 case Ifx_None:
659 break;
660 case Ifx_Read:
661 case Ifx_Write:
662 case Ifx_Modify:
663 tl_assert(d->mAddr);
664 tl_assert(d->mSize > 0);
665 argv = mkIRExprVec_2(d->mAddr, mkIRExpr_HWord(d->mSize));
666 if (mFx == Ifx_Read || mFx == Ifx_Modify) {
667 di = unsafeIRDirty_0_N(
668 /*regparms*/2,
669 "drd_trace_load",
670 VG_(fnptr_to_fnentry)(DRD_(trace_load)),
671 argv);
672 addStmtToIRSB(bb, IRStmt_Dirty(di));
673 }
sewardj1c0ce7a2009-07-01 08:10:49 +0000674 if (mFx == Ifx_Write || mFx == Ifx_Modify)
bartbedfd232009-03-26 19:07:15 +0000675 {
676 di = unsafeIRDirty_0_N(
677 /*regparms*/2,
678 "drd_trace_store",
679 VG_(fnptr_to_fnentry)(DRD_(trace_store)),
680 argv);
681 addStmtToIRSB(bb, IRStmt_Dirty(di));
682 }
683 break;
684 default:
685 tl_assert(0);
686 }
687 }
688 addStmtToIRSB(bb, st);
689 break;
690
sewardj1c0ce7a2009-07-01 08:10:49 +0000691 case Ist_CAS:
bartb63dc782011-12-12 19:18:26 +0000692 if (instrument) {
barta14e3282009-07-11 14:35:59 +0000693 /*
694 * Treat compare-and-swap as a read. By handling atomic
695 * instructions as read instructions no data races are reported
696 * between conflicting atomic operations nor between atomic
697 * operations and non-atomic reads. Conflicts between atomic
698 * operations and non-atomic write operations are still reported
699 * however.
700 */
sewardj1c0ce7a2009-07-01 08:10:49 +0000701 Int dataSize;
702 IRCAS* cas = st->Ist.CAS.details;
bartb63dc782011-12-12 19:18:26 +0000703
sewardj1c0ce7a2009-07-01 08:10:49 +0000704 tl_assert(cas->addr != NULL);
705 tl_assert(cas->dataLo != NULL);
706 dataSize = sizeofIRType(typeOfIRExpr(bb->tyenv, cas->dataLo));
707 if (cas->dataHi != NULL)
708 dataSize *= 2; /* since it's a doubleword-CAS */
bartb63dc782011-12-12 19:18:26 +0000709
bart42f32632011-12-13 11:12:05 +0000710 if (UNLIKELY(DRD_(any_address_is_traced)()))
711 instr_trace_mem_store(bb, cas->addr, cas->dataHi, cas->dataLo);
bartb63dc782011-12-12 19:18:26 +0000712
713 instrument_load(bb, cas->addr, dataSize);
sewardj1c0ce7a2009-07-01 08:10:49 +0000714 }
715 addStmtToIRSB(bb, st);
716 break;
717
sewardjdb5907d2009-11-26 17:20:21 +0000718 case Ist_LLSC: {
bartea692152011-12-11 20:17:57 +0000719 /*
720 * Ignore store-conditionals (except for tracing), and handle
721 * load-linked's exactly like normal loads.
722 */
sewardjdb5907d2009-11-26 17:20:21 +0000723 IRType dataTy;
bartb63dc782011-12-12 19:18:26 +0000724
bartea692152011-12-11 20:17:57 +0000725 if (st->Ist.LLSC.storedata == NULL) {
sewardjdb5907d2009-11-26 17:20:21 +0000726 /* LL */
727 dataTy = typeOfIRTemp(bb_in->tyenv, st->Ist.LLSC.result);
bartb63dc782011-12-12 19:18:26 +0000728 if (instrument) {
bart25026ef2011-12-17 12:59:45 +0000729 IRExpr* addr_expr = st->Ist.LLSC.addr;
bartb63dc782011-12-12 19:18:26 +0000730 if (UNLIKELY(DRD_(any_address_is_traced)()))
bart25026ef2011-12-17 12:59:45 +0000731 addr_expr = instr_trace_mem_load(bb, addr_expr,
732 sizeofIRType(dataTy));
bartb63dc782011-12-12 19:18:26 +0000733
bart25026ef2011-12-17 12:59:45 +0000734 instrument_load(bb, addr_expr, sizeofIRType(dataTy));
bartb63dc782011-12-12 19:18:26 +0000735 }
bartea692152011-12-11 20:17:57 +0000736 } else {
sewardjdb5907d2009-11-26 17:20:21 +0000737 /* SC */
bart42f32632011-12-13 11:12:05 +0000738 instr_trace_mem_store(bb, st->Ist.LLSC.addr, NULL,
bartb63dc782011-12-12 19:18:26 +0000739 st->Ist.LLSC.storedata);
sewardjdb5907d2009-11-26 17:20:21 +0000740 }
bartbedfd232009-03-26 19:07:15 +0000741 addStmtToIRSB(bb, st);
742 break;
bart09dc13f2009-02-14 15:13:31 +0000743 }
sewardjdb5907d2009-11-26 17:20:21 +0000744
745 case Ist_NoOp:
746 case Ist_AbiHint:
747 case Ist_Put:
748 case Ist_PutI:
749 case Ist_Exit:
750 /* None of these can contain any memory references. */
751 addStmtToIRSB(bb, st);
752 break;
753
754 default:
755 ppIRStmt(st);
756 tl_assert(0);
757 }
bartbedfd232009-03-26 19:07:15 +0000758 }
bart09dc13f2009-02-14 15:13:31 +0000759
bartbedfd232009-03-26 19:07:15 +0000760 return bb;
bart09dc13f2009-02-14 15:13:31 +0000761}
762