void instrument_WrTmp_Mux0X(IRStmt* st, IRSB* sb_out) { IRTemp tmp = st->Ist.WrTmp.tmp; IRExpr* data = st->Ist.WrTmp.data; IRExpr* cond = data->Iex.Mux0X.cond; IRExpr* expr0 = data->Iex.Mux0X.expr0; IRExpr* exprX = data->Iex.Mux0X.exprX; Int size = sizeofIRType_bits(typeOfIRExpr(sb_out->tyenv, expr0)); IRDirty* di; tl_assert(cond->tag == Iex_RdTmp); tl_assert(isIRAtom(expr0)); tl_assert(isIRAtom(exprX)); tl_assert(typeOfIRTemp(sb_out->tyenv, tmp) == typeOfIRExpr(sb_out->tyenv, expr0)); tl_assert(typeOfIRTemp(sb_out->tyenv, tmp) == typeOfIRExpr(sb_out->tyenv, exprX)); di = unsafeIRDirty_0_N(0, "helper_instrument_WrTmp_Mux0X", VG_(fnptr_to_fnentry)(helper_instrument_WrTmp_Mux0X), mkIRExprVec_5(mkIRExpr_HWord(tmp), assignNew_HWord(sb_out, cond), mkIRExpr_HWord((expr0->tag == Iex_RdTmp) ? expr0->Iex.RdTmp.tmp : IRTemp_INVALID), mkIRExpr_HWord((exprX->tag == Iex_RdTmp) ? exprX->Iex.RdTmp.tmp : IRTemp_INVALID), mkIRExpr_HWord(size)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); }
void AddOpRhsTypeHelper(IRSB* sb, IRExpr* arg, IntTyStateHint hint, Addr addr) { IRDirty * d; HWord tmpname; switch (arg->tag) { case(Iex_RdTmp): tmpname = (HWord)arg->Iex.RdTmp.tmp; d = unsafeIRDirty_0_N(0, "EmitTmpHelper", &EmitTmpHelper, mkIRExprVec_4( mkIRExpr_HWord(tmpname), mkIRExpr_HWord(hint), mkIRExpr_HWord(counter), mkIRExpr_HWord(addr) ) ); setHelperAnns(d); addStmtToIRSB(sb,IRStmt_Dirty(d)); break; default: break; } return; }
void instrument_WrTmp_Binop(IRStmt* st, IRSB* sb_out) { IRTemp tmp = st->Ist.WrTmp.tmp; IRExpr* data = st->Ist.WrTmp.data; IROp op = data->Iex.Binop.op; IRExpr* arg1 = data->Iex.Binop.arg1; IRExpr* arg2 = data->Iex.Binop.arg2; UInt arg1_value = 0, arg2_value = 0; IRExpr* expr = IRExpr_Binop(op, arg1, arg2); Int size = sizeofIRType_bits(typeOfIRExpr(sb_out->tyenv, expr)); IRDirty* di; // we don't care about floating point and SIMD operations if (op > Iop_AddF64) return; tl_assert(isIRAtom(arg1)); tl_assert(isIRAtom(arg2)); tl_assert(typeOfIRTemp(sb_out->tyenv, tmp) == typeOfIRExpr(sb_out->tyenv, expr)); if (arg1->tag == Iex_Const) { switch (arg1->Iex.Const.con->tag) { case Ico_U1: arg1_value = arg1->Iex.Const.con->Ico.U1; break; case Ico_U8: arg1_value = arg1->Iex.Const.con->Ico.U8; break; case Ico_U16: arg1_value = arg1->Iex.Const.con->Ico.U16; break; case Ico_U32: arg1_value = arg1->Iex.Const.con->Ico.U32; break; case Ico_U64: arg1_value = arg1->Iex.Const.con->Ico.U64; break; default: VG_(tool_panic)("instrument_WrTmp_Binop"); } } if (arg2->tag == Iex_Const) { switch (arg2->Iex.Const.con->tag) { case Ico_U1: arg2_value = arg2->Iex.Const.con->Ico.U1; break; case Ico_U8: arg2_value = arg2->Iex.Const.con->Ico.U8; break; case Ico_U16: arg2_value = arg2->Iex.Const.con->Ico.U16; break; case Ico_U32: arg2_value = arg2->Iex.Const.con->Ico.U32; break; case Ico_U64: arg2_value = arg2->Iex.Const.con->Ico.U64; break; default: VG_(tool_panic)("instrument_WrTmp_Binop"); } } di = unsafeIRDirty_0_N(0, "helper_instrument_WrTmp_Binop", VG_(fnptr_to_fnentry)(helper_instrument_WrTmp_Binop), mkIRExprVec_7(mkIRExpr_HWord(tmp), mkIRExpr_HWord((arg1->tag == Iex_RdTmp) ? arg1->Iex.RdTmp.tmp : IRTemp_INVALID), mkIRExpr_HWord((arg2->tag == Iex_RdTmp) ? arg2->Iex.RdTmp.tmp : IRTemp_INVALID), mkIRExpr_HWord(op), mkIRExpr_HWord(size), (arg1->tag == Iex_RdTmp) ? assignNew_HWord(sb_out, arg1) : mkIRExpr_HWord(arg1_value), (arg2->tag == Iex_RdTmp) ? assignNew_HWord(sb_out, arg2) : mkIRExpr_HWord(arg2_value)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); }
/* instruments a Binary Operation Expression in a Ist_WrTmp statement */ static void instrument_Triop(IRSB* sb, IRStmt* st, Addr64 cia) { Char thisFct[]="instrument_Triop"; IRDirty* di; IRExpr** argv; IRExpr *op = st->Ist.WrTmp.data; IRExpr* oa_event_expr; IROp irop=op->Iex.Triop.details->op; void* f=callbackFromIROp(irop); if (f == NULL) return; OA_InstrumentContext inscon=contextFor(cia, irop); if (not_worth_watching(inscon)) return; // filter events that can't be attached to source-code location updateStats(inscon->op); oa_event_expr = mkIRExpr_HWord( (HWord)inscon ); IRExpr * args1[2]; packToI32orI64(sb, op->Iex.Triop.details->arg2, args1, irop); IRExpr * args2[2]; packToI32orI64(sb, op->Iex.Triop.details->arg3, args2, irop); argv = mkIRExprVec_3(args1[0], args2[0], oa_event_expr); di = unsafeIRDirty_0_N( 3, thisFct, VG_(fnptr_to_fnentry)( f ), argv); addStmtToIRSB( sb, IRStmt_Dirty(di) ); if (args1[1] != NULL) { // we need a second callback for 64bit types argv = mkIRExprVec_3(args1[1], args2[1], oa_event_expr); di = unsafeIRDirty_0_N( 3, thisFct, VG_(fnptr_to_fnentry)( f ), argv); addStmtToIRSB( sb, IRStmt_Dirty(di) ); } }
void AddStoreHelper(IRSB* sb, IRExpr* addr, IRExpr* data) { IRDirty* d; HWord tmpname; switch (addr->tag) { case (Iex_RdTmp): switch (data->tag) { case (Iex_RdTmp): tmpname = (HWord) data->Iex.RdTmp.tmp; d = unsafeIRDirty_0_N(0, "EmitStoreAddr2TmpHelper", &EmitStoreAddr2TmpHelper, mkIRExprVec_3(addr, mkIRExpr_HWord(tmpname), mkIRExpr_HWord(counter) ) ); setHelperAnns(d); addStmtToIRSB(sb, IRStmt_Dirty(d)); break; case (Iex_Const): /* add code to emit new tyvar for memory address */ d = unsafeIRDirty_0_N(0, "EmitStoreAddr2ConstHelper", &EmitStoreAddr2ConstHelper, mkIRExprVec_1(addr ) ); setHelperAnns(d); addStmtToIRSB(sb,IRStmt_Dirty(d)); break; default: /* Should not reach here. */ ppIRExpr(data); vpanic("Bad store address!\n"); break; } break; default: break; } return; }
/* cc_op add/sub/mul adc/sbb shl/Shl/sar tmp = cond(cc_op(cc_dep1, cc_dep2)) and/or/xor inc/dec rol/ror tmp = cond(cc_op(cc_dep1, 0)) The taintness of tmp depends on taintness of both args. (we can't handle and(cc_dep1, 0) which gives an untainted result) cf. valgrind guest_x86_defs.h */ void instrument_WrTmp_CCall(IRStmt* st, IRSB* sb_out) { IRTemp tmp = st->Ist.WrTmp.tmp; IRExpr* data = st->Ist.WrTmp.data; IRCallee* cee = data->Iex.CCall.cee; IRExpr** args = data->Iex.CCall.args; IRDirty* di; if (VG_(strcmp)(cee->name, "x86g_calculate_condition") == 0) { IRExpr* cond = args[0]; IRExpr* cc_op = args[1]; IRExpr* cc_dep1 = args[2]; IRExpr* cc_dep2 = args[3]; tl_assert(cond->tag == Iex_Const && cond->Iex.Const.con->tag == Ico_U32); tl_assert(isIRAtom(cc_op)); tl_assert(isIRAtom(cc_dep1)); tl_assert(isIRAtom(cc_dep2)); if (cc_op->tag == Iex_Const) tl_assert(cc_op->Iex.Const.con->tag == Ico_U32); if (cc_dep1->tag == Iex_Const) tl_assert(cc_dep1->Iex.Const.con->tag == Ico_U32); if (cc_dep2->tag == Iex_Const) tl_assert(cc_dep2->Iex.Const.con->tag == Ico_U32); // typeOf(x86g_calculate_condition) == typeOf(tmp) == I32 di = unsafeIRDirty_0_N(0, "helper_instrument_WrTmp_CCall_x86g_calculate_condition", VG_(fnptr_to_fnentry)(helper_instrument_WrTmp_CCall_x86g_calculate_condition), mkIRExprVec_7(mkIRExpr_HWord(tmp), mkIRExpr_HWord((cc_dep1->tag == Iex_RdTmp) ? cc_dep1->Iex.RdTmp.tmp : IRTemp_INVALID), mkIRExpr_HWord((cc_dep2->tag == Iex_RdTmp) ? cc_dep2->Iex.RdTmp.tmp : IRTemp_INVALID), mkIRExpr_HWord(cond->Iex.Const.con->Ico.U32), (cc_op->tag == Iex_RdTmp) ? assignNew_HWord(sb_out, cc_op) : mkIRExpr_HWord(cc_op->Iex.Const.con->Ico.U32), (cc_dep1->tag == Iex_RdTmp) ? assignNew_HWord(sb_out, cc_dep1) : mkIRExpr_HWord(cc_dep1->Iex.Const.con->Ico.U32), (cc_dep2->tag == Iex_RdTmp) ? assignNew_HWord(sb_out, cc_dep2) : mkIRExpr_HWord(cc_dep2->Iex.Const.con->Ico.U32)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); } else { di = unsafeIRDirty_0_N(0, "helper_instrument_WrTmp_CCall_else", VG_(fnptr_to_fnentry)(helper_instrument_WrTmp_CCall_else), mkIRExprVec_0() ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); } }
static void addEvent_RegW ( IRSB* sb, char *fnname, Int reg_no, IRAtom* tmp_val) { IRExpr** argv; IRDirty* di; tl_assert(clo_trace_mem); tl_assert(isIRAtom(tmp_val)); char *buf = (char *)VG_(malloc)("addEvent_RegW",100*sizeof(char)); tl_assert(buf!=NULL); VG_(strcpy)(buf,fnname); argv = mkIRExprVec_3( mkIRExpr_HWord( (HWord) buf ), mkIRExpr_HWord( reg_no ), tmp_val ); di = unsafeIRDirty_0_N( /*regparms*/3, "trace_regw", VG_(fnptr_to_fnentry)( trace_regw ), argv ); if(events_used > 0) flushEvents(sb); addStmtToIRSB( sb, IRStmt_Dirty(di) ); }
void instrument_WrTmp_RdTmp(IRStmt* st, IRSB* sb_out) { IRTemp tmp_lhs = st->Ist.WrTmp.tmp; IRExpr* data = st->Ist.WrTmp.data; IRTemp tmp_rhs = data->Iex.RdTmp.tmp; Int size = sizeofIRType_bits(typeOfIRTemp(sb_out->tyenv, tmp_rhs)); IRDirty* di; tl_assert(typeOfIRTemp(sb_out->tyenv, tmp_lhs) == typeOfIRTemp(sb_out->tyenv, tmp_rhs)); di = unsafeIRDirty_0_N(0, "helper_instrument_WrTmp_RdTmp", VG_(fnptr_to_fnentry)(helper_instrument_WrTmp_RdTmp), mkIRExprVec_3(mkIRExpr_HWord(tmp_lhs), mkIRExpr_HWord(tmp_rhs), mkIRExpr_HWord(size)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); }
void instrument_Put(IRStmt* st, IRSB* sb_out) { Int offset = st->Ist.Put.offset; IRExpr* data = st->Ist.Put.data; Int size = sizeofIRType_bits(typeOfIRExpr(sb_out->tyenv, data)); IRDirty* di; tl_assert(isIRAtom(data)); // the data transfer type is the type of data di = unsafeIRDirty_0_N(0, "helper_instrument_Put", VG_(fnptr_to_fnentry)(helper_instrument_Put), mkIRExprVec_3(mkIRExpr_HWord(offset), mkIRExpr_HWord((data->tag == Iex_RdTmp) ? data->Iex.RdTmp.tmp : IRTemp_INVALID), mkIRExpr_HWord(size)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); }
void instrument_Exit(IRStmt* st, IRSB* sb_out) { IRExpr* guard = st->Ist.Exit.guard; Int offsIP = st->Ist.Exit.offsIP; Int size = sizeofIRType_bits(typeOfIRConst(st->Ist.Exit.dst)); IRDirty* di; tl_assert(guard->tag == Iex_RdTmp); di = unsafeIRDirty_0_N(0, "helper_instrument_Exit", VG_(fnptr_to_fnentry)(helper_instrument_Exit), mkIRExprVec_4(assignNew_HWord(sb_out, guard), mkIRExpr_HWord(offsIP), mkIRExpr_HWord(size), mkIRExpr_HWord(guard->Iex.RdTmp.tmp)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); }
void AddLoadHelper(IRSB* sb, IRTemp lhs, IRExpr* addr) { IRDirty * d; ULong lhs_int; lhs_int = (HWord)lhs; d = unsafeIRDirty_0_N(0, "EmitLoadTmp2AddrHelper", &EmitRdTmpTmp2TmpHelper, mkIRExprVec_3( mkIRExpr_HWord(lhs_int), addr, mkIRExpr_HWord(counter) ) ); setHelperAnns(d); addStmtToIRSB(sb,IRStmt_Dirty(d)); return; }
void instrument_CAS_double_element(IRStmt* st, IRSB* sb_out) { IRCAS* cas = st->Ist.CAS.details; IRTemp oldHi = cas->oldHi, oldLo = cas->oldLo; IREndness end = cas->end; IRExpr* addr = cas->addr; IRExpr *expdHi = cas->expdHi, *expdLo = cas->expdLo; IRExpr *dataHi = cas->dataHi, *dataLo = cas->dataLo; Int size = sizeofIRType_bits(typeOfIRExpr(sb_out->tyenv, dataLo)); IROp op; IRExpr *expr, *expr2; IRDirty* di; tl_assert(isIRAtom(addr)); tl_assert(end == Iend_LE); // we assume endianness is little endian tl_assert(isIRAtom(dataLo)); tl_assert(isIRAtom(dataHi)); if (addr->tag == Iex_Const) tl_assert(addr->Iex.Const.con->tag == Ico_U32); tl_assert(typeOfIRExpr(sb_out->tyenv, addr) == typeOfIRExpr(sb_out->tyenv, dataLo)); switch (size) { case 8: op = Iop_CasCmpEQ8; break; case 16: op = Iop_CasCmpEQ16; break; case 32: op = Iop_CasCmpEQ32; break; default: VG_(tool_panic)("instrument_CAS_double_element"); } expr = assignNew(sb_out, IRExpr_Binop(op, IRExpr_RdTmp(oldLo), expdLo)); // statement has to be flat expr2 = assignNew(sb_out, IRExpr_Binop(op, IRExpr_RdTmp(oldHi), expdHi)); // statement has to be flat di = unsafeIRDirty_0_N(0, "helper_instrument_CAS_double_element", VG_(fnptr_to_fnentry)(helper_instrument_CAS_double_element), mkIRExprVec_6((addr->tag == Iex_RdTmp) ? assignNew_HWord(sb_out, addr) : mkIRExpr_HWord(addr->Iex.Const.con->Ico.U32), mkIRExpr_HWord((dataLo->tag == Iex_RdTmp) ? dataLo->Iex.RdTmp.tmp : IRTemp_INVALID), mkIRExpr_HWord((dataHi->tag == Iex_RdTmp) ? dataHi->Iex.RdTmp.tmp : IRTemp_INVALID), mkIRExpr_HWord(size), assignNew_HWord(sb_out, expr), assignNew_HWord(sb_out, expr2)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); }
void instrument_LLSC_Load_Linked(IRStmt* st, IRSB* sb_out) { IRTemp result = st->Ist.LLSC.result; IRExpr* addr = st->Ist.LLSC.addr; Int size = sizeofIRType_bits(typeOfIRTemp(sb_out->tyenv, result)); IRDirty* di; tl_assert(isIRAtom(addr)); if (addr->tag == Iex_Const) tl_assert(addr->Iex.Const.con->tag == Ico_U32); // the data transfer type is the type of result di = unsafeIRDirty_0_N(0, "helper_instrument_LLSC_Load_Linked", VG_(fnptr_to_fnentry)(helper_instrument_LLSC_Load_Linked), mkIRExprVec_3(mkIRExpr_HWord(result), (addr->tag == Iex_RdTmp) ? assignNew_HWord(sb_out, addr) : mkIRExpr_HWord(addr->Iex.Const.con->Ico.U32), mkIRExpr_HWord(size)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); }
void AddPutHelper(IRSB* sb, Int offset, IRExpr* data) { IRDirty * d; HWord h_offset = (HWord)(offset); HWord lhs_name; switch (data->tag) { case(Iex_Const): d = unsafeIRDirty_0_N(0, "EmitPutConstHelper", &EmitPutConstHelper, mkIRExprVec_2(mkIRExpr_HWord(h_offset), mkIRExpr_HWord(counter) ) ); setHelperAnns(d); addStmtToIRSB(sb, IRStmt_Dirty(d)); break; case(Iex_RdTmp): lhs_name = (HWord)data->Iex.RdTmp.tmp; d = unsafeIRDirty_0_N(0, "EmitPutTmpHelper", &EmitPutTmpHelper, mkIRExprVec_3(mkIRExpr_HWord(h_offset), mkIRExpr_HWord(lhs_name), mkIRExpr_HWord(counter) ) ); setHelperAnns(d); addStmtToIRSB(sb, IRStmt_Dirty(d)); break; default: break; } return; }
void instrument_Store(IRStmt* st, IRSB* sb_out) { IRExpr* addr = st->Ist.Store.addr; IRExpr* data = st->Ist.Store.data; Int size = sizeofIRType_bits(typeOfIRExpr(sb_out->tyenv, st->Ist.Store.data)); IRDirty* di; tl_assert(isIRAtom(addr)); tl_assert(isIRAtom(data)); if (addr->tag == Iex_Const) tl_assert(addr->Iex.Const.con->tag == Ico_U32); // the data transfer type is the type of data di = unsafeIRDirty_0_N(0, "helper_instrument_Store", VG_(fnptr_to_fnentry)(helper_instrument_Store), mkIRExprVec_3((addr->tag == Iex_RdTmp) ? assignNew_HWord(sb_out, addr) : mkIRExpr_HWord(addr->Iex.Const.con->Ico.U32), mkIRExpr_HWord((data->tag == Iex_RdTmp) ? data->Iex.RdTmp.tmp : IRTemp_INVALID), mkIRExpr_HWord(size)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); }
void instrument_WrTmp_Load(IRStmt* st, IRSB* sb_out) { IRTemp tmp = st->Ist.WrTmp.tmp; IRExpr* data = st->Ist.WrTmp.data; IRExpr* addr = data->Iex.Load.addr; Int size = sizeofIRType_bits(data->Iex.Load.ty); IRDirty* di; tl_assert(isIRAtom(addr)); if (addr->tag == Iex_Const) tl_assert(addr->Iex.Const.con->tag == Ico_U32); tl_assert(typeOfIRTemp(sb_out->tyenv, tmp) == data->Iex.Load.ty); di = unsafeIRDirty_0_N(0, "helper_instrument_WrTmp_Load", VG_(fnptr_to_fnentry)(helper_instrument_WrTmp_Load), mkIRExprVec_3(mkIRExpr_HWord(tmp), (addr->tag == Iex_RdTmp) ? assignNew_HWord(sb_out, addr) : mkIRExpr_HWord(addr->Iex.Const.con->Ico.U32), mkIRExpr_HWord(size)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); }
void instrument_WrTmp_Const(IRStmt* st, IRSB* sb_out) { IRTemp tmp = st->Ist.WrTmp.tmp; IRDirty* di; di = unsafeIRDirty_0_N(0, "helper_instrument_WrTmp_Const", VG_(fnptr_to_fnentry)(helper_instrument_WrTmp_Const), mkIRExprVec_1(mkIRExpr_HWord(tmp)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); }
static void flushEvents(IRSB* sb) { Int i; Char* helperName; void* helperAddr; IRExpr** argv; IRDirty* di; Event* ev; for (i = 0; i < events_used; i++) { ev = &events[i]; // Decide on helper fn to call and args to pass it. switch (ev->ekind) { case Event_Ir: /*helperName = "trace_instr"; helperAddr = trace_instr;*/ continue;break; case Event_Dr: helperName = "trace_load"; helperAddr = trace_load; break; case Event_Dw: helperName = "trace_store"; helperAddr = trace_store; break; case Event_Dm: helperName = "trace_modify"; helperAddr = trace_modify; break; default: tl_assert(0); } // Add the helper. argv = mkIRExprVec_3( mkIRExpr_HWord( (HWord) ev->fnname ), ev->addr, mkIRExpr_HWord( ev->size ) ); di = unsafeIRDirty_0_N( /*regparms*/3, helperName, VG_(fnptr_to_fnentry)( helperAddr ), argv ); addStmtToIRSB( sb, IRStmt_Dirty(di) ); } events_used = 0; }
/* The GetI expression is used to read guest registers which identity is not known until run time, i.e. not the registers we are shadowing (in principle), no harm in verifying though. */ void instrument_WrTmp_GetI(IRStmt* st, IRSB* sb_out) { IRExpr* data = st->Ist.WrTmp.data; IRRegArray* descr = data->Iex.GetI.descr; Int base = descr->base; Int nElems = descr->nElems; IRExpr* ix = data->Iex.GetI.ix; Int bias = data->Iex.GetI.bias; IRDirty* di; tl_assert(ix->tag == Iex_RdTmp); di = unsafeIRDirty_0_N(0, "helper_instrument_WrTmp_GetI", VG_(fnptr_to_fnentry)(helper_instrument_WrTmp_GetI), mkIRExprVec_4(mkIRExpr_HWord(base), assignNew_HWord(sb_out, ix), mkIRExpr_HWord(bias), mkIRExpr_HWord(nElems)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); }
static void mkCall(IRSB* sb, EventKind ev, IRStmt* stmt, IRExpr* addr) { const HChar* helperName; void* helperAddr; IRExpr** argv = NULL; IRDirty* di = NULL; // Decide on helper fn to call and args to pass it. switch (ev) { case Event_Load: helperName = "trace_load"; helperAddr = trace_load; break; case Event_Store: helperName = "trace_store"; helperAddr = trace_store; break; case Event_Op: helperName = "trace_op"; helperAddr = trace_op; argv = mkIRExprVec_3( mkIRExpr_HWord( (HWord) stmt), mkIRExpr_HWord( 1), mkIRExpr_HWord( 2)); di = unsafeIRDirty_0_N(3, helperName, VG_(fnptr_to_fnentry)( helperAddr ), argv ); break; default: tl_assert(0); } if (!di || !argv) { // Add the helper. argv = mkIRExprVec_3(addr, mkIRExpr_HWord( 0), mkIRExpr_HWord((HWord) stmt)); di = unsafeIRDirty_0_N( 2, helperName, VG_(fnptr_to_fnentry)( helperAddr ), argv ); } IRStmt* a = IRStmt_Dirty(di); addStmtToIRSB( sb, a); }
void instrument_WrTmp_Unop(IRStmt* st, IRSB* sb_out) { IRTemp tmp = st->Ist.WrTmp.tmp; IRExpr* data = st->Ist.WrTmp.data; IROp op = data->Iex.Unop.op; IRExpr* arg = data->Iex.Unop.arg; IRExpr* expr = IRExpr_Unop(op, arg); Int size = sizeofIRType_bits(typeOfIRExpr(sb_out->tyenv, expr)); IRDirty* di; tl_assert(isIRAtom(arg)); tl_assert(typeOfIRTemp(sb_out->tyenv, tmp) == typeOfIRExpr(sb_out->tyenv, expr)); di = unsafeIRDirty_0_N(0, "helper_instrument_WrTmp_Unop", VG_(fnptr_to_fnentry)(helper_instrument_WrTmp_Unop), mkIRExprVec_4(mkIRExpr_HWord(tmp), mkIRExpr_HWord((arg->tag == Iex_RdTmp) ? arg->Iex.RdTmp.tmp : IRTemp_INVALID), mkIRExpr_HWord(op), mkIRExpr_HWord(size)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); }
static void instrument_store(IRSB* const bb, IRExpr* const addr_expr, const HWord size) { IRExpr* size_expr; IRExpr** argv; IRDirty* di; switch (size) { case 1: argv = mkIRExprVec_1(addr_expr); di = unsafeIRDirty_0_N(/*regparms*/1, "drd_trace_store_1", VG_(fnptr_to_fnentry)(drd_trace_store_1), argv); break; case 2: argv = mkIRExprVec_1(addr_expr); di = unsafeIRDirty_0_N(/*regparms*/1, "drd_trace_store_2", VG_(fnptr_to_fnentry)(drd_trace_store_2), argv); break; case 4: argv = mkIRExprVec_1(addr_expr); di = unsafeIRDirty_0_N(/*regparms*/1, "drd_trace_store_4", VG_(fnptr_to_fnentry)(drd_trace_store_4), argv); break; case 8: argv = mkIRExprVec_1(addr_expr); di = unsafeIRDirty_0_N(/*regparms*/1, "drd_trace_store_8", VG_(fnptr_to_fnentry)(drd_trace_store_8), argv); break; default: size_expr = mkIRExpr_HWord(size); argv = mkIRExprVec_2(addr_expr, size_expr); di = unsafeIRDirty_0_N(/*regparms*/2, "drd_trace_store", VG_(fnptr_to_fnentry)(drd_trace_store), argv); break; } addStmtToIRSB(bb, IRStmt_Dirty(di)); }
void instrument_LLSC_Store_Conditional(IRStmt* st, IRSB* sb_out) { IRTemp result = st->Ist.LLSC.result; IRExpr* addr = st->Ist.LLSC.addr; IRExpr* storedata = st->Ist.LLSC.storedata; Int size = sizeofIRType_bits(typeOfIRExpr(sb_out->tyenv, storedata)); IRExpr* result_expr = IRExpr_RdTmp(result); IRDirty* di; tl_assert(isIRAtom(addr)); tl_assert(isIRAtom(storedata)); if (addr->tag == Iex_Const) tl_assert(addr->Iex.Const.con->tag == Ico_U32); // the data transfer type is the type of storedata di = unsafeIRDirty_0_N(0, "helper_instrument_LLSC_Store_Conditional", VG_(fnptr_to_fnentry)(helper_instrument_LLSC_Store_Conditional), mkIRExprVec_4((addr->tag == Iex_RdTmp) ? assignNew_HWord(sb_out, addr) : mkIRExpr_HWord(addr->Iex.Const.con->Ico.U32), mkIRExpr_HWord((storedata->tag == Iex_RdTmp) ? storedata->Iex.RdTmp.tmp : IRTemp_INVALID), mkIRExpr_HWord(size), assignNew_HWord(sb_out, result_expr)) ); addStmtToIRSB(sb_out, IRStmt_Dirty(di)); }
/* A helper that adds the instrumentation for a detail. */ static void instrument_detail(IRSB* sb, Op op, IRType type) { IRDirty* di; IRExpr** argv; const UInt typeIx = type2index(type); tl_assert(op < N_OPS); tl_assert(typeIx < N_TYPES); argv = mkIRExprVec_1( mkIRExpr_HWord( (HWord)&detailCounts[op][typeIx] ) ); di = unsafeIRDirty_0_N( 1, "increment_detail", VG_(fnptr_to_fnentry)( &increment_detail ), argv); addStmtToIRSB( sb, IRStmt_Dirty(di) ); }
static void addEvent_FnEntry ( IRSB* sb, char *fnname) { IRExpr** argv; IRDirty* di; char *buf = (char *)VG_(malloc)("addEvent_FnEntry",100*sizeof(char)); tl_assert(buf!=NULL); VG_(strcpy)(buf,fnname); argv = mkIRExprVec_1( mkIRExpr_HWord( (HWord) buf )); di = unsafeIRDirty_0_N( /*regparms*/1, "trace_fnentry", VG_(fnptr_to_fnentry)( trace_fnentry ), argv ); if(events_used > 0) flushEvents(sb); addStmtToIRSB( sb, IRStmt_Dirty(di) ); }
//----------------------------------------------------------------- static void instrument_Unop(IRSB* sb, IRStmt* st, Addr64 cia) { Char thisFct[]="instrument_Unop"; IRExpr *op = st->Ist.WrTmp.data; IROp irop=op->Iex.Unop.op; void* f=callbackFromIROp(irop); if (f == NULL) return; OA_InstrumentContext inscon=contextFor(cia, irop); if (not_worth_watching(inscon)) return; // filter events that can't be attached to source-code location updateStats(inscon->op); IRExpr* oa_event_expr = mkIRExpr_HWord( (HWord)inscon ); IRExpr * args[2]; packToI32orI64(sb, op->Iex.Unop.arg, args, irop); IRExpr** argv = mkIRExprVec_2(args[0], oa_event_expr); IRDirty* di = unsafeIRDirty_0_N( 2, thisFct, VG_(fnptr_to_fnentry)( f ), argv); addStmtToIRSB( sb, IRStmt_Dirty(di) ); }
static void instrument_store(IRSB* const bb, IRExpr* const addr_expr, const HWord size) { IRExpr* size_expr; IRExpr** argv; IRDirty* di; if (UNLIKELY(drd_any_address_is_traced())) { addStmtToIRSB(bb, IRStmt_Dirty( unsafeIRDirty_0_N(/*regparms*/2, "drd_trace_store", VG_(fnptr_to_fnentry) (drd_trace_mem_store), mkIRExprVec_2(addr_expr, mkIRExpr_HWord(size))))); } if (! s_drd_check_stack_accesses && is_stack_access(bb, addr_expr)) return; switch (size) { case 1: argv = mkIRExprVec_1(addr_expr); di = unsafeIRDirty_0_N(/*regparms*/1, "drd_trace_store_1", VG_(fnptr_to_fnentry)(drd_trace_store_1), argv); break; case 2: argv = mkIRExprVec_1(addr_expr); di = unsafeIRDirty_0_N(/*regparms*/1, "drd_trace_store_2", VG_(fnptr_to_fnentry)(drd_trace_store_2), argv); break; case 4: argv = mkIRExprVec_1(addr_expr); di = unsafeIRDirty_0_N(/*regparms*/1, "drd_trace_store_4", VG_(fnptr_to_fnentry)(drd_trace_store_4), argv); break; case 8: argv = mkIRExprVec_1(addr_expr); di = unsafeIRDirty_0_N(/*regparms*/1, "drd_trace_store_8", VG_(fnptr_to_fnentry)(drd_trace_store_8), argv); break; default: size_expr = mkIRExpr_HWord(size); argv = mkIRExprVec_2(addr_expr, size_expr); di = unsafeIRDirty_0_N(/*regparms*/2, "drd_trace_store", VG_(fnptr_to_fnentry)(drd_trace_store), argv); break; } addStmtToIRSB(bb, IRStmt_Dirty(di)); }
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 void flushEvents ( CgState* cgs ) { Int i, regparms; Char* helperName; void* helperAddr; IRExpr** argv; IRExpr* i_node_expr; IRDirty* di; Event* ev; Event* ev2; Event* ev3; i = 0; while (i < cgs->events_used) { helperName = NULL; helperAddr = NULL; argv = NULL; regparms = 0; /* generate IR to notify event i and possibly the ones immediately following it. */ tl_assert(i >= 0 && i < cgs->events_used); ev = &cgs->events[i]; ev2 = ( i < cgs->events_used-1 ? &cgs->events[i+1] : NULL ); ev3 = ( i < cgs->events_used-2 ? &cgs->events[i+2] : NULL ); if (DEBUG_CG) { VG_(printf)(" flush "); showEvent( ev ); } i_node_expr = mkIRExpr_HWord( (HWord)ev->inode ); /* Decide on helper fn to call and args to pass it, and advance i appropriately. */ switch (ev->ekind) { case Event_Ir: /* Merge with a following Dr/Dm if it is from this insn. */ if (ev2 && (ev2->ekind == Event_Dr || ev2->ekind == Event_Dm)) { tl_assert(ev2->inode == ev->inode); helperName = "log_1I_1Dr_cache_access"; helperAddr = &log_1I_1Dr_cache_access; argv = mkIRExprVec_3( i_node_expr, ev2->dataEA, mkIRExpr_HWord( ev2->datasize ) ); regparms = 3; i += 2; } /* Merge with a following Dw if it is from this insn. */ else if (ev2 && ev2->ekind == Event_Dw) { tl_assert(ev2->inode == ev->inode); helperName = "log_1I_1Dw_cache_access"; helperAddr = &log_1I_1Dw_cache_access; argv = mkIRExprVec_3( i_node_expr, ev2->dataEA, mkIRExpr_HWord( ev2->datasize ) ); regparms = 3; i += 2; } /* Merge with two following Irs if possible. */ else if (ev2 && ev3 && ev2->ekind == Event_Ir && ev3->ekind == Event_Ir) { helperName = "log_3I_0D_cache_access"; helperAddr = &log_3I_0D_cache_access; argv = mkIRExprVec_3( i_node_expr, mkIRExpr_HWord( (HWord)ev2->inode ), mkIRExpr_HWord( (HWord)ev3->inode ) ); regparms = 3; i += 3; } /* Merge with a following Ir if possible. */ else if (ev2 && ev2->ekind == Event_Ir) { helperName = "log_2I_0D_cache_access"; helperAddr = &log_2I_0D_cache_access; argv = mkIRExprVec_2( i_node_expr, mkIRExpr_HWord( (HWord)ev2->inode ) ); regparms = 2; i += 2; } /* No merging possible; emit as-is. */ else { // Assertion: this Event_Ir must be the last one in the // events buffer, otherwise it would have been merged with a // following event. tl_assert(!ev2 && !ev3); helperName = "log_1I_0D_cache_access"; helperAddr = &log_1I_0D_cache_access; argv = mkIRExprVec_1( i_node_expr ); regparms = 1; i++; } break; case Event_Dr: case Event_Dm: helperName = "log_0I_1Dr_cache_access"; helperAddr = &log_0I_1Dr_cache_access; argv = mkIRExprVec_3( i_node_expr, ev->dataEA, mkIRExpr_HWord( ev->datasize ) ); regparms = 3; i++; break; case Event_Dw: helperName = "log_0I_1Dw_cache_access"; helperAddr = &log_0I_1Dw_cache_access; argv = mkIRExprVec_3( i_node_expr, ev->dataEA, mkIRExpr_HWord( ev->datasize ) ); regparms = 3; i++; break; default: tl_assert(0); } /* Add the helper. */ tl_assert(helperName); tl_assert(helperAddr); tl_assert(argv); di = unsafeIRDirty_0_N( regparms, helperName, helperAddr, argv); addStmtToIRBB( cgs->bbOut, IRStmt_Dirty(di) ); } cgs->events_used = 0; }
static IRBB* CLG_(instrument)( VgCallbackClosure* closure, IRBB* bbIn, VexGuestLayout* layout, VexGuestExtents* vge, IRType gWordTy, IRType hWordTy ) { Int i; IRBB* bbOut; IRStmt* st, *stnext; Addr instrAddr, origAddr; UInt instrLen = 0, dataSize; UInt instrCount, costOffset; IRExpr *loadAddrExpr, *storeAddrExpr; BB* bb; IRDirty* di; IRExpr *arg1, **argv; Bool bb_seen_before = False; UInt cJumps = 0, cJumpsCorrected; Bool beforeIBoundary, instrIssued; if (gWordTy != hWordTy) { /* We don't currently support this case. */ VG_(tool_panic)("host/guest word size mismatch"); } // No instrumentation if it is switched off if (! CLG_(instrument_state)) { CLG_DEBUG(5, "instrument(BB %p) [Instrumentation OFF]\n", (Addr)closure->readdr); return bbIn; } CLG_DEBUG(3, "+ instrument(BB %p)\n", (Addr)closure->readdr); /* Set up BB for instrumented IR */ bbOut = emptyIRBB(); bbOut->tyenv = dopyIRTypeEnv(bbIn->tyenv); bbOut->next = dopyIRExpr(bbIn->next); bbOut->jumpkind = bbIn->jumpkind; // Copy verbatim any IR preamble preceding the first IMark i = 0; while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) { addStmtToIRBB( bbOut, bbIn->stmts[i] ); i++; } // Get the first statement, and origAddr from it CLG_ASSERT(bbIn->stmts_used > 0); st = bbIn->stmts[i]; CLG_ASSERT(Ist_IMark == st->tag); instrAddr = origAddr = (Addr)st->Ist.IMark.addr; CLG_ASSERT(origAddr == st->Ist.IMark.addr); // XXX: check no overflow /* Get BB (creating if necessary). * JS: The hash table is keyed with orig_addr_noredir -- important! * JW: Why? If it is because of different chasing of the redirection, * this is not needed, as chasing is switched off in callgrind */ bb = CLG_(get_bb)(origAddr, bbIn, &bb_seen_before); //bb = CLG_(get_bb)(orig_addr_noredir, bbIn, &bb_seen_before); /* * Precondition: * - jmps_passed has number of cond.jumps passed in last executed BB * - current_bbcc has a pointer to the BBCC of the last executed BB * Thus, if bbcc_jmpkind is != -1 (JmpNone), * current_bbcc->bb->jmp_addr * gives the address of the jump source. * * The BBCC setup does 2 things: * - trace call: * * Unwind own call stack, i.e sync our ESP with real ESP * This is for ESP manipulation (longjmps, C++ exec handling) and RET * * For CALLs or JMPs crossing objects, record call arg + * push are on own call stack * * - prepare for cache log functions: * Set current_bbcc to BBCC that gets the costs for this BB execution * attached */ // helper call to setup_bbcc, with pointer to basic block info struct as argument arg1 = mkIRExpr_HWord( (HWord)bb ); argv = mkIRExprVec_1(arg1); di = unsafeIRDirty_0_N( 1, "setup_bbcc", VG_(fnptr_to_fnentry)( & CLG_(setup_bbcc) ), argv); addStmtToIRBB( bbOut, IRStmt_Dirty(di) ); instrCount = 0; costOffset = 0; // loop for each host instruction (starting from 'i') do { // We should be at an IMark statement CLG_ASSERT(Ist_IMark == st->tag); // Reset stuff for this original instruction loadAddrExpr = storeAddrExpr = NULL; instrIssued = False; dataSize = 0; // Process all the statements for this original instruction (ie. until // the next IMark statement, or the end of the block) do { i++; stnext = ( i < bbIn->stmts_used ? bbIn->stmts[i] : NULL ); beforeIBoundary = !stnext || (Ist_IMark == stnext->tag); collectStatementInfo(bbIn->tyenv, bbOut, st, &instrAddr, &instrLen, &loadAddrExpr, &storeAddrExpr, &dataSize, hWordTy); // instrument a simulator call before conditional jumps if (st->tag == Ist_Exit) { // Nb: instrLen will be zero if Vex failed to decode it. // Also Client requests can appear to be very large (eg. 18 // bytes on x86) because they are really multiple instructions. CLG_ASSERT( 0 == instrLen || bbIn->jumpkind == Ijk_ClientReq || (instrLen >= VG_MIN_INSTR_SZB && instrLen <= VG_MAX_INSTR_SZB) ); // Add instrumentation before this statement endOfInstr(bbOut, &(bb->instr[instrCount]), bb_seen_before, instrAddr - origAddr, instrLen, dataSize, &costOffset, instrIssued, loadAddrExpr, storeAddrExpr); // prepare for a possible further simcall in same host instr loadAddrExpr = storeAddrExpr = NULL; instrIssued = True; if (!bb_seen_before) { bb->jmp[cJumps].instr = instrCount; bb->jmp[cJumps].skip = False; } /* Update global variable jmps_passed (this is before the jump!) * A correction is needed if VEX inverted the last jump condition */ cJumpsCorrected = cJumps; if ((cJumps+1 == bb->cjmp_count) && bb->cjmp_inverted) cJumpsCorrected++; addConstMemStoreStmt( bbOut, (UWord) &CLG_(current_state).jmps_passed, cJumpsCorrected, hWordTy); cJumps++; } addStmtToIRBB( bbOut, st ); st = stnext; } while (!beforeIBoundary); // Add instrumentation for this original instruction. if (!instrIssued || (loadAddrExpr != 0) || (storeAddrExpr !=0)) endOfInstr(bbOut, &(bb->instr[instrCount]), bb_seen_before, instrAddr - origAddr, instrLen, dataSize, &costOffset, instrIssued, loadAddrExpr, storeAddrExpr); instrCount++; } while (st); /* Always update global variable jmps_passed (at end of BB) * A correction is needed if VEX inverted the last jump condition */ cJumpsCorrected = cJumps; if (bb->cjmp_inverted) cJumpsCorrected--; addConstMemStoreStmt( bbOut, (UWord) &CLG_(current_state).jmps_passed, cJumpsCorrected, hWordTy); /* This stores the instr of the call/ret at BB end */ bb->jmp[cJumps].instr = instrCount-1; CLG_ASSERT(bb->cjmp_count == cJumps); CLG_ASSERT(bb->instr_count == instrCount); instrAddr += instrLen; if (bb_seen_before) { CLG_ASSERT(bb->instr_len == instrAddr - origAddr); CLG_ASSERT(bb->cost_count == costOffset); CLG_ASSERT(bb->jmpkind == bbIn->jumpkind); } else { bb->instr_len = instrAddr - origAddr; bb->cost_count = costOffset; bb->jmpkind = bbIn->jumpkind; } CLG_DEBUG(3, "- instrument(BB %p): byteLen %u, CJumps %u, CostLen %u\n", origAddr, bb->instr_len, bb->cjmp_count, bb->cost_count); if (cJumps>0) { CLG_DEBUG(3, " [ "); for (i=0; i<cJumps; i++) CLG_DEBUG(3, "%d ", bb->jmp[i].instr); CLG_DEBUG(3, "], last inverted: %s \n", bb->cjmp_inverted ? "yes":"no"); } return bbOut; }