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 (at) 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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