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