Пример #1
0
static
ARMAMode2* genGuestArrayOffset ( ISelEnv* env, IRRegArray* descr, 
				 IRExpr* off, Int bias )
{
   HReg tmp, tmp2, roff;
   Int  elemSz = sizeofIRType(descr->elemTy);
   Int  nElems = descr->nElems;
   ARMImm12A imm12a;

   /* throw out any cases not generated by an x86 front end.  In
      theory there might be a day where we need to handle them -- if
      we ever run non-x86-guest on x86 host. */

   if (nElems != 8 || (elemSz != 1 && elemSz != 8))
      vpanic("genGuestArrayOffset(arm host)");

   /* Compute off into a reg, %off.  Then return:

         movl %off, %tmp
         addl $bias, %tmp  (if bias != 0)
         andl %tmp, 7
         ... base(%ebp, %tmp, shift) ...
   */
   tmp  = newVRegI(env);
   roff = iselIntExpr_R(env, off);
   addInstr(env, mk_iMOVsd_RR(roff, tmp));
   if (bias != 0) {
       if ( mk_ARMImm12A( (UInt)bias, &imm12a ) ) {
	   addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD, tmp, tmp,
					   ARMAMode1_I12A( imm12a )));
       } else {
	   HReg tmp3 = newVRegI(env);
	   addInstr(env, ARMInstr_Literal( tmp, (UInt)bias ));
	   addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD, tmp, tmp,
					   ARMAMode1_ShlI( tmp3, 0 )));
       }
   }

   mk_ARMImm12A( (UInt)7, &imm12a );
   addInstr(env, ARMInstr_DPInstr2(ARMalu_AND, tmp, tmp,
				   ARMAMode1_I12A( imm12a )));
   vassert(elemSz == 1 || elemSz == 8);



// CAB: This anywhere near correct?

// X86AMode_IRRS: Immediate + Reg1 + (Reg2 << Shift)
// return X86AMode_IRRS( descr->base, hregX86_EBP(), tmp, elemSz==8 ? 3 : 0);

   tmp2 = newVRegI(env);  // tmp2 = GET_BP_REG + (tmp << 3|0)
   addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD, tmp2, GET_BP_REG(),
				   ARMAMode1_ShlI(tmp, elemSz==8 ? 3 : 0)));
   return ARMAMode2_RI( tmp2, descr->base );
}
Пример #2
0
/* Store a value to memory. If a value requires more than 8 bytes a series
   of 8-byte stores will be generated. */
static __inline__ void
store(IRSB *irsb, IREndness endian, HWord haddr, IRExpr *data)
{
   IROp high, low;
   IRExpr *addr, *next_addr;

   if (VEX_HOST_WORDSIZE == 8) {
      addr = mkU64(haddr);
      next_addr = binop(Iop_Add64, addr, mkU64(8));
   } else if (VEX_HOST_WORDSIZE == 4) {
      addr = mkU32(haddr);
      next_addr = binop(Iop_Add32, addr, mkU32(8));
   } else {
      vpanic("invalid #bytes for address");
   }

   IRType type = typeOfIRExpr(irsb->tyenv, data);

   vassert(type == Ity_I1 || sizeofIRType(type) <= 16);

   switch (type) {
   case Ity_I128: high = Iop_128HIto64;   low = Iop_128to64;     goto store128;
   case Ity_F128: high = Iop_F128HItoF64; low = Iop_F128LOtoF64; goto store128;
   case Ity_D128: high = Iop_D128HItoD64; low = Iop_D128LOtoD64; goto store128;

   store128:
     /* Two stores of 64 bit each. */
      if (endian == Iend_BE) {
         /* The more significant bits are at the lower address. */
         store_aux(irsb, endian, addr, unop(high, data));
         store_aux(irsb, endian, next_addr, unop(low, data));
      } else {
         /* The more significant bits are at the higher address. */
         store_aux(irsb, endian, addr, unop(low, data));
         store_aux(irsb, endian, next_addr, unop(high, data));
      }
      return;

   default:
      store_aux(irsb, endian, addr, data);
      return;
   }
}
Пример #3
0
/* Load a value from memory. Loads of more than 8 byte are split into
   a series of 8-byte loads and combined using appropriate IROps. */
