drd_load_store.c revision 1335ecca5095dea85be94095885082b80573df8c
1/* 2 This file is part of drd, a data race detector. 3 4 Copyright (C) 2006-2009 Bart Van Assche <bart.vanassche@gmail.com>. 5 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" 27 28/* Include several source files here in order to allow the compiler to */ 29/* do more inlining. */ 30#include "drd_bitmap.c" 31#include "drd_load_store.h" 32#include "drd_segment.c" 33#include "drd_thread.c" 34#include "drd_vc.c" 35#include "libvex_guest_offsets.h" 36 37 38/* STACK_POINTER_OFFSET: VEX register offset for the stack pointer register. */ 39#if defined(VGA_x86) 40#define STACK_POINTER_OFFSET OFFSET_x86_ESP 41#elif defined(VGA_amd64) 42#define STACK_POINTER_OFFSET OFFSET_amd64_RSP 43#elif defined(VGA_ppc32) 44#define STACK_POINTER_OFFSET ((OFFSET_ppc32_GPR0 + OFFSET_ppc32_GPR2) / 2) 45#elif defined(VGA_ppc64) 46#define STACK_POINTER_OFFSET ((OFFSET_ppc64_GPR0 + OFFSET_ppc64_GPR2) / 2) 47#else 48#error Unknown architecture. 49#endif 50 51 52/* Local variables. */ 53 54static Bool s_drd_check_stack_accesses = False; 55 56 57/* Function definitions. */ 58 59Bool DRD_(get_check_stack_accesses)() 60{ 61 return s_drd_check_stack_accesses; 62} 63 64void DRD_(set_check_stack_accesses)(const Bool c) 65{ 66 tl_assert(c == False || c == True); 67 s_drd_check_stack_accesses = c; 68} 69 70void DRD_(trace_mem_access)(const Addr addr, const SizeT size, 71 const BmAccessTypeT access_type) 72{ 73 if (DRD_(is_any_traced)(addr, addr + size)) 74 { 75 char vc[80]; 76 vc_snprint(vc, sizeof(vc), thread_get_vc(thread_get_running_tid())); 77 VG_(message)(Vg_UserMsg, 78 "%s 0x%lx size %ld (vg %d / drd %d / vc %s)", 79 access_type == eLoad 80 ? "load " 81 : access_type == eStore 82 ? "store" 83 : access_type == eStart 84 ? "start" 85 : access_type == eEnd 86 ? "end " 87 : "????", 88 addr, 89 size, 90 VG_(get_running_tid)(), 91 thread_get_running_tid(), 92 vc); 93 VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), 94 VG_(clo_backtrace_size)); 95 tl_assert(DrdThreadIdToVgThreadId(thread_get_running_tid()) 96 == VG_(get_running_tid)()); 97 } 98} 99 100static VG_REGPARM(2) void drd_trace_mem_load(const Addr addr, const SizeT size) 101{ 102 return DRD_(trace_mem_access)(addr, size, eLoad); 103} 104 105static VG_REGPARM(2) void drd_trace_mem_store(const Addr addr,const SizeT size) 106{ 107 return DRD_(trace_mem_access)(addr, size, eStore); 108} 109 110static void drd_report_race(const Addr addr, const SizeT size, 111 const BmAccessTypeT access_type) 112{ 113 DataRaceErrInfo drei; 114 115 drei.tid = thread_get_running_tid(); 116 drei.addr = addr; 117 drei.size = size; 118 drei.access_type = access_type; 119 VG_(maybe_record_error)(VG_(get_running_tid)(), 120 DataRaceErr, 121 VG_(get_IP)(VG_(get_running_tid)()), 122 "Conflicting accesses", 123 &drei); 124} 125 126VG_REGPARM(2) void drd_trace_load(Addr addr, SizeT size) 127{ 128#ifdef ENABLE_DRD_CONSISTENCY_CHECKS 129 /* The assert below has been commented out because of performance reasons.*/ 130 tl_assert(thread_get_running_tid() 131 == VgThreadIdToDrdThreadId(VG_(get_running_tid()))); 132#endif 133 134 if (running_thread_is_recording() 135 && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr)) 136 && bm_access_load_triggers_conflict(addr, addr + size) 137 && ! DRD_(is_suppressed)(addr, addr + size)) 138 { 139 drd_report_race(addr, size, eLoad); 140 } 141} 142 143static VG_REGPARM(1) void drd_trace_load_1(Addr addr) 144{ 145 if (running_thread_is_recording() 146 && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr)) 147 && bm_access_load_1_triggers_conflict(addr) 148 && ! DRD_(is_suppressed)(addr, addr + 1)) 149 { 150 drd_report_race(addr, 1, eLoad); 151 } 152} 153 154static VG_REGPARM(1) void drd_trace_load_2(Addr addr) 155{ 156 if (running_thread_is_recording() 157 && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr)) 158 && bm_access_load_2_triggers_conflict(addr) 159 && ! DRD_(is_suppressed)(addr, addr + 2)) 160 { 161 drd_report_race(addr, 2, eLoad); 162 } 163} 164 165static VG_REGPARM(1) void drd_trace_load_4(Addr addr) 166{ 167 if (running_thread_is_recording() 168 && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr)) 169 && bm_access_load_4_triggers_conflict(addr) 170 && ! DRD_(is_suppressed)(addr, addr + 4)) 171 { 172 drd_report_race(addr, 4, eLoad); 173 } 174} 175 176static VG_REGPARM(1) void drd_trace_load_8(Addr addr) 177{ 178 if (running_thread_is_recording() 179 && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr)) 180 && bm_access_load_8_triggers_conflict(addr) 181 && ! DRD_(is_suppressed)(addr, addr + 8)) 182 { 183 drd_report_race(addr, 8, eLoad); 184 } 185} 186 187VG_REGPARM(2) void drd_trace_store(Addr addr, SizeT size) 188{ 189#ifdef ENABLE_DRD_CONSISTENCY_CHECKS 190 /* The assert below has been commented out because of performance reasons.*/ 191 tl_assert(thread_get_running_tid() 192 == VgThreadIdToDrdThreadId(VG_(get_running_tid()))); 193#endif 194 195 if (running_thread_is_recording() 196 && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr)) 197 && bm_access_store_triggers_conflict(addr, addr + size) 198 && ! DRD_(is_suppressed)(addr, addr + size)) 199 { 200 drd_report_race(addr, size, eStore); 201 } 202} 203 204static VG_REGPARM(1) void drd_trace_store_1(Addr addr) 205{ 206 if (running_thread_is_recording() 207 && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr)) 208 && bm_access_store_1_triggers_conflict(addr) 209 && ! DRD_(is_suppressed)(addr, addr + 1)) 210 { 211 drd_report_race(addr, 1, eStore); 212 } 213} 214 215static VG_REGPARM(1) void drd_trace_store_2(Addr addr) 216{ 217 if (running_thread_is_recording() 218 && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr)) 219 && bm_access_store_2_triggers_conflict(addr) 220 && ! DRD_(is_suppressed)(addr, addr + 2)) 221 { 222 drd_report_race(addr, 2, eStore); 223 } 224} 225 226static VG_REGPARM(1) void drd_trace_store_4(Addr addr) 227{ 228 if (running_thread_is_recording() 229 && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr)) 230 && bm_access_store_4_triggers_conflict(addr) 231 && ! DRD_(is_suppressed)(addr, addr + 4)) 232 { 233 drd_report_race(addr, 4, eStore); 234 } 235} 236 237static VG_REGPARM(1) void drd_trace_store_8(Addr addr) 238{ 239 if (running_thread_is_recording() 240 && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr)) 241 && bm_access_store_8_triggers_conflict(addr) 242 && ! DRD_(is_suppressed)(addr, addr + 8)) 243 { 244 drd_report_race(addr, 8, eStore); 245 } 246} 247 248/** 249 * Return true if and only if addr_expr matches the pattern (SP) or 250 * <offset>(SP). 251 */ 252static Bool is_stack_access(IRSB* const bb, IRExpr* const addr_expr) 253{ 254 Bool result = False; 255 256 if (addr_expr->tag == Iex_RdTmp) 257 { 258 int i; 259 for (i = 0; i < bb->stmts_size; i++) 260 { 261 if (bb->stmts[i] 262 && bb->stmts[i]->tag == Ist_WrTmp 263 && bb->stmts[i]->Ist.WrTmp.tmp == addr_expr->Iex.RdTmp.tmp) 264 { 265 IRExpr* e = bb->stmts[i]->Ist.WrTmp.data; 266 if (e->tag == Iex_Get && e->Iex.Get.offset == STACK_POINTER_OFFSET) 267 { 268 result = True; 269 } 270 271 //ppIRExpr(e); 272 //VG_(printf)(" (%s)\n", result ? "True" : "False"); 273 break; 274 } 275 } 276 } 277 return result; 278} 279 280static void instrument_load(IRSB* const bb, 281 IRExpr* const addr_expr, 282 const HWord size) 283{ 284 IRExpr* size_expr; 285 IRExpr** argv; 286 IRDirty* di; 287 288 if (UNLIKELY(DRD_(any_address_is_traced)())) 289 { 290 addStmtToIRSB(bb, 291 IRStmt_Dirty( 292 unsafeIRDirty_0_N(/*regparms*/2, 293 "drd_trace_load", 294 VG_(fnptr_to_fnentry) 295 (drd_trace_mem_load), 296 mkIRExprVec_2(addr_expr, 297 mkIRExpr_HWord(size))))); 298 } 299 300 if (! s_drd_check_stack_accesses && is_stack_access(bb, addr_expr)) 301 return; 302 303 switch (size) 304 { 305 case 1: 306 argv = mkIRExprVec_1(addr_expr); 307 di = unsafeIRDirty_0_N(/*regparms*/1, 308 "drd_trace_load_1", 309 VG_(fnptr_to_fnentry)(drd_trace_load_1), 310 argv); 311 break; 312 case 2: 313 argv = mkIRExprVec_1(addr_expr); 314 di = unsafeIRDirty_0_N(/*regparms*/1, 315 "drd_trace_load_2", 316 VG_(fnptr_to_fnentry)(drd_trace_load_2), 317 argv); 318 break; 319 case 4: 320 argv = mkIRExprVec_1(addr_expr); 321 di = unsafeIRDirty_0_N(/*regparms*/1, 322 "drd_trace_load_4", 323 VG_(fnptr_to_fnentry)(drd_trace_load_4), 324 argv); 325 break; 326 case 8: 327 argv = mkIRExprVec_1(addr_expr); 328 di = unsafeIRDirty_0_N(/*regparms*/1, 329 "drd_trace_load_8", 330 VG_(fnptr_to_fnentry)(drd_trace_load_8), 331 argv); 332 break; 333 default: 334 size_expr = mkIRExpr_HWord(size); 335 argv = mkIRExprVec_2(addr_expr, size_expr); 336 di = unsafeIRDirty_0_N(/*regparms*/2, 337 "drd_trace_load", 338 VG_(fnptr_to_fnentry)(drd_trace_load), 339 argv); 340 break; 341 } 342 addStmtToIRSB(bb, IRStmt_Dirty(di)); 343} 344 345static void instrument_store(IRSB* const bb, 346 IRExpr* const addr_expr, 347 const HWord size) 348{ 349 IRExpr* size_expr; 350 IRExpr** argv; 351 IRDirty* di; 352 353 if (UNLIKELY(DRD_(any_address_is_traced)())) 354 { 355 addStmtToIRSB(bb, 356 IRStmt_Dirty( 357 unsafeIRDirty_0_N(/*regparms*/2, 358 "drd_trace_store", 359 VG_(fnptr_to_fnentry) 360 (drd_trace_mem_store), 361 mkIRExprVec_2(addr_expr, 362 mkIRExpr_HWord(size))))); 363 } 364 365 if (! s_drd_check_stack_accesses && is_stack_access(bb, addr_expr)) 366 return; 367 368 switch (size) 369 { 370 case 1: 371 argv = mkIRExprVec_1(addr_expr); 372 di = unsafeIRDirty_0_N(/*regparms*/1, 373 "drd_trace_store_1", 374 VG_(fnptr_to_fnentry)(drd_trace_store_1), 375 argv); 376 break; 377 case 2: 378 argv = mkIRExprVec_1(addr_expr); 379 di = unsafeIRDirty_0_N(/*regparms*/1, 380 "drd_trace_store_2", 381 VG_(fnptr_to_fnentry)(drd_trace_store_2), 382 argv); 383 break; 384 case 4: 385 argv = mkIRExprVec_1(addr_expr); 386 di = unsafeIRDirty_0_N(/*regparms*/1, 387 "drd_trace_store_4", 388 VG_(fnptr_to_fnentry)(drd_trace_store_4), 389 argv); 390 break; 391 case 8: 392 argv = mkIRExprVec_1(addr_expr); 393 di = unsafeIRDirty_0_N(/*regparms*/1, 394 "drd_trace_store_8", 395 VG_(fnptr_to_fnentry)(drd_trace_store_8), 396 argv); 397 break; 398 default: 399 size_expr = mkIRExpr_HWord(size); 400 argv = mkIRExprVec_2(addr_expr, size_expr); 401 di = unsafeIRDirty_0_N(/*regparms*/2, 402 "drd_trace_store", 403 VG_(fnptr_to_fnentry)(drd_trace_store), 404 argv); 405 break; 406 } 407 addStmtToIRSB(bb, IRStmt_Dirty(di)); 408} 409 410IRSB* DRD_(instrument)(VgCallbackClosure* const closure, 411 IRSB* const bb_in, 412 VexGuestLayout* const layout, 413 VexGuestExtents* const vge, 414 IRType const gWordTy, 415 IRType const hWordTy) 416{ 417 IRDirty* di; 418 Int i; 419 IRSB* bb; 420 IRExpr** argv; 421 Bool instrument = True; 422 Bool bus_locked = False; 423 424 /* Set up BB */ 425 bb = emptyIRSB(); 426 bb->tyenv = deepCopyIRTypeEnv(bb_in->tyenv); 427 bb->next = deepCopyIRExpr(bb_in->next); 428 bb->jumpkind = bb_in->jumpkind; 429 430 for (i = 0; i < bb_in->stmts_used; i++) 431 { 432 IRStmt* const st = bb_in->stmts[i]; 433 tl_assert(st); 434 if (st->tag == Ist_NoOp) 435 continue; 436 437 switch (st->tag) 438 { 439 /* Note: the code for not instrumenting the code in .plt */ 440 /* sections is only necessary on CentOS 3.0 x86 (kernel 2.4.21 */ 441 /* + glibc 2.3.2 + NPTL 0.60 + binutils 2.14.90.0.4). */ 442 /* This is because on this platform dynamic library symbols are */ 443 /* relocated in another way than by later binutils versions. The */ 444 /* linker e.g. does not generate .got.plt sections on CentOS 3.0. */ 445 case Ist_IMark: 446 instrument = VG_(seginfo_sect_kind)(NULL, 0, st->Ist.IMark.addr) 447 != Vg_SectPLT; 448 addStmtToIRSB(bb, st); 449 break; 450 451 case Ist_MBE: 452 switch (st->Ist.MBE.event) 453 { 454 case Imbe_Fence: 455 break; /* not interesting */ 456 case Imbe_BusLock: 457 case Imbe_SnoopedStoreBegin: 458 tl_assert(! bus_locked); 459 bus_locked = True; 460 break; 461 case Imbe_BusUnlock: 462 case Imbe_SnoopedStoreEnd: 463 tl_assert(bus_locked); 464 bus_locked = False; 465 break; 466 default: 467 tl_assert(0); 468 } 469 addStmtToIRSB(bb, st); 470 break; 471 472 case Ist_Store: 473 if (instrument && ! bus_locked) 474 { 475 instrument_store(bb, 476 st->Ist.Store.addr, 477 sizeofIRType(typeOfIRExpr(bb->tyenv, 478 st->Ist.Store.data))); 479 } 480 addStmtToIRSB(bb, st); 481 break; 482 483 case Ist_WrTmp: 484 if (instrument) 485 { 486 const IRExpr* const data = st->Ist.WrTmp.data; 487 if (data->tag == Iex_Load) 488 { 489 instrument_load(bb, 490 data->Iex.Load.addr, 491 sizeofIRType(data->Iex.Load.ty)); 492 } 493 } 494 addStmtToIRSB(bb, st); 495 break; 496 497 case Ist_Dirty: 498 if (instrument) 499 { 500 IRDirty* d = st->Ist.Dirty.details; 501 IREffect const mFx = d->mFx; 502 switch (mFx) { 503 case Ifx_None: 504 break; 505 case Ifx_Read: 506 case Ifx_Write: 507 case Ifx_Modify: 508 tl_assert(d->mAddr); 509 tl_assert(d->mSize > 0); 510 argv = mkIRExprVec_2(d->mAddr, mkIRExpr_HWord(d->mSize)); 511 if (mFx == Ifx_Read || mFx == Ifx_Modify) { 512 di = unsafeIRDirty_0_N( 513 /*regparms*/2, 514 "drd_trace_load", 515 VG_(fnptr_to_fnentry)(drd_trace_load), 516 argv); 517 addStmtToIRSB(bb, IRStmt_Dirty(di)); 518 } 519 if ((mFx == Ifx_Write || mFx == Ifx_Modify) 520 && ! bus_locked) 521 { 522 di = unsafeIRDirty_0_N( 523 /*regparms*/2, 524 "drd_trace_store", 525 VG_(fnptr_to_fnentry)(drd_trace_store), 526 argv); 527 addStmtToIRSB(bb, IRStmt_Dirty(di)); 528 } 529 break; 530 default: 531 tl_assert(0); 532 } 533 } 534 addStmtToIRSB(bb, st); 535 break; 536 537 default: 538 addStmtToIRSB(bb, st); 539 break; 540 } 541 } 542 543 tl_assert(! bus_locked); 544 545 return bb; 546} 547 548