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