static IRExpr *
load(IREndness endian, IRType type, HWord haddr)
{
   IROp concat;
   IRExpr *addr, *next_addr;

   vassert(type == Ity_I1 || sizeofIRType(type) <= 16);

   if (VEX_HOST_WORDSIZE == 8) {
      addr = mkU64(haddr);
      next_addr = binop(Iop_Add64, addr, mkU64(8));
   } else if (VEX_HOST_WORDSIZE == 4) {
      addr = mkU32(haddr);
      next_addr = binop(Iop_Add32, addr, mkU32(8));
   } else {
      vpanic("invalid #bytes for address");
   }

   switch (type) {
   case Ity_I128: concat = Iop_64HLto128;   type = Ity_I64; goto load128;
   case Ity_F128: concat = Iop_F64HLtoF128; type = Ity_F64; goto load128;
   case Ity_D128: concat = Iop_D64HLtoD128; type = Ity_D64; goto load128;

   load128:
     /* Two loads of 64 bit each. */
      if (endian == Iend_BE) {
         /* The more significant bits are at the lower address. */
         return binop(concat,
                      load_aux(endian, type, addr),
                      load_aux(endian, type, next_addr));
      } else {
         /* The more significant bits are at the higher address. */
         return binop(concat,
                      load_aux(endian, type, next_addr),
                      load_aux(endian, type, addr));
      }

   default:
      return load_aux(endian, type, addr);
   }
}
Пример #4
0
unsigned
sizeof_irtype(IRType ty)
{
   return sizeofIRType(ty);
}
Пример #5
0
static
void collectStatementInfo(IRTypeEnv* tyenv, IRBB* bbOut, IRStmt* st,
                          Addr* instrAddr, UInt* instrLen,
                          IRExpr** loadAddrExpr, IRExpr** storeAddrExpr,
                          UInt* dataSize, IRType hWordTy)
{
    CLG_ASSERT(isFlatIRStmt(st));

    switch (st->tag) {
    case Ist_NoOp:
        break;

    case Ist_AbiHint:
        /* ABI hints aren't interesting.  Ignore. */
        break;

    case Ist_IMark:
        /* st->Ist.IMark.addr is a 64-bit int.  ULong_to_Ptr casts this
           to the host's native pointer type; if that is 32 bits then it
           discards the upper 32 bits.  If we are cachegrinding on a
           32-bit host then we are also ensured that the guest word size
           is 32 bits, due to the assertion in cg_instrument that the
           host and guest word sizes must be the same.  Hence
           st->Ist.IMark.addr will have been derived from a 32-bit guest
           code address and truncation of it is safe.  I believe this
           assignment should be correct for both 32- and 64-bit
           machines. */
        *instrAddr = (Addr)ULong_to_Ptr(st->Ist.IMark.addr);
        *instrLen =        st->Ist.IMark.len;
        break;

    case Ist_Tmp: {
        IRExpr* data = st->Ist.Tmp.data;
        if (data->tag == Iex_Load) {
            IRExpr* aexpr = data->Iex.Load.addr;
            CLG_ASSERT( isIRAtom(aexpr) );
            // Note also, endianness info is ignored.  I guess that's not
            // interesting.
            // XXX: repe cmpsb does two loads... the first one is ignored here!
            //tl_assert( NULL == *loadAddrExpr );          // XXX: ???
            *loadAddrExpr = aexpr;
            *dataSize = sizeofIRType(data->Iex.Load.ty);
        }
        break;
    }

    case Ist_Store: {
        IRExpr* data  = st->Ist.Store.data;
        IRExpr* aexpr = st->Ist.Store.addr;
        CLG_ASSERT( isIRAtom(aexpr) );
        if ( NULL == *storeAddrExpr ) {
            /* this is a kludge: ignore all except the first store from
               an instruction. */
            *storeAddrExpr = aexpr;
            *dataSize = sizeofIRType(typeOfIRExpr(tyenv, data));
        }
        break;
    }

    case Ist_Dirty: {
        IRDirty* d = st->Ist.Dirty.details;
        if (d->mFx != Ifx_None) {
            /* This dirty helper accesses memory.  Collect the
               details. */
            CLG_ASSERT(d->mAddr != NULL);
            CLG_ASSERT(d->mSize != 0);
            *dataSize = d->mSize;
            if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
                *loadAddrExpr = d->mAddr;
            if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
                *storeAddrExpr = d->mAddr;
        } else {
            CLG_ASSERT(d->mAddr == NULL);
            CLG_ASSERT(d->mSize == 0);
        }
        break;
    }

    case Ist_Put:
    case Ist_PutI:
    case Ist_MFence:
    case Ist_Exit:
        break;

    default:
        VG_(printf)("\n");
        ppIRStmt(st);
        VG_(printf)("\n");
        VG_(tool_panic)("Callgrind: unhandled IRStmt");
    }
}
Пример #6
0
static
IRSB* lk_instrument ( VgCallbackClosure* closure,
                      IRSB* sbIn,
                      VexGuestLayout* layout,
                      VexGuestExtents* vge,
                      VexArchInfo* archinfo_host,
                      IRType gWordTy, IRType hWordTy )
{
   IRDirty*   di;
   Int        i;
   IRSB*      sbOut;
   HChar      fnname[100];
   IRTypeEnv* tyenv = sbIn->tyenv;
   Addr       iaddr = 0, dst;
   UInt       ilen = 0;
   Bool       condition_inverted = False;

   if (gWordTy != hWordTy) {
      /* We don't currently support this case. */
      VG_(tool_panic)("host/guest word size mismatch");
   }

   /* Set up SB */
   sbOut = deepCopyIRSBExceptStmts(sbIn);

   // Copy verbatim any IR preamble preceding the first IMark
   i = 0;
   while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
      addStmtToIRSB( sbOut, sbIn->stmts[i] );
      i++;
   }

   if (clo_basic_counts) {
      /* Count this superblock. */
      di = unsafeIRDirty_0_N( 0, "add_one_SB_entered",
                                 VG_(fnptr_to_fnentry)( &add_one_SB_entered ),
                                 mkIRExprVec_0() );
      addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
   }

   if (clo_trace_sbs) {
      /* Print this superblock's address. */
      di = unsafeIRDirty_0_N(
              0, "trace_superblock",
              VG_(fnptr_to_fnentry)( &trace_superblock ),
              mkIRExprVec_1( mkIRExpr_HWord( vge->base[0] ) )
           );
      addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
   }

   if (clo_trace_mem) {
      events_used = 0;
   }

   for (/*use current i*/; i < sbIn->stmts_used; i++) {
      IRStmt* st = sbIn->stmts[i];
      if (!st || st->tag == Ist_NoOp) continue;

      if (clo_basic_counts) {
         /* Count one VEX statement. */
         di = unsafeIRDirty_0_N( 0, "add_one_IRStmt",
                                    VG_(fnptr_to_fnentry)( &add_one_IRStmt ),
                                    mkIRExprVec_0() );
         addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
      }

      switch (st->tag) {
         case Ist_NoOp:
         case Ist_AbiHint:
         case Ist_Put:
         case Ist_PutI:
         case Ist_MBE:
            addStmtToIRSB( sbOut, st );
            break;

         case Ist_IMark:
            if (clo_basic_counts) {
               /* Needed to be able to check for inverted condition in Ist_Exit */
               iaddr = st->Ist.IMark.addr;
               ilen  = st->Ist.IMark.len;

               /* Count guest instruction. */
               di = unsafeIRDirty_0_N( 0, "add_one_guest_instr",
                                          VG_(fnptr_to_fnentry)( &add_one_guest_instr ),
                                          mkIRExprVec_0() );
               addStmtToIRSB( sbOut, IRStmt_Dirty(di) );

               /* An unconditional branch to a known destination in the
                * guest's instructions can be represented, in the IRSB to
                * instrument, by the VEX statements that are the
                * translation of that known destination. This feature is
                * called 'SB chasing' and can be influenced by command
                * line option --vex-guest-chase-thresh.
                *
                * To get an accurate count of the calls to a specific
                * function, taking SB chasing into account, we need to
                * check for each guest instruction (Ist_IMark) if it is
                * the entry point of a function.
                */
               tl_assert(clo_fnname);
               tl_assert(clo_fnname[0]);
               if (VG_(get_fnname_if_entry)(st->Ist.IMark.addr,
                                            fnname, sizeof(fnname))
                   && 0 == VG_(strcmp)(fnname, clo_fnname)) {
                  di = unsafeIRDirty_0_N(
                          0, "add_one_func_call",
                             VG_(fnptr_to_fnentry)( &add_one_func_call ),
                             mkIRExprVec_0() );
                  addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
               }
            }
            if (clo_trace_mem) {
               // WARNING: do not remove this function call, even if you
               // aren't interested in instruction reads.  See the comment
               // above the function itself for more detail.
               addEvent_Ir( sbOut, mkIRExpr_HWord( (HWord)st->Ist.IMark.addr ),
                            st->Ist.IMark.len );
            }
            addStmtToIRSB( sbOut, st );
            break;

         case Ist_WrTmp:
            // Add a call to trace_load() if --trace-mem=yes.
            if (clo_trace_mem) {
               IRExpr* data = st->Ist.WrTmp.data;
               if (data->tag == Iex_Load) {
                  addEvent_Dr( sbOut, data->Iex.Load.addr,
                               sizeofIRType(data->Iex.Load.ty) );
               }
            }
            if (clo_detailed_counts) {
               IRExpr* expr = st->Ist.WrTmp.data;
               IRType  type = typeOfIRExpr(sbOut->tyenv, expr);
               tl_assert(type != Ity_INVALID);
               switch (expr->tag) {
                  case Iex_Load:
                    instrument_detail( sbOut, OpLoad, type, NULL/*guard*/ );
                     break;
                  case Iex_Unop:
                  case Iex_Binop:
                  case Iex_Triop:
                  case Iex_Qop:
                  case Iex_ITE:
                     instrument_detail( sbOut, OpAlu, type, NULL/*guard*/ );
                     break;
                  default:
                     break;
               }
            }
            addStmtToIRSB( sbOut, st );
            break;

         case Ist_Store: {
            IRExpr* data = st->Ist.Store.data;
            IRType  type = typeOfIRExpr(tyenv, data);
            tl_assert(type != Ity_INVALID);
            if (clo_trace_mem) {
               addEvent_Dw( sbOut, st->Ist.Store.addr,
                            sizeofIRType(type) );
            }
            if (clo_detailed_counts) {
               instrument_detail( sbOut, OpStore, type, NULL/*guard*/ );
            }
            addStmtToIRSB( sbOut, st );
            break;
         }

         case Ist_StoreG: {
            IRStoreG* sg   = st->Ist.StoreG.details;
            IRExpr*   data = sg->data;
            IRType    type = typeOfIRExpr(tyenv, data);
            tl_assert(type != Ity_INVALID);
            if (clo_trace_mem) {
               addEvent_Dw_guarded( sbOut, sg->addr,
                                    sizeofIRType(type), sg->guard );
            }
            if (clo_detailed_counts) {
               instrument_detail( sbOut, OpStore, type, sg->guard );
            }
            addStmtToIRSB( sbOut, st );
            break;
         }

         case Ist_LoadG: {
            IRLoadG* lg       = st->Ist.LoadG.details;
            IRType   type     = Ity_INVALID; /* loaded type */
            IRType   typeWide = Ity_INVALID; /* after implicit widening */
            typeOfIRLoadGOp(lg->cvt, &typeWide, &type);
            tl_assert(type != Ity_INVALID);
            if (clo_trace_mem) {
               addEvent_Dr_guarded( sbOut, lg->addr,
                                    sizeofIRType(type), lg->guard );
            }
            if (clo_detailed_counts) {
               instrument_detail( sbOut, OpLoad, type, lg->guard );
            }
            addStmtToIRSB( sbOut, st );
            break;
         }

         case Ist_Dirty: {
            if (clo_trace_mem) {
               Int      dsize;
               IRDirty* d = st->Ist.Dirty.details;
               if (d->mFx != Ifx_None) {
                  // This dirty helper accesses memory.  Collect the details.
                  tl_assert(d->mAddr != NULL);
                  tl_assert(d->mSize != 0);
                  dsize = d->mSize;
                  if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
                     addEvent_Dr( sbOut, d->mAddr, dsize );
                  if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
                     addEvent_Dw( sbOut, d->mAddr, dsize );
               } else {
                  tl_assert(d->mAddr == NULL);
                  tl_assert(d->mSize == 0);
               }
            }
            addStmtToIRSB( sbOut, st );
            break;
         }

         case Ist_CAS: {
            /* We treat it as a read and a write of the location.  I
               think that is the same behaviour as it was before IRCAS
               was introduced, since prior to that point, the Vex
               front ends would translate a lock-prefixed instruction
               into a (normal) read followed by a (normal) write. */
            Int    dataSize;
            IRType dataTy;
            IRCAS* cas = st->Ist.CAS.details;
            tl_assert(cas->addr != NULL);
            tl_assert(cas->dataLo != NULL);
            dataTy   = typeOfIRExpr(tyenv, cas->dataLo);
            dataSize = sizeofIRType(dataTy);
            if (cas->dataHi != NULL)
               dataSize *= 2; /* since it's a doubleword-CAS */
            if (clo_trace_mem) {
               addEvent_Dr( sbOut, cas->addr, dataSize );
               addEvent_Dw( sbOut, cas->addr, dataSize );
            }
            if (clo_detailed_counts) {
               instrument_detail( sbOut, OpLoad, dataTy, NULL/*guard*/ );
               if (cas->dataHi != NULL) /* dcas */
                  instrument_detail( sbOut, OpLoad, dataTy, NULL/*guard*/ );
               instrument_detail( sbOut, OpStore, dataTy, NULL/*guard*/ );
               if (cas->dataHi != NULL) /* dcas */
                  instrument_detail( sbOut, OpStore, dataTy, NULL/*guard*/ );
            }
            addStmtToIRSB( sbOut, st );
            break;
         }

         case Ist_LLSC: {
            IRType dataTy;
            if (st->Ist.LLSC.storedata == NULL) {
               /* LL */
               dataTy = typeOfIRTemp(tyenv, st->Ist.LLSC.result);
               if (clo_trace_mem) {
                  addEvent_Dr( sbOut, st->Ist.LLSC.addr,
                                      sizeofIRType(dataTy) );
                  /* flush events before LL, helps SC to succeed */
                  flushEvents(sbOut);
	       }
               if (clo_detailed_counts)
                  instrument_detail( sbOut, OpLoad, dataTy, NULL/*guard*/ );
            } else {
               /* SC */
               dataTy = typeOfIRExpr(tyenv, st->Ist.LLSC.storedata);
               if (clo_trace_mem)
                  addEvent_Dw( sbOut, st->Ist.LLSC.addr,
                                      sizeofIRType(dataTy) );
               if (clo_detailed_counts)
                  instrument_detail( sbOut, OpStore, dataTy, NULL/*guard*/ );
            }
            addStmtToIRSB( sbOut, st );
            break;
         }

         case Ist_Exit:
            if (clo_basic_counts) {
               // The condition of a branch was inverted by VEX if a taken
               // branch is in fact a fall trough according to client address
               tl_assert(iaddr != 0);
               dst = (sizeof(Addr) == 4) ? st->Ist.Exit.dst->Ico.U32 :
                                           st->Ist.Exit.dst->Ico.U64;
               condition_inverted = (dst == iaddr + ilen);

               /* Count Jcc */
               if (!condition_inverted)
                  di = unsafeIRDirty_0_N( 0, "add_one_Jcc",
                                          VG_(fnptr_to_fnentry)( &add_one_Jcc ),
                                          mkIRExprVec_0() );
               else
                  di = unsafeIRDirty_0_N( 0, "add_one_inverted_Jcc",
                                          VG_(fnptr_to_fnentry)(
                                             &add_one_inverted_Jcc ),
                                          mkIRExprVec_0() );

               addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
            }
            if (clo_trace_mem) {
               flushEvents(sbOut);
            }

            addStmtToIRSB( sbOut, st );      // Original statement

            if (clo_basic_counts) {
               /* Count non-taken Jcc */
               if (!condition_inverted)
                  di = unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken",
                                          VG_(fnptr_to_fnentry)(
                                             &add_one_Jcc_untaken ),
                                          mkIRExprVec_0() );
               else
                  di = unsafeIRDirty_0_N( 0, "add_one_inverted_Jcc_untaken",
                                          VG_(fnptr_to_fnentry)(
                                             &add_one_inverted_Jcc_untaken ),
                                          mkIRExprVec_0() );

               addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
            }
            break;

         default:
            ppIRStmt(st);
            tl_assert(0);
      }
   }

   if (clo_basic_counts) {
      /* Count this basic block. */
      di = unsafeIRDirty_0_N( 0, "add_one_SB_completed",
                                 VG_(fnptr_to_fnentry)( &add_one_SB_completed ),
                                 mkIRExprVec_0() );
      addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
   }

   if (clo_trace_mem) {
      /* At the end of the sbIn.  Flush outstandings. */
      flushEvents(sbOut);
   }

   return sbOut;
}
Пример #7
0
static
IRSB* el_instrument ( VgCallbackClosure* closure,
                      IRSB* sbIn,
                      VexGuestLayout* layout,
                      VexGuestExtents* vge,
                      IRType gWordTy, IRType hWordTy )
{
    IRDirty*   di;
    Int        i;
    IRSB*      sbOut;
    Char       fnname[100];
    IRType     type;
    IRTypeEnv* tyenv = sbIn->tyenv;
    Addr       iaddr = 0, dst;
    UInt       ilen = 0;
    Bool       condition_inverted = False;

    if (gWordTy != hWordTy) {
        /* We don't currently support this case. */
        VG_(tool_panic)("host/guest word size mismatch");
    }

    /* Set up SB */
    sbOut = deepCopyIRSBExceptStmts(sbIn);

    // Copy verbatim any IR preamble preceding the first IMark
    i = 0;
    while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
        addStmtToIRSB( sbOut, sbIn->stmts[i] );
        i++;
    }

    events_used = 0;


    for (/*use current i*/; i < sbIn->stmts_used; i++) {
        IRStmt* st = sbIn->stmts[i];
        if (!st || st->tag == Ist_NoOp) continue;



        switch (st->tag) {
        case Ist_NoOp:
        case Ist_AbiHint:
        case Ist_Put:
        case Ist_PutI:
        case Ist_MBE:
            addStmtToIRSB( sbOut, st );
            break;

        case Ist_IMark:

            // Store the last seen address
            lastAddress = st->Ist.IMark.addr;

            addEvent_Ir( sbOut, mkIRExpr_HWord( (HWord)st->Ist.IMark.addr ),
                         st->Ist.IMark.len );

            VG_(get_filename)(lastAddress, (char*) g_buff1, kBuffSize);

            if(VG_(strcmp)(g_buff1, clo_filename) == 0) {
                shouldInterpret = 1;
                ppIRStmt(st);
                VG_(printf)("\n");
            } else {
                shouldInterpret = 0;
            }

            addStmtToIRSB( sbOut, st );
            break;

        case Ist_WrTmp:
            // Add a call to trace_load() if --trace-mem=yes.
        {
            if(shouldInterpret) {
                IRExpr* data = st->Ist.WrTmp.data;
                if (data->tag == Iex_Load) {
                    addEvent_Dr( sbOut, data->Iex.Load.addr,
                                 sizeofIRType(data->Iex.Load.ty) );
                }

            }
            addStmtToIRSB( sbOut, st );
            break;
        }
        case Ist_Store:
        {
            if(shouldInterpret) {
                IRExpr* data  = st->Ist.Store.data;
                addEvent_Dw( sbOut, st->Ist.Store.addr,
                             sizeofIRType(typeOfIRExpr(tyenv, data)) );


            }
            addStmtToIRSB( sbOut, st );
            break;
        }
        case Ist_Dirty:
        {

            if(shouldInterpret) {
                Int      dsize;
                IRDirty* d = st->Ist.Dirty.details;
                if (d->mFx != Ifx_None) {
                    // This dirty helper accesses memory.  Collect the details.
                    tl_assert(d->mAddr != NULL);
                    tl_assert(d->mSize != 0);
                    dsize = d->mSize;
                    if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
                        addEvent_Dr( sbOut, d->mAddr, dsize );
                    if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
                        addEvent_Dw( sbOut, d->mAddr, dsize );
                } else {
                    tl_assert(d->mAddr == NULL);
                    tl_assert(d->mSize == 0);
                }
            }

            addStmtToIRSB( sbOut, st );
            break;
        }

        case Ist_CAS: {
            if(shouldInterpret) {
                Int    dataSize;
                IRType dataTy;
                IRCAS* cas = st->Ist.CAS.details;
                tl_assert(cas->addr != NULL);
                tl_assert(cas->dataLo != NULL);
                dataTy   = typeOfIRExpr(tyenv, cas->dataLo);
                dataSize = sizeofIRType(dataTy);
                if (cas->dataHi != NULL)
                    dataSize *= 2; /* since it's a doubleword-CAS */

                addEvent_Dr( sbOut, cas->addr, dataSize );
                addEvent_Dw( sbOut, cas->addr, dataSize );

            }
            addStmtToIRSB( sbOut, st );
            break;
        }

        case Ist_LLSC: {
            if(shouldInterpret) {
                IRType dataTy;
                if (st->Ist.LLSC.storedata == NULL) {
                    /* LL */
                    dataTy = typeOfIRTemp(tyenv, st->Ist.LLSC.result);

                    addEvent_Dr( sbOut, st->Ist.LLSC.addr,
                                 sizeofIRType(dataTy) );

                } else {
                    /* SC */
                    dataTy = typeOfIRExpr(tyenv, st->Ist.LLSC.storedata);

                    addEvent_Dw( sbOut, st->Ist.LLSC.addr,
                                 sizeofIRType(dataTy) );

                }
            }
            addStmtToIRSB( sbOut, st );
            break;
        }

        case Ist_Exit:
            if(shouldInterpret) {

            }

            flushEvents(sbOut);
            addStmtToIRSB( sbOut, st );      // Original statement
            break;

        default:
            tl_assert(0);
        }
    }


    /* At the end of the sbIn.  Flush outstandings. */
    flushEvents(sbOut);


    return sbOut;
}
Пример #8
0
static 
Bool handleOneStatement(IRTypeEnv* tyenv, IRBB* bbOut, IRStmt* st, IRStmt* st2,
                        Addr* instrAddr, UInt* instrLen,
                        IRExpr** loadAddrExpr, IRExpr** storeAddrExpr,
                        UInt* dataSize)
{
   tl_assert(isFlatIRStmt(st));

   switch (st->tag) {
   case Ist_NoOp:
   case Ist_AbiHint:
   case Ist_Put:
   case Ist_PutI:
   case Ist_MFence:
      break;

   case Ist_Exit: {
      // This is a conditional jump.  Most of the time, we want to add the
      // instrumentation before it, to ensure it gets executed.  Eg, (1) if
      // this conditional jump is just before an IMark:
      //
      //   t108 = Not1(t107)
      //   [add instrumentation here]
      //   if (t108) goto {Boring} 0x3A96637D:I32
      //   ------ IMark(0x3A966370, 7) ------
      //
      // or (2) if this conditional jump is the last thing before the
      // block-ending unconditional jump:
      //
      //   t111 = Not1(t110)
      //   [add instrumentation here]
      //   if (t111) goto {Boring} 0x3A96637D:I32
      //   goto {Boring} 0x3A966370:I32
      //
      // One case (3) where we want the instrumentation after the conditional
      // jump is when the conditional jump is for an x86 REP instruction:
      //
      //   ------ IMark(0x3A967F13, 2) ------
      //   t1 = GET:I32(4)
      //   t6 = CmpEQ32(t1,0x0:I32) 
      //   if (t6) goto {Boring} 0x3A967F15:I32    # ignore this cond jmp
      //   t7 = Sub32(t1,0x1:I32)
      //   PUT(4) = t7
      //   ...
      //   t56 = Not1(t55)
      //   [add instrumentation here]
      //   if (t56) goto {Boring} 0x3A967F15:I32
      //
      // Therefore, we return true if the next statement is an IMark, or if
      // there is no next statement (which matches case (2), as the final
      // unconditional jump is not represented in the IRStmt list).
      //
      // Note that this approach won't do in the long run for supporting
      // PPC, but it's good enough for x86/AMD64 for the 3.0.X series.
      if (NULL == st2 || Ist_IMark == st2->tag)
         return True;
      else
         return False;
   }

   case Ist_IMark:
      /* st->Ist.IMark.addr is a 64-bit int.  ULong_to_Ptr casts this
         to the host's native pointer type; if that is 32 bits then it
         discards the upper 32 bits.  If we are cachegrinding on a
         32-bit host then we are also ensured that the guest word size
         is 32 bits, due to the assertion in cg_instrument that the
         host and guest word sizes must be the same.  Hence
         st->Ist.IMark.addr will have been derived from a 32-bit guest
         code address and truncation of it is safe.  I believe this
         assignment should be correct for both 32- and 64-bit
         machines. */
      *instrAddr = (Addr)ULong_to_Ptr(st->Ist.IMark.addr);
      *instrLen =        st->Ist.IMark.len;
      break;

   case Ist_Tmp: {
      IRExpr* data = st->Ist.Tmp.data;
      if (data->tag == Iex_Load) {
         IRExpr* aexpr = data->Iex.Load.addr;
         tl_assert( isIRAtom(aexpr) );
         // Note also, endianness info is ignored.  I guess that's not
         // interesting.
         // XXX: repe cmpsb does two loads... the first one is ignored here!
         //tl_assert( NULL == *loadAddrExpr );          // XXX: ???
         *loadAddrExpr = aexpr;
         *dataSize = sizeofIRType(data->Iex.Load.ty);
      }
      break;
   }
      
   case Ist_Store: {
      IRExpr* data  = st->Ist.Store.data;
      IRExpr* aexpr = st->Ist.Store.addr;
      tl_assert( isIRAtom(aexpr) );
      tl_assert( NULL == *storeAddrExpr );          // XXX: ???
      *storeAddrExpr = aexpr;
      *dataSize = sizeofIRType(typeOfIRExpr(tyenv, data));
      break;
   }
   
   case Ist_Dirty: {
      IRDirty* d = st->Ist.Dirty.details;
      if (d->mFx != Ifx_None) {
         /* This dirty helper accesses memory.  Collect the
            details. */
         tl_assert(d->mAddr != NULL);
         tl_assert(d->mSize != 0);
         *dataSize = d->mSize;
         if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
            *loadAddrExpr = d->mAddr;
         if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
            *storeAddrExpr = d->mAddr;
      } else {
         tl_assert(d->mAddr == NULL);
         tl_assert(d->mSize == 0);
      }
      break;
   }

   default:
      VG_(printf)("\n");
      ppIRStmt(st);
      VG_(printf)("\n");
      VG_(tool_panic)("Cachegrind: unhandled IRStmt");
   }

   return False;
}
Пример #9
0
static
IRSB* sh_instrument ( VgCallbackClosure* closure,
                      IRSB* sbIn,
                      VexGuestLayout* layout, 
                      VexGuestExtents* vge,
                      IRType gWordTy, IRType hWordTy )
{
    IRDirty*   di;
    Int        i;
    IRSB*      sbOut;
    IRType     type;
    IRTypeEnv* tyenv = sbIn->tyenv;
    IRStmt*    imarkst;
    char *fnname = global_fnname;
    if (gWordTy != hWordTy) {
        /* We don't currently support this case. */
        VG_(tool_panic)("host/guest word size mismatch");
    }

    /* Set up SB */
    sbOut = deepCopyIRSBExceptStmts(sbIn);

    // Copy verbatim any IR preamble preceding the first IMark
    i = 0;
    while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
        addStmtToIRSB( sbOut, sbIn->stmts[i] );
        i++;
    }
    if (clo_trace_mem) {
       events_used = 0;
    }
    for (/*use current i*/; i < sbIn->stmts_used; i++) {
        IRStmt* st = sbIn->stmts[i];
        if (!st || st->tag == Ist_NoOp) continue;

        /* Prettyprint All IR statements Starting from main
           that valgrind has generated */
        /*if(clo_trace_mem){
            ppIRStmt(st);
            VG_(printf)("\n");
        }
        */

        switch (st->tag) {
           case Ist_NoOp:
           case Ist_AbiHint:
           case Ist_PutI:
           case Ist_MBE:
              break;
           case Ist_Put:
              if(clo_trace_mem){
                  Int reg_no = st->Ist.Put.offset;
                  if(reg_no == layout->offset_SP || reg_no == 20){
                     IRExpr* data = st->Ist.Put.data;
                     if(data->tag == Iex_RdTmp){
                        /* Add registerwrite instrumentation to IRSBout */
                        addEvent_RegW( sbOut, fnname, reg_no, data);
                      }
                  }
              }
              addStmtToIRSB( sbOut, st );
              break;

           case Ist_IMark:
              imarkst = st;
              if (VG_(get_fnname_if_entry)(
                                            st->Ist.IMark.addr, 
                                            fnname, 100)){
                   //VG_(printf)("-- %s --\n",fnname);
                   if(0 == VG_(strcmp)(fnname, "main")) {
                      di = unsafeIRDirty_0_N( 
                              0, "trace_debug", 
                                 VG_(fnptr_to_fnentry)(trace_debug), 
                                 mkIRExprVec_0() );
                      addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
                      //VG_(printf)("SP:%d\n",layout->offset_SP);
                      clo_trace_mem = True;
                  }
                  if(clo_trace_mem){
                       addEvent_FnEntry(sbOut, fnname);
                  }
               }
              if (clo_trace_mem) {
                 // WARNING: do not remove this function call, even if you
                 // aren't interested in instruction reads.  See the comment
                 // above the function itself for more detail.
                 addEvent_Ir( sbOut, mkIRExpr_HWord( (HWord)st->Ist.IMark.addr ),
                              st->Ist.IMark.len );
              }
              addStmtToIRSB( sbOut, st );
              break;

           case Ist_WrTmp:
              // Add a call to trace_load() if --trace-mem=yes.
              if (clo_trace_mem) {
                 IRExpr* data = st->Ist.WrTmp.data;
                 if (data->tag == Iex_Load) {
                    addEvent_Dr( sbOut, fnname, data->Iex.Load.addr,
                                 sizeofIRType(data->Iex.Load.ty) );
                 }
              }
              addStmtToIRSB( sbOut, st );
              break;

           case Ist_Store:
              if (clo_trace_mem) {
                 IRExpr* data  = st->Ist.Store.data;
                 addEvent_Dw( sbOut, fnname, st->Ist.Store.addr,
                              sizeofIRType(typeOfIRExpr(tyenv, data)) );
              }
              addStmtToIRSB( sbOut, st );
              break;

           case Ist_Dirty: {
              if (clo_trace_mem) {
                 Int      dsize;
                 IRDirty* d = st->Ist.Dirty.details;
                 if (d->mFx != Ifx_None) {
                    // This dirty helper accesses memory.  Collect the details.
                    tl_assert(d->mAddr != NULL);
                    tl_assert(d->mSize != 0);
                    dsize = d->mSize;
                    if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
                       addEvent_Dr( sbOut, fnname, d->mAddr, dsize );
                    if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
                       addEvent_Dw( sbOut, fnname, d->mAddr, dsize );
                 } else {
                    tl_assert(d->mAddr == NULL);
                    tl_assert(d->mSize == 0);
                 }
              }
              addStmtToIRSB( sbOut, st );
              break;
           }

           case Ist_CAS: {
              /* We treat it as a read and a write of the location.  I
                 think that is the same behaviour as it was before IRCAS
                 was introduced, since prior to that point, the Vex
                 front ends would translate a lock-prefixed instruction
                 into a (normal) read followed by a (normal) write. */
              Int    dataSize;
              IRType dataTy;
              IRCAS* cas = st->Ist.CAS.details;
              tl_assert(cas->addr != NULL);
              tl_assert(cas->dataLo != NULL);
              dataTy   = typeOfIRExpr(tyenv, cas->dataLo);
              dataSize = sizeofIRType(dataTy);
              if (clo_trace_mem) {
                 addEvent_Dr( sbOut, fnname, cas->addr, dataSize );
                 addEvent_Dw( sbOut, fnname, cas->addr, dataSize );
              }
              addStmtToIRSB( sbOut, st );
              break;
           }

           case Ist_LLSC: {
              IRType dataTy;
              if (st->Ist.LLSC.storedata == NULL) {
                 /* LL */
                 dataTy = typeOfIRTemp(tyenv, st->Ist.LLSC.result);
                 if (clo_trace_mem)
                    addEvent_Dr( sbOut, fnname, st->Ist.LLSC.addr,
                                        sizeofIRType(dataTy) );
              } else {
                 /* SC */
                 dataTy = typeOfIRExpr(tyenv, st->Ist.LLSC.storedata);
                 if (clo_trace_mem)
                    addEvent_Dw( sbOut, fnname, st->Ist.LLSC.addr,
                                        sizeofIRType(dataTy) );
              }
              addStmtToIRSB( sbOut, st );
              break;
           }

           case Ist_Exit:
              if (clo_trace_mem) {
                 flushEvents(sbOut);
              }

              addStmtToIRSB( sbOut, st );      // Original statement
              break;

           default:
              tl_assert(0);
        }
    }
    if(clo_trace_mem){
        if(sbIn->jumpkind == Ijk_Ret){
            VG_(get_fnname)(imarkst->Ist.IMark.addr, 
                                            fnname, 100);
            addEvent_FnExit(sbOut,fnname);
        }
    }
    if (clo_trace_mem) {
        /* At the end of the sbIn.  Flush outstandings. */
        flushEvents(sbOut);
    }
    return sbOut;
}
Пример #10
0
static
IRSB* fr_instrument(VgCallbackClosure* closure,
                    IRSB* sbIn,
                    VexGuestLayout* layout, 
                    VexGuestExtents* vge,
                    IRType gWordTy, IRType hWordTy)
{
   Int        i;
   IRSB*      sbOut;
   IRTypeEnv* tyenv = sbIn->tyenv;
   IRDirty*   di;
   IRType     dataTy;
   IRExpr**   argv;
   IRCAS*     cas;

   // We don't care about mmaps
   if (!clo_mmap)
      return sbIn;

   // From lackey tool
   tl_assert(gWordTy == hWordTy);

   sbOut = deepCopyIRSBExceptStmts(sbIn);

   // Copy verbatim any IR preamble preceding the first IMark
   i = 0;
   while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
      addStmtToIRSB( sbOut, sbIn->stmts[i] );
      i++;
   }

   for (/*use current i*/; i < sbIn->stmts_used; i++) {
      IRStmt* st = sbIn->stmts[i];
      if (!st || st->tag == Ist_NoOp) continue;

      switch (st->tag) {
         case Ist_NoOp: // Make compiler happy
         case Ist_AbiHint:
         case Ist_Put:
         case Ist_PutI:
         case Ist_MBE:
         case Ist_IMark:
         case Ist_WrTmp:
         case Ist_Exit:
            addStmtToIRSB( sbOut, st );
            break;

         case Ist_Store:
            dataTy = typeOfIRExpr( tyenv, st->Ist.Store.data );
            argv   = mkIRExprVec_2( st->Ist.Store.addr, mkIRExpr_HWord( sizeofIRType( dataTy ) ) );
            di     = unsafeIRDirty_0_N(/*regparms*/2, "trace_store", VG_(fnptr_to_fnentry)( trace_store ), argv);
            addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
            addStmtToIRSB( sbOut, st );
            break;

         case Ist_LLSC:
            if (st->Ist.LLSC.storedata != NULL) {
               dataTy = typeOfIRExpr( tyenv, st->Ist.LLSC.storedata );
               argv   = mkIRExprVec_2( st->Ist.LLSC.addr, mkIRExpr_HWord( sizeofIRType( dataTy ) ) );
               di     = unsafeIRDirty_0_N(/*regparms*/2, "trace_store", VG_(fnptr_to_fnentry)( trace_store ), argv);
               addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
               addStmtToIRSB( sbOut, st );
            }
            break;

         case Ist_Dirty:
            di = st->Ist.Dirty.details;
            if (di->mFx != Ifx_None) {
               // This dirty helper accesses memory.  Collect the details.
               tl_assert(di->mAddr != NULL);
               tl_assert(di->mSize != 0);
               if (di->mFx == Ifx_Write || di->mFx == Ifx_Modify) {
                  argv = mkIRExprVec_2( di->mAddr, mkIRExpr_HWord( di->mSize ) );
                  di   = unsafeIRDirty_0_N( /*regparms*/2, "trace_store", VG_(fnptr_to_fnentry)( trace_store ), argv );
                  addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
               }
            } else {
               tl_assert(di->mAddr == NULL);
               tl_assert(di->mSize == 0);
            }
            addStmtToIRSB( sbOut, st );
            break;

         case Ist_CAS:
            cas = st->Ist.CAS.details;
            tl_assert(cas->addr != NULL);
            tl_assert(cas->dataLo != NULL);
            argv = mkIRExprVec_2( cas->addr, mkIRExpr_HWord( sizeofIRType(typeOfIRExpr(tyenv, cas->dataLo)) * (cas->dataHi != NULL ? 2 : 1) ) );
            di   = unsafeIRDirty_0_N( /*regparms*/2, "trace_store", VG_(fnptr_to_fnentry)( trace_store ), argv );
            addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
            addStmtToIRSB( sbOut, st );
            break;
      }
   }

   return sbOut;
}
Пример #11
0
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;
}
Пример #12
0
/* Inject IR stmts depending on the data provided in the control
   block iricb. */
