static IRSB* drd_instrument(VgCallbackClosure* const closure, IRSB* const bb_in, VexGuestLayout* const layout, VexGuestExtents* const vge, IRType const gWordTy, IRType const hWordTy) { IRDirty* di; Int i; IRSB* bb; IRExpr** argv; Bool instrument = True; Bool bus_locked = False; /* Set up BB */ bb = emptyIRSB(); bb->tyenv = deepCopyIRTypeEnv(bb_in->tyenv); bb->next = deepCopyIRExpr(bb_in->next); bb->jumpkind = bb_in->jumpkind; for (i = 0; i < bb_in->stmts_used; i++) { IRStmt* const st = bb_in->stmts[i]; tl_assert(st); if (st->tag == Ist_NoOp) continue; switch (st->tag) { /* Note: the code for not instrumenting the code in .plt */ /* sections is only necessary on CentOS 3.0 x86 (kernel 2.4.21 */ /* + glibc 2.3.2 + NPTL 0.60 + binutils 2.14.90.0.4). */ /* This is because on this platform dynamic library symbols are */ /* relocated in another way than by later binutils versions. The */ /* linker e.g. does not generate .got.plt sections on CentOS 3.0. */ case Ist_IMark: instrument = VG_(seginfo_sect_kind)(NULL, 0, st->Ist.IMark.addr) != Vg_SectPLT; addStmtToIRSB(bb, st); break; case Ist_MBE: switch (st->Ist.MBE.event) { case Imbe_Fence: break; /* not interesting */ case Imbe_BusLock: case Imbe_SnoopedStoreBegin: tl_assert(! bus_locked); bus_locked = True; break; case Imbe_BusUnlock: case Imbe_SnoopedStoreEnd: tl_assert(bus_locked); bus_locked = False; break; default: tl_assert(0); } addStmtToIRSB(bb, st); break; case Ist_Store: if (instrument && ! bus_locked) { instrument_store(bb, st->Ist.Store.addr, sizeofIRType(typeOfIRExpr(bb->tyenv, st->Ist.Store.data))); } addStmtToIRSB(bb, st); break; case Ist_WrTmp: if (instrument) { const IRExpr* const data = st->Ist.WrTmp.data; if (data->tag == Iex_Load) { instrument_load(bb, data->Iex.Load.addr, sizeofIRType(data->Iex.Load.ty)); } } addStmtToIRSB(bb, st); break; case Ist_Dirty: if (instrument) { IRDirty* d = st->Ist.Dirty.details; IREffect const mFx = d->mFx; switch (mFx) { case Ifx_None: break; case Ifx_Read: case Ifx_Write: case Ifx_Modify: tl_assert(d->mAddr); tl_assert(d->mSize > 0); argv = mkIRExprVec_2(d->mAddr, mkIRExpr_HWord(d->mSize)); if (mFx == Ifx_Read || mFx == Ifx_Modify) { di = unsafeIRDirty_0_N( /*regparms*/2, "drd_trace_load", VG_(fnptr_to_fnentry)(drd_trace_load), argv); addStmtToIRSB(bb, IRStmt_Dirty(di)); } if ((mFx == Ifx_Write || mFx == Ifx_Modify) && ! bus_locked) { di = unsafeIRDirty_0_N( /*regparms*/2, "drd_trace_store", VG_(fnptr_to_fnentry)(drd_trace_store), argv); addStmtToIRSB(bb, IRStmt_Dirty(di)); } break; default: tl_assert(0); } } addStmtToIRSB(bb, st); break; default: addStmtToIRSB(bb, st); break; } } tl_assert(! bus_locked); return bb; }
static IRSB* ca_instrument( VgCallbackClosure * closure, IRSB* bb_in, VexGuestLayout* layout, VexGuestExtents* vge, IRType gWordTy, IRType hWordTy ) { Int i; IRSB* bb; Int count1; Int count2; Int count3; Int count4; Int count5; Int count6; Int count7; Int count8; Int count9; Int sum; findRepMovContext * repMovContext; // do not instrument block if we have not yet read from tainted data if (run_prefix_task == 0) { /* Update count of BBs instrumented. Do it here to agree with */ /* Valgrind core numbering of BBs instrumented. */ /* NOTE: our numbering of BBs executed does not agree w/core! */ caMainBBCounter++; return bb_in; } /* Counting the number of entries in a hash table */ count1 = ca_count_hashtable(ogVarOf); count2 = ca_count_hashtable(ogTypeOf); count3 = ca_count_hashtable(cgPathCond); count4 = ca_count_hashtable(isIsSymbolic); count5 = ca_count_hashtable(caIntervalTable); count6 = ca_count_hashtable(cgIsDeclared); count7 = ca_count_hashtable(cgITEWriteStackMemSt); count8 = ca_count_hashtable(cgITEWriteStackMaSt); count9 = ca_count_hashtable(tmAddrToVar); // debugging option if (ca_output_comment) { VG_(printf)("XXX The number of has entries in hash tables 1-9 are %d %d %d %d %d %d %d %d %d\n", count1, count2, count3, count4, count5, count6, count7, count8, count9); sum = count1 + count2 + count3 + count4 + count5 + count6 + count7 + count8 + count9; VG_(printf)("XXX The total number of hash entries in all the tables is %d\n", sum); VG_(printf)("XXX The size of each entry for the hash tables 1-9 are %d %d %d %d %d %d %d %d %d\n", sizeof(OgVarOfHashNode), sizeof(ogTypeOf), sizeof(cgPathCond), sizeof(isIsSymbolic), sizeof(caIntervalTable), sizeof(cgIsDeclared), sizeof(cgITEWriteStackMemSt), sizeof(cgITEWriteStackMaSt), sizeof(tmAddrToVar)); } if (gWordTy != hWordTy) { VG_(printf)("MISMATCH: "); ppIRType(gWordTy); VG_(printf)(" "); ppIRType(hWordTy); VG_(printf)("\n"); /* We don't currently support this case. */ VG_(tool_panic)("host/guest word size mismatch"); } /* Set up BB */ bb = emptyIRSB(); bb->tyenv = deepCopyIRTypeEnv(bb_in->tyenv); bb->next = deepCopyIRExpr(bb_in->next); bb->jumpkind = bb_in->jumpkind; /* Set up context for finding rep mov instructions */ /* assume at most 400 tmp vars per basic block */ repMovContext = createRepMovContext(bb->tyenv->types_used); // Copy verbatim any IR preamble preceding the first IMark i = 0; while (i < bb_in->stmts_used && bb_in->stmts[i]->tag != Ist_IMark) { addStmtToIRSB( bb, bb_in->stmts[i] ); i++; } cgAddPreamble(bb,caMainBBCounter); for (/*use current i*/; i < bb_in->stmts_used; i++) { IRStmt* st = bb_in->stmts[i]; if (!st || st->tag == Ist_NoOp) continue; if (st->tag == Ist_Exit) { cgAddExitPre(bb,st); } addStmtToIRSB(bb, st ); if (ca_type_inference) { ogIRStmt(bb, st, caMainBBCounter); } ufInstOgIRStmt(bb, st, caMainBBCounter); findRepMovIRStmt(bb, st, repMovContext, caMainBBCounter); isIRStmt(bb, st, caMainBBCounter); tmIRStmt(bb, st, caMainBBCounter); cgIRStmt(bb, st, caMainBBCounter); if (st->tag == Ist_Exit) { cgAddExitPost(bb,st); } } /* Update count of BBs instrumented. Do it here to agree with */ /* Valgrind core numbering of BBs instrumented. */ caMainBBCounter++; /* Destroy the rep mov context */ destroyRepMovContext(repMovContext); /* Return the new bb */ return bb; }
/* For tools that want to know about SP changes, this pass adds in the appropriate hooks. We have to do it after the tool's instrumentation, so the tool doesn't have to worry about the C calls it adds in, and we must do it before register allocation because spilled temps make it much harder to work out the SP deltas. This it is done with Vex's "second instrumentation" pass. Basically, we look for GET(SP)/PUT(SP) pairs and track constant increments/decrements of SP between them. (This requires tracking one or more "aliases", which are not exact aliases but instead are tempregs whose value is equal to the SP's plus or minus a known constant.) If all the changes to SP leading up to a PUT(SP) are by known, small constants, we can do a specific call to eg. new_mem_stack_4, otherwise we fall back to the case that handles an unknown SP change. */ static IRSB* vg_SP_update_pass ( void* closureV, IRSB* sb_in, VexGuestLayout* layout, VexGuestExtents* vge, IRType gWordTy, IRType hWordTy ) { Int i, j, minoff_ST, maxoff_ST, sizeof_SP, offset_SP; IRDirty *dcall, *d; IRStmt* st; IRExpr* e; IRRegArray* descr; IRType typeof_SP; Long delta, con; /* Set up BB */ IRSB* bb = emptyIRSB(); bb->tyenv = deepCopyIRTypeEnv(sb_in->tyenv); bb->next = deepCopyIRExpr(sb_in->next); bb->jumpkind = sb_in->jumpkind; delta = 0; sizeof_SP = layout->sizeof_SP; offset_SP = layout->offset_SP; typeof_SP = sizeof_SP==4 ? Ity_I32 : Ity_I64; vg_assert(sizeof_SP == 4 || sizeof_SP == 8); # define IS_ADD(op) (sizeof_SP==4 ? ((op)==Iop_Add32) : ((op)==Iop_Add64)) # define IS_SUB(op) (sizeof_SP==4 ? ((op)==Iop_Sub32) : ((op)==Iop_Sub64)) # define IS_ADD_OR_SUB(op) (IS_ADD(op) || IS_SUB(op)) # define GET_CONST(con) \ (sizeof_SP==4 ? (Long)(Int)(con->Ico.U32) \ : (Long)(con->Ico.U64)) // XXX: convert this to a function # define DO(kind, syze, tmpp) \ do { \ if (!VG_(tdict).track_##kind##_mem_stack_##syze) \ goto generic; \ \ /* I don't know if it's really necessary to say that the */ \ /* call reads the stack pointer. But anyway, we do. */ \ dcall = unsafeIRDirty_0_N( \ 1/*regparms*/, \ "track_" #kind "_mem_stack_" #syze, \ VG_(fnptr_to_fnentry)( \ VG_(tdict).track_##kind##_mem_stack_##syze ), \ mkIRExprVec_1(IRExpr_RdTmp(tmpp)) \ ); \ dcall->nFxState = 1; \ dcall->fxState[0].fx = Ifx_Read; \ dcall->fxState[0].offset = layout->offset_SP; \ dcall->fxState[0].size = layout->sizeof_SP; \ \ addStmtToIRSB( bb, IRStmt_Dirty(dcall) ); \ \ update_SP_aliases(-delta); \ \ n_SP_updates_fast++; \ \ } while (0) clear_SP_aliases(); for (i = 0; i < sb_in->stmts_used; i++) { st = sb_in->stmts[i]; /* t = Get(sp): curr = t, delta = 0 */ if (st->tag != Ist_WrTmp) goto case2; e = st->Ist.WrTmp.data; if (e->tag != Iex_Get) goto case2; if (e->Iex.Get.offset != offset_SP) goto case2; if (e->Iex.Get.ty != typeof_SP) goto case2; add_SP_alias(st->Ist.WrTmp.tmp, 0); addStmtToIRSB( bb, st ); continue; case2: /* t' = curr +/- const: curr = t', delta +=/-= const */ if (st->tag != Ist_WrTmp) goto case3; e = st->Ist.WrTmp.data; if (e->tag != Iex_Binop) goto case3; if (e->Iex.Binop.arg1->tag != Iex_RdTmp) goto case3; if (!get_SP_delta(e->Iex.Binop.arg1->Iex.RdTmp.tmp, &delta)) goto case3; if (e->Iex.Binop.arg2->tag != Iex_Const) goto case3; if (!IS_ADD_OR_SUB(e->Iex.Binop.op)) goto case3; con = GET_CONST(e->Iex.Binop.arg2->Iex.Const.con); if (IS_ADD(e->Iex.Binop.op)) { add_SP_alias(st->Ist.WrTmp.tmp, delta + con); } else { add_SP_alias(st->Ist.WrTmp.tmp, delta - con); } addStmtToIRSB( bb, st ); continue; case3: /* t' = curr: curr = t' */ if (st->tag != Ist_WrTmp) goto case4; e = st->Ist.WrTmp.data; if (e->tag != Iex_RdTmp) goto case4; if (!get_SP_delta(e->Iex.RdTmp.tmp, &delta)) goto case4; add_SP_alias(st->Ist.WrTmp.tmp, delta); addStmtToIRSB( bb, st ); continue; case4: /* Put(sp) = curr */ if (st->tag != Ist_Put) goto case5; if (st->Ist.Put.offset != offset_SP) goto case5; if (st->Ist.Put.data->tag != Iex_RdTmp) goto case5; if (get_SP_delta(st->Ist.Put.data->Iex.RdTmp.tmp, &delta)) { IRTemp tttmp = st->Ist.Put.data->Iex.RdTmp.tmp; switch (delta) { case 0: addStmtToIRSB(bb,st); continue; case 4: DO(die, 4, tttmp); addStmtToIRSB(bb,st); continue; case -4: DO(new, 4, tttmp); addStmtToIRSB(bb,st); continue; case 8: DO(die, 8, tttmp); addStmtToIRSB(bb,st); continue; case -8: DO(new, 8, tttmp); addStmtToIRSB(bb,st); continue; case 12: DO(die, 12, tttmp); addStmtToIRSB(bb,st); continue; case -12: DO(new, 12, tttmp); addStmtToIRSB(bb,st); continue; case 16: DO(die, 16, tttmp); addStmtToIRSB(bb,st); continue; case -16: DO(new, 16, tttmp); addStmtToIRSB(bb,st); continue; case 32: DO(die, 32, tttmp); addStmtToIRSB(bb,st); continue; case -32: DO(new, 32, tttmp); addStmtToIRSB(bb,st); continue; case 112: DO(die, 112, tttmp); addStmtToIRSB(bb,st); continue; case -112: DO(new, 112, tttmp); addStmtToIRSB(bb,st); continue; case 128: DO(die, 128, tttmp); addStmtToIRSB(bb,st); continue; case -128: DO(new, 128, tttmp); addStmtToIRSB(bb,st); continue; case 144: DO(die, 144, tttmp); addStmtToIRSB(bb,st); continue; case -144: DO(new, 144, tttmp); addStmtToIRSB(bb,st); continue; case 160: DO(die, 160, tttmp); addStmtToIRSB(bb,st); continue; case -160: DO(new, 160, tttmp); addStmtToIRSB(bb,st); continue; default: /* common values for ppc64: 144 128 160 112 176 */ n_SP_updates_generic_known++; goto generic; } } else {
IRSB* DRD_(instrument)(VgCallbackClosure* const closure, IRSB* const bb_in, VexGuestLayout* const layout, VexGuestExtents* const vge, IRType const gWordTy, IRType const hWordTy) { IRDirty* di; Int i; IRSB* bb; IRExpr** argv; Bool instrument = True; /* Set up BB */ bb = emptyIRSB(); bb->tyenv = deepCopyIRTypeEnv(bb_in->tyenv); bb->next = deepCopyIRExpr(bb_in->next); bb->jumpkind = bb_in->jumpkind; for (i = 0; i < bb_in->stmts_used; i++) { IRStmt* const st = bb_in->stmts[i]; tl_assert(st); if (st->tag == Ist_NoOp) continue; switch (st->tag) { /* Note: the code for not instrumenting the code in .plt */ /* sections is only necessary on CentOS 3.0 x86 (kernel 2.4.21 */ /* + glibc 2.3.2 + NPTL 0.60 + binutils 2.14.90.0.4). */ /* This is because on this platform dynamic library symbols are */ /* relocated in another way than by later binutils versions. The */ /* linker e.g. does not generate .got.plt sections on CentOS 3.0. */ case Ist_IMark: instrument = VG_(seginfo_sect_kind)(NULL, 0, st->Ist.IMark.addr) != Vg_SectPLT; addStmtToIRSB(bb, st); break; case Ist_MBE: switch (st->Ist.MBE.event) { case Imbe_Fence: break; /* not interesting */ default: tl_assert(0); } addStmtToIRSB(bb, st); break; case Ist_Store: if (instrument && /* ignore stores resulting from st{d,w}cx. */ st->Ist.Store.resSC == IRTemp_INVALID) { instrument_store(bb, st->Ist.Store.addr, sizeofIRType(typeOfIRExpr(bb->tyenv, st->Ist.Store.data))); } addStmtToIRSB(bb, st); break; case Ist_WrTmp: if (instrument) { const IRExpr* const data = st->Ist.WrTmp.data; if (data->tag == Iex_Load) { instrument_load(bb, data->Iex.Load.addr, sizeofIRType(data->Iex.Load.ty)); } } addStmtToIRSB(bb, st); break; case Ist_Dirty: if (instrument) { IRDirty* d = st->Ist.Dirty.details; IREffect const mFx = d->mFx; switch (mFx) { case Ifx_None: break; case Ifx_Read: case Ifx_Write: case Ifx_Modify: tl_assert(d->mAddr); tl_assert(d->mSize > 0); argv = mkIRExprVec_2(d->mAddr, mkIRExpr_HWord(d->mSize)); if (mFx == Ifx_Read || mFx == Ifx_Modify) { di = unsafeIRDirty_0_N( /*regparms*/2, "drd_trace_load", VG_(fnptr_to_fnentry)(DRD_(trace_load)), argv); addStmtToIRSB(bb, IRStmt_Dirty(di)); } if (mFx == Ifx_Write || mFx == Ifx_Modify) { di = unsafeIRDirty_0_N( /*regparms*/2, "drd_trace_store", VG_(fnptr_to_fnentry)(DRD_(trace_store)), argv); addStmtToIRSB(bb, IRStmt_Dirty(di)); } break; default: tl_assert(0); } } addStmtToIRSB(bb, st); break; case Ist_CAS: if (instrument) { /* * Treat compare-and-swap as a read. By handling atomic * instructions as read instructions no data races are reported * between conflicting atomic operations nor between atomic * operations and non-atomic reads. Conflicts between atomic * operations and non-atomic write operations are still reported * however. */ Int dataSize; IRCAS* cas = st->Ist.CAS.details; tl_assert(cas->addr != NULL); tl_assert(cas->dataLo != NULL); dataSize = sizeofIRType(typeOfIRExpr(bb->tyenv, cas->dataLo)); if (cas->dataHi != NULL) dataSize *= 2; /* since it's a doubleword-CAS */ instrument_load(bb, cas->addr, dataSize); } addStmtToIRSB(bb, st); break; default: addStmtToIRSB(bb, st); break; } } return bb; }
static IRSB* drd_instrument(VgCallbackClosure* const closure, IRSB* const bb_in, VexGuestLayout* const layout, VexGuestExtents* const vge, IRType const gWordTy, IRType const hWordTy) { IRDirty* di; Int i; IRSB* bb; IRExpr** argv; Bool instrument = True; Bool bus_locked = False; /* Set up BB */ bb = emptyIRSB(); bb->tyenv = deepCopyIRTypeEnv(bb_in->tyenv); bb->next = deepCopyIRExpr(bb_in->next); bb->jumpkind = bb_in->jumpkind; for (i = 0; i < bb_in->stmts_used; i++) { IRStmt* const st = bb_in->stmts[i]; tl_assert(st); if (st->tag == Ist_NoOp) continue; switch (st->tag) { case Ist_MBE: switch (st->Ist.MBE.event) { case Imbe_Fence: break; /* not interesting */ case Imbe_BusLock: tl_assert(! bus_locked); bus_locked = True; break; case Imbe_BusUnlock: tl_assert(bus_locked); bus_locked = False; break; default: tl_assert(0); } addStmtToIRSB(bb, st); break; case Ist_Store: if (instrument && ! bus_locked) { instrument_store(bb, st->Ist.Store.addr, sizeofIRType(typeOfIRExpr(bb->tyenv, st->Ist.Store.data))); } addStmtToIRSB(bb, st); break; case Ist_WrTmp: if (instrument) { const IRExpr* const data = st->Ist.WrTmp.data; if (data->tag == Iex_Load) { instrument_load(bb, data->Iex.Load.addr, sizeofIRType(data->Iex.Load.ty)); } } addStmtToIRSB(bb, st); break; case Ist_Dirty: if (instrument) { IRDirty* d = st->Ist.Dirty.details; IREffect const mFx = d->mFx; switch (mFx) { case Ifx_None: break; case Ifx_Read: case Ifx_Write: case Ifx_Modify: tl_assert(d->mAddr); tl_assert(d->mSize > 0); argv = mkIRExprVec_2(d->mAddr, mkIRExpr_HWord(d->mSize)); if (mFx == Ifx_Read || mFx == Ifx_Modify) { di = unsafeIRDirty_0_N( /*regparms*/2, "drd_trace_load", VG_(fnptr_to_fnentry)(drd_trace_load), argv); addStmtToIRSB(bb, IRStmt_Dirty(di)); } if ((mFx == Ifx_Write || mFx == Ifx_Modify) && ! bus_locked) { di = unsafeIRDirty_0_N( /*regparms*/2, "drd_trace_store", VG_(fnptr_to_fnentry)(drd_trace_store), argv); addStmtToIRSB(bb, IRStmt_Dirty(di)); } break; default: tl_assert(0); } } addStmtToIRSB(bb, st); break; default: addStmtToIRSB(bb, st); break; } } tl_assert(! bus_locked); return bb; }