drd_load_store.c revision 19f91bbaedb4caef8a60ce94b0f507193cc0bc10
1/* 2 This file is part of drd, a thread error detector. 3 4 Copyright (C) 2006-2012 Bart Van Assche <bvanassche@acm.org>. 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_GPR1 46#elif defined(VGA_ppc64) 47#define STACK_POINTER_OFFSET OFFSET_ppc64_GPR1 48#elif defined(VGA_arm) 49#define STACK_POINTER_OFFSET OFFSET_arm_R13 50#elif defined(VGA_s390x) 51#define STACK_POINTER_OFFSET OFFSET_s390x_r15 52#elif defined(VGA_mips32) 53#define STACK_POINTER_OFFSET OFFSET_mips32_r29 54#else 55#error Unknown architecture. 56#endif 57 58 59/* Local variables. */ 60 61static Bool s_check_stack_accesses = False; 62static Bool s_first_race_only = False; 63 64 65/* Function definitions. */ 66 67Bool DRD_(get_check_stack_accesses)() 68{ 69 return s_check_stack_accesses; 70} 71 72void DRD_(set_check_stack_accesses)(const Bool c) 73{ 74 tl_assert(c == False || c == True); 75 s_check_stack_accesses = c; 76} 77 78Bool DRD_(get_first_race_only)() 79{ 80 return s_first_race_only; 81} 82 83void DRD_(set_first_race_only)(const Bool fro) 84{ 85 tl_assert(fro == False || fro == True); 86 s_first_race_only = fro; 87} 88 89void DRD_(trace_mem_access)(const Addr addr, const SizeT size, 90 const BmAccessTypeT access_type, 91 const HWord stored_value_hi, 92 const HWord stored_value_lo) 93{ 94 if (DRD_(is_any_traced)(addr, addr + size)) 95 { 96 HChar* vc; 97 98 vc = DRD_(vc_aprint)(DRD_(thread_get_vc)(DRD_(thread_get_running_tid)())); 99 if (access_type == eStore && size <= sizeof(HWord)) { 100 DRD_(trace_msg_w_bt)("store 0x%lx size %ld val %ld/0x%lx (thread %d /" 101 " vc %s)", addr, size, stored_value_lo, 102 stored_value_lo, DRD_(thread_get_running_tid)(), 103 vc); 104 } else if (access_type == eStore && size > sizeof(HWord)) { 105 ULong sv; 106 107 tl_assert(sizeof(HWord) == 4); 108 sv = ((ULong)stored_value_hi << 32) | stored_value_lo; 109 DRD_(trace_msg_w_bt)("store 0x%lx size %ld val %lld/0x%llx (thread %d" 110 " / vc %s)", addr, size, sv, sv, 111 DRD_(thread_get_running_tid)(), vc); 112 } else { 113 DRD_(trace_msg_w_bt)("%s 0x%lx size %ld (thread %d / vc %s)", 114 access_type == eLoad ? "load " 115 : access_type == eStore ? "store" 116 : access_type == eStart ? "start" 117 : access_type == eEnd ? "end " : "????", 118 addr, size, DRD_(thread_get_running_tid)(), vc); 119 } 120 VG_(free)(vc); 121 tl_assert(DRD_(DrdThreadIdToVgThreadId)(DRD_(thread_get_running_tid)()) 122 == VG_(get_running_tid)()); 123 } 124} 125 126static VG_REGPARM(2) void drd_trace_mem_load(const Addr addr, const SizeT size) 127{ 128 return DRD_(trace_mem_access)(addr, size, eLoad, 0, 0); 129} 130 131static VG_REGPARM(3) void drd_trace_mem_store(const Addr addr,const SizeT size, 132 const HWord stored_value_hi, 133 const HWord stored_value_lo) 134{ 135 return DRD_(trace_mem_access)(addr, size, eStore, stored_value_hi, 136 stored_value_lo); 137} 138 139static void drd_report_race(const Addr addr, const SizeT size, 140 const BmAccessTypeT access_type) 141{ 142 ThreadId vg_tid; 143 144 vg_tid = VG_(get_running_tid)(); 145 if (!DRD_(get_check_stack_accesses)() 146 && DRD_(thread_address_on_any_stack)(addr)) { 147#if 0 148 GenericErrInfo GEI = { 149 .tid = DRD_(thread_get_running_tid)(), 150 .addr = addr, 151 }; 152 VG_(maybe_record_error)(vg_tid, GenericErr, VG_(get_IP)(vg_tid), 153 "--check-stack-var=no skips checking stack" 154 " variables shared over threads", 155 &GEI); 156#endif 157 } else { 158 DataRaceErrInfo drei = { 159 .tid = DRD_(thread_get_running_tid)(), 160 .addr = addr, 161 .size = size, 162 .access_type = access_type, 163 }; 164 VG_(maybe_record_error)(vg_tid, DataRaceErr, VG_(get_IP)(vg_tid), 165 "Conflicting access", &drei); 166 167 if (s_first_race_only) 168 DRD_(start_suppression)(addr, addr + size, "first race only"); 169 } 170} 171 172VG_REGPARM(2) void DRD_(trace_load)(Addr addr, SizeT size) 173{ 174#ifdef ENABLE_DRD_CONSISTENCY_CHECKS 175 /* The assert below has been commented out because of performance reasons.*/ 176 tl_assert(DRD_(thread_get_running_tid)() 177 == DRD_(VgThreadIdToDrdThreadId)(VG_(get_running_tid()))); 178#endif 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_triggers_conflict(addr, addr + size) 184 && ! DRD_(is_suppressed)(addr, addr + size)) 185 { 186 drd_report_race(addr, size, eLoad); 187 } 188} 189 190static VG_REGPARM(1) void drd_trace_load_1(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_1_triggers_conflict(addr) 196 && ! DRD_(is_suppressed)(addr, addr + 1)) 197 { 198 drd_report_race(addr, 1, eLoad); 199 } 200} 201 202static VG_REGPARM(1) void drd_trace_load_2(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_2_triggers_conflict(addr) 208 && ! DRD_(is_suppressed)(addr, addr + 2)) 209 { 210 drd_report_race(addr, 2, eLoad); 211 } 212} 213 214static VG_REGPARM(1) void drd_trace_load_4(Addr addr) 215{ 216 if (DRD_(running_thread_is_recording_loads)() 217 && (s_check_stack_accesses 218 || ! DRD_(thread_address_on_stack)(addr)) 219 && bm_access_load_4_triggers_conflict(addr) 220 && ! DRD_(is_suppressed)(addr, addr + 4)) 221 { 222 drd_report_race(addr, 4, eLoad); 223 } 224} 225 226static VG_REGPARM(1) void drd_trace_load_8(Addr addr) 227{ 228 if (DRD_(running_thread_is_recording_loads)() 229 && (s_check_stack_accesses 230 || ! DRD_(thread_address_on_stack)(addr)) 231 && bm_access_load_8_triggers_conflict(addr) 232 && ! DRD_(is_suppressed)(addr, addr + 8)) 233 { 234 drd_report_race(addr, 8, eLoad); 235 } 236} 237 238VG_REGPARM(2) void DRD_(trace_store)(Addr addr, SizeT size) 239{ 240#ifdef ENABLE_DRD_CONSISTENCY_CHECKS 241 /* The assert below has been commented out because of performance reasons.*/ 242 tl_assert(DRD_(thread_get_running_tid)() 243 == DRD_(VgThreadIdToDrdThreadId)(VG_(get_running_tid()))); 244#endif 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_triggers_conflict(addr, addr + size) 250 && ! DRD_(is_suppressed)(addr, addr + size)) 251 { 252 drd_report_race(addr, size, eStore); 253 } 254} 255 256static VG_REGPARM(1) void drd_trace_store_1(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_1_triggers_conflict(addr) 262 && ! DRD_(is_suppressed)(addr, addr + 1)) 263 { 264 drd_report_race(addr, 1, eStore); 265 } 266} 267 268static VG_REGPARM(1) void drd_trace_store_2(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_2_triggers_conflict(addr) 274 && ! DRD_(is_suppressed)(addr, addr + 2)) 275 { 276 drd_report_race(addr, 2, eStore); 277 } 278} 279 280static VG_REGPARM(1) void drd_trace_store_4(Addr addr) 281{ 282 if (DRD_(running_thread_is_recording_stores)() 283 && (s_check_stack_accesses 284 || !DRD_(thread_address_on_stack)(addr)) 285 && bm_access_store_4_triggers_conflict(addr) 286 && !DRD_(is_suppressed)(addr, addr + 4)) 287 { 288 drd_report_race(addr, 4, eStore); 289 } 290} 291 292static VG_REGPARM(1) void drd_trace_store_8(Addr addr) 293{ 294 if (DRD_(running_thread_is_recording_stores)() 295 && (s_check_stack_accesses 296 || ! DRD_(thread_address_on_stack)(addr)) 297 && bm_access_store_8_triggers_conflict(addr) 298 && ! DRD_(is_suppressed)(addr, addr + 8)) 299 { 300 drd_report_race(addr, 8, eStore); 301 } 302} 303 304/** 305 * Return true if and only if addr_expr matches the pattern (SP) or 306 * <offset>(SP). 307 */ 308static Bool is_stack_access(IRSB* const bb, IRExpr* const addr_expr) 309{ 310 Bool result = False; 311 312 if (addr_expr->tag == Iex_RdTmp) 313 { 314 int i; 315 for (i = 0; i < bb->stmts_size; i++) 316 { 317 if (bb->stmts[i] 318 && bb->stmts[i]->tag == Ist_WrTmp 319 && bb->stmts[i]->Ist.WrTmp.tmp == addr_expr->Iex.RdTmp.tmp) 320 { 321 IRExpr* e = bb->stmts[i]->Ist.WrTmp.data; 322 if (e->tag == Iex_Get && e->Iex.Get.offset == STACK_POINTER_OFFSET) 323 { 324 result = True; 325 } 326 327 //ppIRExpr(e); 328 //VG_(printf)(" (%s)\n", result ? "True" : "False"); 329 break; 330 } 331 } 332 } 333 return result; 334} 335 336static const IROp u_widen_irop[5][9] = { 337 [Ity_I1 - Ity_I1] = { [4] = Iop_1Uto32, [8] = Iop_1Uto64 }, 338 [Ity_I8 - Ity_I1] = { [4] = Iop_8Uto32, [8] = Iop_8Uto64 }, 339 [Ity_I16 - Ity_I1] = { [4] = Iop_16Uto32, [8] = Iop_16Uto64 }, 340 [Ity_I32 - Ity_I1] = { [8] = Iop_32Uto64 }, 341}; 342 343/** 344 * Instrument the client code to trace a memory load (--trace-addr). 345 */ 346static IRExpr* instr_trace_mem_load(IRSB* const bb, IRExpr* addr_expr, 347 const HWord size) 348{ 349 IRTemp tmp; 350 351 tmp = newIRTemp(bb->tyenv, typeOfIRExpr(bb->tyenv, addr_expr)); 352 addStmtToIRSB(bb, IRStmt_WrTmp(tmp, addr_expr)); 353 addr_expr = IRExpr_RdTmp(tmp); 354 355 addStmtToIRSB(bb, 356 IRStmt_Dirty( 357 unsafeIRDirty_0_N(/*regparms*/2, 358 "drd_trace_mem_load", 359 VG_(fnptr_to_fnentry) 360 (drd_trace_mem_load), 361 mkIRExprVec_2(addr_expr, mkIRExpr_HWord(size))))); 362 363 return addr_expr; 364} 365 366/** 367 * Instrument the client code to trace a memory store (--trace-addr). 368 */ 369static void instr_trace_mem_store(IRSB* const bb, IRExpr* const addr_expr, 370 IRExpr* data_expr_hi, IRExpr* data_expr_lo) 371{ 372 IRType ty_data_expr; 373 HWord size; 374 375 tl_assert(sizeof(HWord) == 4 || sizeof(HWord) == 8); 376 tl_assert(!data_expr_hi || typeOfIRExpr(bb->tyenv, data_expr_hi) == Ity_I32); 377 378 ty_data_expr = typeOfIRExpr(bb->tyenv, data_expr_lo); 379 size = sizeofIRType(ty_data_expr); 380 381#if 0 382 // Test code 383 if (ty_data_expr == Ity_I32) { 384 IRTemp tmp = newIRTemp(bb->tyenv, Ity_F32); 385 data_expr_lo = IRExpr_Unop(Iop_ReinterpI32asF32, data_expr_lo); 386 addStmtToIRSB(bb, IRStmt_WrTmp(tmp, data_expr_lo)); 387 data_expr_lo = IRExpr_RdTmp(tmp); 388 ty_data_expr = Ity_F32; 389 } else if (ty_data_expr == Ity_I64) { 390 IRTemp tmp = newIRTemp(bb->tyenv, Ity_F64); 391 data_expr_lo = IRExpr_Unop(Iop_ReinterpI64asF64, data_expr_lo); 392 addStmtToIRSB(bb, IRStmt_WrTmp(tmp, data_expr_lo)); 393 data_expr_lo = IRExpr_RdTmp(tmp); 394 ty_data_expr = Ity_F64; 395 } 396#endif 397 398 if (ty_data_expr == Ity_F32) { 399 IRTemp tmp = newIRTemp(bb->tyenv, Ity_I32); 400 addStmtToIRSB(bb, IRStmt_WrTmp(tmp, IRExpr_Unop(Iop_ReinterpF32asI32, 401 data_expr_lo))); 402 data_expr_lo = IRExpr_RdTmp(tmp); 403 ty_data_expr = Ity_I32; 404 } else if (ty_data_expr == Ity_F64) { 405 IRTemp tmp = newIRTemp(bb->tyenv, Ity_I64); 406 addStmtToIRSB(bb, IRStmt_WrTmp(tmp, IRExpr_Unop(Iop_ReinterpF64asI64, 407 data_expr_lo))); 408 data_expr_lo = IRExpr_RdTmp(tmp); 409 ty_data_expr = Ity_I64; 410 } 411 412 if (size == sizeof(HWord) 413 && (ty_data_expr == Ity_I32 || ty_data_expr == Ity_I64)) 414 { 415 /* No conversion necessary */ 416 } else { 417 IROp widen_op; 418 419 if (Ity_I1 <= ty_data_expr 420 && ty_data_expr 421 < Ity_I1 + sizeof(u_widen_irop)/sizeof(u_widen_irop[0])) 422 { 423 widen_op = u_widen_irop[ty_data_expr - Ity_I1][sizeof(HWord)]; 424 if (!widen_op) 425 widen_op = Iop_INVALID; 426 } else { 427 widen_op = Iop_INVALID; 428 } 429 if (widen_op != Iop_INVALID) { 430 IRTemp tmp; 431 432 /* Widen the integer expression to a HWord */ 433 tmp = newIRTemp(bb->tyenv, sizeof(HWord) == 4 ? Ity_I32 : Ity_I64); 434 addStmtToIRSB(bb, 435 IRStmt_WrTmp(tmp, IRExpr_Unop(widen_op, data_expr_lo))); 436 data_expr_lo = IRExpr_RdTmp(tmp); 437 } else if (size > sizeof(HWord) && !data_expr_hi 438 && ty_data_expr == Ity_I64) { 439 IRTemp tmp; 440 441 tl_assert(sizeof(HWord) == 4); 442 tl_assert(size == 8); 443 tmp = newIRTemp(bb->tyenv, Ity_I32); 444 addStmtToIRSB(bb, 445 IRStmt_WrTmp(tmp, 446 IRExpr_Unop(Iop_64HIto32, data_expr_lo))); 447 data_expr_hi = IRExpr_RdTmp(tmp); 448 tmp = newIRTemp(bb->tyenv, Ity_I32); 449 addStmtToIRSB(bb, IRStmt_WrTmp(tmp, 450 IRExpr_Unop(Iop_64to32, data_expr_lo))); 451 data_expr_lo = IRExpr_RdTmp(tmp); 452 } else { 453 data_expr_lo = mkIRExpr_HWord(0); 454 } 455 } 456 addStmtToIRSB(bb, 457 IRStmt_Dirty( 458 unsafeIRDirty_0_N(/*regparms*/3, 459 "drd_trace_mem_store", 460 VG_(fnptr_to_fnentry)(drd_trace_mem_store), 461 mkIRExprVec_4(addr_expr, mkIRExpr_HWord(size), 462 data_expr_hi ? data_expr_hi 463 : mkIRExpr_HWord(0), data_expr_lo)))); 464} 465 466static void instrument_load(IRSB* const bb, IRExpr* const addr_expr, 467 const HWord size) 468{ 469 IRExpr* size_expr; 470 IRExpr** argv; 471 IRDirty* di; 472 473 if (!s_check_stack_accesses && is_stack_access(bb, addr_expr)) 474 return; 475 476 switch (size) 477 { 478 case 1: 479 argv = mkIRExprVec_1(addr_expr); 480 di = unsafeIRDirty_0_N(/*regparms*/1, 481 "drd_trace_load_1", 482 VG_(fnptr_to_fnentry)(drd_trace_load_1), 483 argv); 484 break; 485 case 2: 486 argv = mkIRExprVec_1(addr_expr); 487 di = unsafeIRDirty_0_N(/*regparms*/1, 488 "drd_trace_load_2", 489 VG_(fnptr_to_fnentry)(drd_trace_load_2), 490 argv); 491 break; 492 case 4: 493 argv = mkIRExprVec_1(addr_expr); 494 di = unsafeIRDirty_0_N(/*regparms*/1, 495 "drd_trace_load_4", 496 VG_(fnptr_to_fnentry)(drd_trace_load_4), 497 argv); 498 break; 499 case 8: 500 argv = mkIRExprVec_1(addr_expr); 501 di = unsafeIRDirty_0_N(/*regparms*/1, 502 "drd_trace_load_8", 503 VG_(fnptr_to_fnentry)(drd_trace_load_8), 504 argv); 505 break; 506 default: 507 size_expr = mkIRExpr_HWord(size); 508 argv = mkIRExprVec_2(addr_expr, size_expr); 509 di = unsafeIRDirty_0_N(/*regparms*/2, 510 "drd_trace_load", 511 VG_(fnptr_to_fnentry)(DRD_(trace_load)), 512 argv); 513 break; 514 } 515 addStmtToIRSB(bb, IRStmt_Dirty(di)); 516} 517 518static void instrument_store(IRSB* const bb, IRExpr* addr_expr, 519 IRExpr* const data_expr) 520{ 521 IRExpr* size_expr; 522 IRExpr** argv; 523 IRDirty* di; 524 HWord size; 525 526 size = sizeofIRType(typeOfIRExpr(bb->tyenv, data_expr)); 527 528 if (UNLIKELY(DRD_(any_address_is_traced)())) { 529 IRTemp tmp = newIRTemp(bb->tyenv, typeOfIRExpr(bb->tyenv, addr_expr)); 530 addStmtToIRSB(bb, IRStmt_WrTmp(tmp, addr_expr)); 531 addr_expr = IRExpr_RdTmp(tmp); 532 instr_trace_mem_store(bb, addr_expr, NULL, data_expr); 533 } 534 535 if (!s_check_stack_accesses && is_stack_access(bb, addr_expr)) 536 return; 537 538 switch (size) 539 { 540 case 1: 541 argv = mkIRExprVec_1(addr_expr); 542 di = unsafeIRDirty_0_N(/*regparms*/1, 543 "drd_trace_store_1", 544 VG_(fnptr_to_fnentry)(drd_trace_store_1), 545 argv); 546 break; 547 case 2: 548 argv = mkIRExprVec_1(addr_expr); 549 di = unsafeIRDirty_0_N(/*regparms*/1, 550 "drd_trace_store_2", 551 VG_(fnptr_to_fnentry)(drd_trace_store_2), 552 argv); 553 break; 554 case 4: 555 argv = mkIRExprVec_1(addr_expr); 556 di = unsafeIRDirty_0_N(/*regparms*/1, 557 "drd_trace_store_4", 558 VG_(fnptr_to_fnentry)(drd_trace_store_4), 559 argv); 560 break; 561 case 8: 562 argv = mkIRExprVec_1(addr_expr); 563 di = unsafeIRDirty_0_N(/*regparms*/1, 564 "drd_trace_store_8", 565 VG_(fnptr_to_fnentry)(drd_trace_store_8), 566 argv); 567 break; 568 default: 569 size_expr = mkIRExpr_HWord(size); 570 argv = mkIRExprVec_2(addr_expr, size_expr); 571 di = unsafeIRDirty_0_N(/*regparms*/2, 572 "drd_trace_store", 573 VG_(fnptr_to_fnentry)(DRD_(trace_store)), 574 argv); 575 break; 576 } 577 addStmtToIRSB(bb, IRStmt_Dirty(di)); 578} 579 580IRSB* DRD_(instrument)(VgCallbackClosure* const closure, 581 IRSB* const bb_in, 582 VexGuestLayout* const layout, 583 VexGuestExtents* const vge, 584 VexArchInfo* archinfo_host, 585 IRType const gWordTy, 586 IRType const hWordTy) 587{ 588 IRDirty* di; 589 Int i; 590 IRSB* bb; 591 IRExpr** argv; 592 Bool instrument = True; 593 594 /* Set up BB */ 595 bb = emptyIRSB(); 596 bb->tyenv = deepCopyIRTypeEnv(bb_in->tyenv); 597 bb->next = deepCopyIRExpr(bb_in->next); 598 bb->jumpkind = bb_in->jumpkind; 599 bb->offsIP = bb_in->offsIP; 600 601 for (i = 0; i < bb_in->stmts_used; i++) 602 { 603 IRStmt* const st = bb_in->stmts[i]; 604 tl_assert(st); 605 tl_assert(isFlatIRStmt(st)); 606 607 switch (st->tag) 608 { 609 /* Note: the code for not instrumenting the code in .plt */ 610 /* sections is only necessary on CentOS 3.0 x86 (kernel 2.4.21 */ 611 /* + glibc 2.3.2 + NPTL 0.60 + binutils 2.14.90.0.4). */ 612 /* This is because on this platform dynamic library symbols are */ 613 /* relocated in another way than by later binutils versions. The */ 614 /* linker e.g. does not generate .got.plt sections on CentOS 3.0. */ 615 case Ist_IMark: 616 instrument = VG_(DebugInfo_sect_kind)(NULL, 0, st->Ist.IMark.addr) 617 != Vg_SectPLT; 618 addStmtToIRSB(bb, st); 619 break; 620 621 case Ist_MBE: 622 switch (st->Ist.MBE.event) 623 { 624 case Imbe_Fence: 625 break; /* not interesting */ 626 default: 627 tl_assert(0); 628 } 629 addStmtToIRSB(bb, st); 630 break; 631 632 case Ist_Store: 633 if (instrument) 634 instrument_store(bb, st->Ist.Store.addr, st->Ist.Store.data); 635 addStmtToIRSB(bb, st); 636 break; 637 638 case Ist_WrTmp: 639 if (instrument) { 640 const IRExpr* const data = st->Ist.WrTmp.data; 641 IRExpr* addr_expr = data->Iex.Load.addr; 642 if (data->tag == Iex_Load) { 643 if (UNLIKELY(DRD_(any_address_is_traced)())) { 644 addr_expr = instr_trace_mem_load(bb, addr_expr, 645 sizeofIRType(data->Iex.Load.ty)); 646 } 647 instrument_load(bb, data->Iex.Load.addr, 648 sizeofIRType(data->Iex.Load.ty)); 649 } 650 } 651 addStmtToIRSB(bb, st); 652 break; 653 654 case Ist_Dirty: 655 if (instrument) { 656 IRDirty* d = st->Ist.Dirty.details; 657 IREffect const mFx = d->mFx; 658 switch (mFx) { 659 case Ifx_None: 660 break; 661 case Ifx_Read: 662 case Ifx_Write: 663 case Ifx_Modify: 664 tl_assert(d->mAddr); 665 tl_assert(d->mSize > 0); 666 argv = mkIRExprVec_2(d->mAddr, mkIRExpr_HWord(d->mSize)); 667 if (mFx == Ifx_Read || mFx == Ifx_Modify) { 668 di = unsafeIRDirty_0_N( 669 /*regparms*/2, 670 "drd_trace_load", 671 VG_(fnptr_to_fnentry)(DRD_(trace_load)), 672 argv); 673 addStmtToIRSB(bb, IRStmt_Dirty(di)); 674 } 675 if (mFx == Ifx_Write || mFx == Ifx_Modify) 676 { 677 di = unsafeIRDirty_0_N( 678 /*regparms*/2, 679 "drd_trace_store", 680 VG_(fnptr_to_fnentry)(DRD_(trace_store)), 681 argv); 682 addStmtToIRSB(bb, IRStmt_Dirty(di)); 683 } 684 break; 685 default: 686 tl_assert(0); 687 } 688 } 689 addStmtToIRSB(bb, st); 690 break; 691 692 case Ist_CAS: 693 if (instrument) { 694 /* 695 * Treat compare-and-swap as a read. By handling atomic 696 * instructions as read instructions no data races are reported 697 * between conflicting atomic operations nor between atomic 698 * operations and non-atomic reads. Conflicts between atomic 699 * operations and non-atomic write operations are still reported 700 * however. 701 */ 702 Int dataSize; 703 IRCAS* cas = st->Ist.CAS.details; 704 705 tl_assert(cas->addr != NULL); 706 tl_assert(cas->dataLo != NULL); 707 dataSize = sizeofIRType(typeOfIRExpr(bb->tyenv, cas->dataLo)); 708 if (cas->dataHi != NULL) 709 dataSize *= 2; /* since it's a doubleword-CAS */ 710 711 if (UNLIKELY(DRD_(any_address_is_traced)())) 712 instr_trace_mem_store(bb, cas->addr, cas->dataHi, cas->dataLo); 713 714 instrument_load(bb, cas->addr, dataSize); 715 } 716 addStmtToIRSB(bb, st); 717 break; 718 719 case Ist_LLSC: { 720 /* 721 * Ignore store-conditionals (except for tracing), and handle 722 * load-linked's exactly like normal loads. 723 */ 724 IRType dataTy; 725 726 if (st->Ist.LLSC.storedata == NULL) { 727 /* LL */ 728 dataTy = typeOfIRTemp(bb_in->tyenv, st->Ist.LLSC.result); 729 if (instrument) { 730 IRExpr* addr_expr = st->Ist.LLSC.addr; 731 if (UNLIKELY(DRD_(any_address_is_traced)())) 732 addr_expr = instr_trace_mem_load(bb, addr_expr, 733 sizeofIRType(dataTy)); 734 735 instrument_load(bb, addr_expr, sizeofIRType(dataTy)); 736 } 737 } else { 738 /* SC */ 739 instr_trace_mem_store(bb, st->Ist.LLSC.addr, NULL, 740 st->Ist.LLSC.storedata); 741 } 742 addStmtToIRSB(bb, st); 743 break; 744 } 745 746 case Ist_NoOp: 747 case Ist_AbiHint: 748 case Ist_Put: 749 case Ist_PutI: 750 case Ist_Exit: 751 /* None of these can contain any memory references. */ 752 addStmtToIRSB(bb, st); 753 break; 754 755 default: 756 ppIRStmt(st); 757 tl_assert(0); 758 } 759 } 760 761 return bb; 762} 763 764