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