void
vex_inject_ir(IRSB *irsb, IREndness endian)
{
   IRExpr *data, *rounding_mode, *opnd1, *opnd2, *opnd3, *opnd4;

   rounding_mode = NULL;
   if (iricb.rounding_mode != NO_ROUNDING_MODE) {
      rounding_mode = mkU32(iricb.rounding_mode);
   }

   switch (iricb.num_operands) {
   case 1:
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      if (rounding_mode)
         data = binop(iricb.op, rounding_mode, opnd1);
      else
         data = unop(iricb.op, opnd1);
      break;

   case 2:
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      /* HACK, compiler warning ‘opnd2’ may be used uninitialized */
      opnd2 = opnd1;

      /* immediate_index = 0  immediate value is not used.
       * immediate_index = 2  opnd2 is an immediate value.
       */
      vassert(iricb.immediate_index == 0 || iricb.immediate_index == 2);

      if (iricb.immediate_index == 2) {
         vassert((iricb.t_opnd2 == Ity_I8) || (iricb.t_opnd2 == Ity_I16)
                 || (iricb.t_opnd2 == Ity_I32));

         /* Interpret the memory as an ULong. */
         if (iricb.immediate_type == Ity_I8) {
            opnd2 = mkU8(*((ULong *)iricb.opnd2));
         } else if (iricb.immediate_type == Ity_I16) {
            opnd2 = mkU16(*((ULong *)iricb.opnd2));
         } else if (iricb.immediate_type == Ity_I32) {
            opnd2 = mkU32(*((ULong *)iricb.opnd2));
         }
      } else {
         opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
      }

      if (rounding_mode)
         data = triop(iricb.op, rounding_mode, opnd1, opnd2);
      else
         data = binop(iricb.op, opnd1, opnd2);
      break;

   case 3:
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
      /* HACK, compiler warning ‘opnd3’ may be used uninitialized */
      opnd3 = opnd2;

      /* immediate_index = 0  immediate value is not used.
       * immediate_index = 3  opnd3 is an immediate value.
       */
      vassert(iricb.immediate_index == 0 || iricb.immediate_index == 3);

      if (iricb.immediate_index == 3) {
         vassert((iricb.t_opnd3 == Ity_I8) || (iricb.t_opnd3 == Ity_I16)
                 || (iricb.t_opnd2 == Ity_I32));

         if (iricb.immediate_type == Ity_I8) {
            opnd3 = mkU8(*((ULong *)iricb.opnd3));
         } else if (iricb.immediate_type == Ity_I16) {
            opnd3 = mkU16(*((ULong *)iricb.opnd3));
         } else if (iricb.immediate_type == Ity_I32) {
            opnd3 = mkU32(*((ULong *)iricb.opnd3));
         }
      } else {
         opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3);
      }
      if (rounding_mode)
         data = qop(iricb.op, rounding_mode, opnd1, opnd2, opnd3);
      else
         data = triop(iricb.op, opnd1, opnd2, opnd3);
      break;

   case 4:
      vassert(rounding_mode == NULL);
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
      opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3);
      /* HACK, compiler warning ‘opnd4’ may be used uninitialized */
      opnd4 = opnd3;

      /* immediate_index = 0  immediate value is not used.
       * immediate_index = 4  opnd4 is an immediate value.
       */
      vassert(iricb.immediate_index == 0 || iricb.immediate_index == 4);

      if (iricb.immediate_index == 4) {
         vassert((iricb.t_opnd3 == Ity_I8) || (iricb.t_opnd3 == Ity_I16)
                 || (iricb.t_opnd2 == Ity_I32));

         if (iricb.immediate_type == Ity_I8) {
            opnd4 = mkU8(*((ULong *)iricb.opnd4));
         } else if (iricb.immediate_type == Ity_I16) {
            opnd4 = mkU16(*((ULong *)iricb.opnd4));
         } else if (iricb.immediate_type == Ity_I32) {
            opnd4 = mkU32(*((ULong *)iricb.opnd4));
         }
      } else {
         opnd4 = load(endian, iricb.t_opnd4, iricb.opnd4);
      }
      data = qop(iricb.op, opnd1, opnd2, opnd3, opnd4);
      break;

   default:
      vpanic("unsupported operator");
   }

   store(irsb, endian, iricb.result, data);

   if (0) {
      vex_printf("BEGIN inject\n");
      if (iricb.t_result == Ity_I1 || sizeofIRType(iricb.t_result) <= 8) {
         ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
      } else if (sizeofIRType(iricb.t_result) == 16) {
         ppIRStmt(irsb->stmts[irsb->stmts_used - 2]);
         vex_printf("\n");
         ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
      }
      vex_printf("\nEND inject\n");
   }
}
Пример #13
0
/* This is copied mostly verbatim from lackey */
static IRSB*
mv_instrument ( VgCallbackClosure* closure,
        IRSB* sbIn, 
        VexGuestLayout* layout, 
        VexGuestExtents* vge,
        VexArchInfo* archinfo_host,
        IRType gWordTy, IRType hWordTy )
{
    Int        i;
    IRSB*      sbOut;
    IRTypeEnv* tyenv = sbIn->tyenv;

    if (gWordTy != hWordTy) {
        /* We don't currently support this case. */
        VG_(tool_panic)("host/guest word size mismatch");
    }

    //ppIRSB(sbIn);

    /* Set up SB */
    sbOut = deepCopyIRSBExceptStmts(sbIn);

    // Copy verbatim any IR preamble preceding the first IMark
    i = 0;
    while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
        addStmtToIRSB( sbOut, sbIn->stmts[i] );
        i++;
    }

    events_used = 0;

    for (/*use current i*/; i < sbIn->stmts_used; i++) {
        IRStmt* st = sbIn->stmts[i];
        if (!st || st->tag == Ist_NoOp) continue;

        switch (st->tag) {
            case Ist_NoOp:
            case Ist_AbiHint:
            case Ist_Put:
            case Ist_PutI:
            case Ist_MBE:
                addStmtToIRSB( sbOut, st );
                break;

            case Ist_IMark:
                canCreateModify = False;
                if (clo_trace_instrs)
                {
                    addEvent_Ir( sbOut,
                            mkIRExpr_HWord( (HWord)st->Ist.IMark.addr ),
                            st->Ist.IMark.len );
                }
                addStmtToIRSB( sbOut, st );
                break;

            case Ist_WrTmp:
                {
                    IRExpr* data = st->Ist.WrTmp.data;
                    if (data->tag == Iex_Load) {
                        addEvent_Dr( sbOut, data->Iex.Load.addr,
                                sizeofIRType(data->Iex.Load.ty),
                               IRTypeToMVType(data->Iex.Load.ty) );
                    }
                }
                addStmtToIRSB( sbOut, st );
                break;

            case Ist_Store:
                {
                    IRExpr* data  = st->Ist.Store.data;
                    addEvent_Dw( sbOut, st->Ist.Store.addr,
                            sizeofIRType(typeOfIRExpr(tyenv, data)),
                           IRTypeToMVType(typeOfIRExpr(tyenv, data)) );
                }
                addStmtToIRSB( sbOut, st );
                break;

            case Ist_Dirty:
                {
                    Int      dsize;
                    IRDirty* d = st->Ist.Dirty.details;
                    if (d->mFx != Ifx_None) {
                        // This dirty helper accesses memory.  Collect the details.
                        tl_assert(d->mAddr != NULL);
                        tl_assert(d->mSize != 0);
                        dsize = d->mSize;
                        if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
                            addEvent_Dr( sbOut, d->mAddr, dsize, MV_DataInt32 );
                        if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
                            addEvent_Dw( sbOut, d->mAddr, dsize, MV_DataInt32 );
                    } else {
                        tl_assert(d->mAddr == NULL);
                        tl_assert(d->mSize == 0);
                    }
                    addStmtToIRSB( sbOut, st );
                    break;
                }

            case Ist_CAS:
                {
                    /* We treat it as a read and a write of the location.  I
                       think that is the same behaviour as it was before IRCAS
                       was introduced, since prior to that point, the Vex
                       front ends would translate a lock-prefixed instruction
                       into a (normal) read followed by a (normal) write. */
                    Int    dataSize;
                    IRType dataTy;
                    IRCAS* cas = st->Ist.CAS.details;
                    tl_assert(cas->addr != NULL);
                    tl_assert(cas->dataLo != NULL);
                    dataTy   = typeOfIRExpr(tyenv, cas->dataLo);
                    dataSize = sizeofIRType(dataTy);
                    if (cas->dataHi != NULL)
                        dataSize *= 2; /* since it's a doubleword-CAS */
                    addEvent_Dr( sbOut, cas->addr, dataSize,
                            IRTypeToMVType(dataTy) );
                    addEvent_Dw( sbOut, cas->addr, dataSize,
                            IRTypeToMVType(dataTy) );
                    addStmtToIRSB( sbOut, st );
                    break;
                }

            case Ist_LLSC:
                {
                    IRType dataTy;
                    if (st->Ist.LLSC.storedata == NULL) {
                        /* LL */
                        dataTy = typeOfIRTemp(tyenv, st->Ist.LLSC.result);
                        addEvent_Dr( sbOut, st->Ist.LLSC.addr,
                                sizeofIRType(dataTy),
                               IRTypeToMVType(dataTy) );
                    } else {
                        /* SC */
                        dataTy = typeOfIRExpr(tyenv, st->Ist.LLSC.storedata);
                        addEvent_Dw( sbOut, st->Ist.LLSC.addr,
                                sizeofIRType(dataTy),
                                IRTypeToMVType(dataTy) );
                    }
                    addStmtToIRSB( sbOut, st );
                    break;
                }

            case Ist_Exit:
                flushEvents(sbOut);

                addStmtToIRSB( sbOut, st );      // Original statement
                break;

            default:
                tl_assert(0);
        }
    }

    /* At the end of the sbIn.  Flush outstandings. */
    flushEvents(sbOut);

    return sbOut;
}
Пример #14
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)
        {
        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;
}
Пример #15
0
static
IRBB* cg_instrument ( IRBB* bbIn, VexGuestLayout* layout, 
                      Addr64 orig_addr_noredir, VexGuestExtents* vge,
                      IRType gWordTy, IRType hWordTy )
{
   Int        i, isize;
   IRStmt*    st;
   Addr64     cia; /* address of current insn */
   CgState    cgs;
   IRTypeEnv* tyenv = bbIn->tyenv;
   InstrInfo* curr_inode = NULL;

   if (gWordTy != hWordTy) {
      /* We don't currently support this case. */
      VG_(tool_panic)("host/guest word size mismatch");
   }

   /* Set up BB, including copying of the where-next stuff. */
   cgs.bbOut           = emptyIRBB();
   cgs.bbOut->tyenv    = dopyIRTypeEnv(tyenv);
   tl_assert( isIRAtom(bbIn->next) );
   cgs.bbOut->next     = dopyIRExpr(bbIn->next);
   cgs.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( cgs.bbOut, bbIn->stmts[i] );
      i++;
   }

   // Get the first statement, and initial cia from it
   tl_assert(bbIn->stmts_used > 0);
   tl_assert(i < bbIn->stmts_used);
   st = bbIn->stmts[i];
   tl_assert(Ist_IMark == st->tag);
   cia = st->Ist.IMark.addr;

   // Set up running state and get block info
   cgs.events_used = 0;
   cgs.bbInfo      = get_BB_info(bbIn, (Addr)orig_addr_noredir);
   cgs.bbInfo_i    = 0;

   if (DEBUG_CG)
      VG_(printf)("\n\n---------- cg_instrument ----------\n");

   // Traverse the block, initialising inodes, adding events and flushing as
   // necessary.
   for (/*use current i*/; i < bbIn->stmts_used; i++) {

      st = bbIn->stmts[i];
      tl_assert(isFlatIRStmt(st));

      switch (st->tag) {
         case Ist_NoOp:
         case Ist_AbiHint:
         case Ist_Put:
         case Ist_PutI:
         case Ist_MFence:
            break;

         case Ist_IMark:
            cia   = st->Ist.IMark.addr;
            isize = st->Ist.IMark.len;

            // If Vex fails to decode an instruction, the size will be zero.
            // Pretend otherwise.
            if (isize == 0) isize = VG_MIN_INSTR_SZB;

            // Sanity-check size.
            tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
                     || VG_CLREQ_SZB == isize );

            // Get space for and init the inode, record it as the current one.
            // Subsequent Dr/Dw/Dm events from the same instruction will 
            // also use it.
            curr_inode = setup_InstrInfo(&cgs, cia, isize);

            addEvent_Ir( &cgs, curr_inode );
            break;

         case Ist_Tmp: {
            IRExpr* data = st->Ist.Tmp.data;
            if (data->tag == Iex_Load) {
               IRExpr* aexpr = data->Iex.Load.addr;
               // Note also, endianness info is ignored.  I guess
               // that's not interesting.
               addEvent_Dr( &cgs, curr_inode, sizeofIRType(data->Iex.Load.ty), 
                                  aexpr );
            }
            break;
         }

         case Ist_Store: {
            IRExpr* data  = st->Ist.Store.data;
            IRExpr* aexpr = st->Ist.Store.addr;
            addEvent_Dw( &cgs, curr_inode, 
                         sizeofIRType(typeOfIRExpr(tyenv, data)), aexpr );
            break;
         }

         case Ist_Dirty: {
            Int      dataSize;
            IRDirty* d = st->Ist.Dirty.details;
            if (d->mFx != Ifx_None) {
               /* This dirty helper accesses memory.  Collect the details. */
               tl_assert(d->mAddr != NULL);
               tl_assert(d->mSize != 0);
               dataSize = d->mSize;
               // Large (eg. 28B, 108B, 512B on x86) data-sized
               // instructions will be done inaccurately, but they're
               // very rare and this avoids errors from hitting more
               // than two cache lines in the simulation.
               if (dataSize > MIN_LINE_SIZE)
                  dataSize = MIN_LINE_SIZE;
               if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
                  addEvent_Dr( &cgs, curr_inode, dataSize, d->mAddr );
               if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
                  addEvent_Dw( &cgs, curr_inode, dataSize, d->mAddr );
            } else {
               tl_assert(d->mAddr == NULL);
               tl_assert(d->mSize == 0);
            }
            break;
         }

         case Ist_Exit:
            /* We may never reach the next statement, so need to flush
               all outstanding transactions now. */
            flushEvents( &cgs );
            break;

         default:
            tl_assert(0);
            break;
      }

      /* Copy the original statement */
      addStmtToIRBB( cgs.bbOut, st );

      if (DEBUG_CG) {
         ppIRStmt(st);
         VG_(printf)("\n");
      }
   }

   /* At the end of the bb.  Flush outstandings. */
   flushEvents( &cgs );

   /* done.  stay sane ... */
   tl_assert(cgs.bbInfo_i == cgs.bbInfo->n_instrs);

   if (DEBUG_CG) {
      VG_(printf)( "goto {");
      ppIRJumpKind(bbIn->jumpkind);
      VG_(printf)( "} ");
      ppIRExpr( bbIn->next );
      VG_(printf)( "}\n");
   }

   return cgs.bbOut;
}
Пример #16
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;
}
Пример #17
0
/* Inject IR stmts depending on the data provided in the control
   block iricb. */
