Exemple #1
0
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; 
}
Exemple #3
0
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));
}
Exemple #4
0
/* 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;
} 
Exemple #6
0
/*
    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));
    }
}
Exemple #7
0
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) );
}
Exemple #8
0
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));
}
Exemple #9
0
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));
}
Exemple #10
0
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));
}
Exemple #11
0
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;
}
Exemple #12
0
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));
}
Exemple #13
0
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));
}
Exemple #14
0
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;    
}
Exemple #15
0
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));
}
Exemple #16
0
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));
}
Exemple #17
0
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));
}
Exemple #18
0
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;
}
Exemple #19
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));
}
Exemple #20
0
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);
}
Exemple #21
0
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));
}
Exemple #22
0
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));
}
Exemple #23
0
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));
}
Exemple #24
0
/* 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) );
}
Exemple #25
0
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) );
}
Exemple #26
0
//-----------------------------------------------------------------
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) );
}
Exemple #27
0
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));
}
Exemple #28
0
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;
}
Exemple #30
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;
}