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