void
vex_inject_ir(IRSB *irsb, IREndness endian)
{
   IRExpr *data, *rounding_mode, *opnd1, *opnd2, *opnd3, *opnd4;

   rounding_mode = NULL;
   if (iricb.rounding_mode != NO_ROUNDING_MODE) {
      rounding_mode = mkU32(iricb.rounding_mode);
   }

   switch (iricb.num_operands) {
   case 1:
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      if (rounding_mode)
         data = binop(iricb.op, rounding_mode, opnd1);
      else
         data = unop(iricb.op, opnd1);
      break;

   case 2:
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);

      if (iricb.shift_amount_is_immediate) {
         // This implies that the IROp is a shift op
         vassert(iricb.t_opnd2 == Ity_I8);
         opnd2 = mkU8(*((Char *)iricb.opnd2));
      } else {
         opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
      }

      if (rounding_mode)
         data = triop(iricb.op, rounding_mode, opnd1, opnd2);
      else
         data = binop(iricb.op, opnd1, opnd2);
      break;

   case 3:
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
      opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3);
      if (rounding_mode)
         data = qop(iricb.op, rounding_mode, opnd1, opnd2, opnd3);
      else
         data = triop(iricb.op, opnd1, opnd2, opnd3);
      break;

   case 4:
      vassert(rounding_mode == NULL);
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
      opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3);
      opnd4 = load(endian, iricb.t_opnd4, iricb.opnd4);
      data = qop(iricb.op, opnd1, opnd2, opnd3, opnd4);
      break;

   default:
      vpanic("unsupported operator");
   }

   store(irsb, endian, iricb.result, data);

   if (0) {
      vex_printf("BEGIN inject\n");
      if (iricb.t_result == Ity_I1 || sizeofIRType(iricb.t_result) <= 8) {
         ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
      } else if (sizeofIRType(iricb.t_result) == 16) {
         ppIRStmt(irsb->stmts[irsb->stmts_used - 2]);
         vex_printf("\n");
         ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
      }
      vex_printf("\nEND inject\n");
   }
}