예제 #1
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;
}
예제 #2
0
static
EventSet* insert_simcall(IRBB* bbOut, InstrInfo* ii, UInt dataSize,
                         Bool instrIssued,
                         IRExpr* loadAddrExpr, IRExpr* storeAddrExpr)
{
    HChar*    helperName;
    void*     helperAddr;
    Int       argc;
    EventSet* es;
    IRExpr   *arg1, *arg2 = 0, *arg3 = 0, **argv;
    IRDirty* di;

    /* Check type of original instruction regarding memory access,
     * and collect info to be able to generate fitting helper call
     */
    if (!loadAddrExpr && !storeAddrExpr) {
        // no load/store
        CLG_ASSERT(0 == dataSize);
        if (instrIssued) {
            helperName = 0;
            helperAddr = 0;
        }
        else {
            helperName = CLG_(cachesim).log_1I0D_name;
            helperAddr = CLG_(cachesim).log_1I0D;
        }
        argc = 1;
        es = CLG_(sets).D0;

    } else if (loadAddrExpr && !storeAddrExpr) {
        // load
        CLG_ASSERT( isIRAtom(loadAddrExpr) );
        if (instrIssued) {
            helperName = CLG_(cachesim).log_0I1Dr_name;
            helperAddr = CLG_(cachesim).log_0I1Dr;
        }
        else {
            helperName = CLG_(cachesim).log_1I1Dr_name;
            helperAddr = CLG_(cachesim).log_1I1Dr;
        }
        argc = 2;
        arg2 = loadAddrExpr;
        es = CLG_(sets).D1r;

    } else if (!loadAddrExpr && storeAddrExpr) {
        // store
        CLG_ASSERT( isIRAtom(storeAddrExpr) );
        if (instrIssued) {
            helperName = CLG_(cachesim).log_0I1Dw_name;
            helperAddr = CLG_(cachesim).log_0I1Dw;
        }
        else {
            helperName = CLG_(cachesim).log_1I1Dw_name;
            helperAddr = CLG_(cachesim).log_1I1Dw;
        }
        argc = 2;
        arg2 = storeAddrExpr;
        es = CLG_(sets).D1w;

    } else {
        CLG_ASSERT( loadAddrExpr && storeAddrExpr );
        CLG_ASSERT( isIRAtom(loadAddrExpr) );
        CLG_ASSERT( isIRAtom(storeAddrExpr) );

        if ( loadStoreAddrsMatch(loadAddrExpr, storeAddrExpr) ) {
            /* modify: suppose write access, as this is
             * more resource consuming (as in callgrind for VG2)
             * Cachegrind does a read here (!)
             * DISCUSS: Best way depends on simulation model?
             */
            if (instrIssued) {
                helperName = CLG_(cachesim).log_0I1Dw_name;
                helperAddr = CLG_(cachesim).log_0I1Dw;
            }
            else {
                helperName = CLG_(cachesim).log_1I1Dw_name;
                helperAddr = CLG_(cachesim).log_1I1Dw;
            }
            argc = 2;
            arg2 = storeAddrExpr;
            es = CLG_(sets).D1w;

        } else {
            // load/store
            if (instrIssued) {
                helperName = CLG_(cachesim).log_0I2D_name;
                helperAddr = CLG_(cachesim).log_0I2D;
            }
            else {
                helperName = CLG_(cachesim).log_1I2D_name;
                helperAddr = CLG_(cachesim).log_1I2D;
            }
            argc = 3;
            arg2 = loadAddrExpr;
            arg3 = storeAddrExpr;
            es = CLG_(sets).D2;
        }
    }

    /* helper could be unset depending on the simulator used */
    if (helperAddr == 0) return 0;

    /* Setup 1st arg: InstrInfo */
    arg1 = mkIRExpr_HWord( (HWord)ii );

    // Add call to the instrumentation function
    if      (argc == 1)
        argv = mkIRExprVec_1(arg1);
    else if (argc == 2)
        argv = mkIRExprVec_2(arg1, arg2);
    else if (argc == 3)
        argv = mkIRExprVec_3(arg1, arg2, arg3);
    else
        VG_(tool_panic)("argc... not 1 or 2 or 3?");

    di = unsafeIRDirty_0_N( argc, helperName,
                            VG_(fnptr_to_fnentry)( helperAddr ), argv);
    addStmtToIRBB( bbOut, IRStmt_Dirty(di) );

    return es;
}
예제 #3
0
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;
}
예제 #4
0
void AddBinopHelper(IRSB* sb,IRStmt* st)
{
  IROp op;
  IRDirty* d1;
  IRDirty* d2;
  IRExpr* arg1;
  IRExpr* arg2;
  HWord lhs,tmpname;
//  HWord cur_ctr = (HWord)counter;

  vassert(st->tag = Ist_WrTmp);
  op = (HWord)st->Ist.WrTmp.data->Iex.Binop.op;
  arg1 = st->Ist.WrTmp.data->Iex.Binop.arg1;
  arg2 = st->Ist.WrTmp.data->Iex.Binop.arg2;
  
  lhs = (HWord)st->Ist.WrTmp.tmp;
  d1 = unsafeIRDirty_0_N(0, "EmitNewTmpTyvarHelper", 
			&EmitNewTmpTyvarHelper,
			mkIRExprVec_2(
				      mkIRExpr_HWord(lhs),
				      mkIRExpr_HWord(counter)
				      )
			);
  setHelperAnns(d1);
  addStmtToIRSB(sb,IRStmt_Dirty(d1));

  if (arg1->tag == Iex_RdTmp && arg2->tag == Iex_RdTmp)
    {
      d2 = unsafeIRDirty_0_N(0, "EmitBinopTmpTmpTypeHelper", 
			     &EmitBinopTmpTmpTypeHelper,
			     mkIRExprVec_5(
			        	   mkIRExpr_HWord(lhs),
				           mkIRExpr_HWord(op),
				           mkIRExpr_HWord((HWord)arg1->Iex.RdTmp.tmp),
				           mkIRExpr_HWord((HWord)arg2->Iex.RdTmp.tmp),
				           mkIRExpr_HWord(counter)
				           )
			     );
      setHelperAnns(d2);
      addStmtToIRSB(sb,IRStmt_Dirty(d2));
    }

  if ((arg1->tag == Iex_RdTmp && arg2->tag == Iex_Const)
      || (arg1->tag == Iex_Const && arg2->tag == Iex_RdTmp))
    {
      if (arg1->tag == Iex_RdTmp) tmpname = (HWord)arg1->Iex.RdTmp.tmp;
      else if (arg2->tag == Iex_RdTmp) tmpname = (HWord)arg2->Iex.RdTmp.tmp;
      else vpanic("Neither arg1 nor arg2 is a tmp! \n");
      d2 = unsafeIRDirty_0_N(0, "EmitBinopTmpConstTypeHelper", 
			     &EmitBinopTmpConstTypeHelper,
			     mkIRExprVec_4(
			        	   mkIRExpr_HWord(lhs),
				           mkIRExpr_HWord(op),
				           mkIRExpr_HWord(tmpname),
				           mkIRExpr_HWord(counter)
				           )
			     );
      setHelperAnns(d2);
      addStmtToIRSB(sb,IRStmt_Dirty(d2));
    }

  return;
}
예제 #5
0
// Instrumentation for the end of each original instruction.
static
void instrumentInstr(IRBB* bbOut, instr_info* i_node, Bool bbSeenBefore,
                     UInt instrAddr, UInt instrLen, UInt dataSize,
                     IRExpr* loadAddrExpr, IRExpr* storeAddrExpr)
{
   IRDirty* di;
   IRExpr  *arg1, *arg2, *arg3, **argv;
   Int      argc;
   Char*    helperName;
   void*    helperAddr;
   IRType   wordTy;

   // Stay sane ...
   tl_assert(sizeof(HWord) == sizeof(void*));
   if (sizeof(HWord) == 4) {
      wordTy = Ity_I32;
   } else
   if (sizeof(HWord) == 8) {
      wordTy = Ity_I64;
   } else {
      VG_(tool_panic)("instrumentInstr: strange word size");
   }

   if (loadAddrExpr) 
      tl_assert(wordTy == typeOfIRExpr(bbOut->tyenv, loadAddrExpr));
   if (storeAddrExpr) 
      tl_assert(wordTy == typeOfIRExpr(bbOut->tyenv, storeAddrExpr));


   // Nb: instrLen will be zero if Vex failed to decode it.
   tl_assert( 0 == instrLen ||
              (instrLen >= VG_MIN_INSTR_SZB && 
               instrLen <= VG_MAX_INSTR_SZB) );

   // 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;

   // Setup 1st arg: instr_info node's address
   // Believed to be 64-bit clean
   do_details(i_node, bbSeenBefore, instrAddr, instrLen, dataSize );
   arg1 = mkIRExpr_HWord( (HWord)i_node );

   if (!loadAddrExpr && !storeAddrExpr) {
      // no load/store
      tl_assert(0 == dataSize);
      helperName = "log_1I_0D_cache_access";
      helperAddr = &log_1I_0D_cache_access;
      argc = 1;
      argv = mkIRExprVec_1(arg1);

   } else if (loadAddrExpr && !storeAddrExpr) {
      // load
      tl_assert( isIRAtom(loadAddrExpr) );
      helperName = "log_1I_1Dr_cache_access";
      helperAddr = &log_1I_1Dr_cache_access;
      argc = 2;
      arg2 = loadAddrExpr;
      argv = mkIRExprVec_2(arg1, arg2);

   } else if (!loadAddrExpr && storeAddrExpr) {
      // store
      tl_assert( isIRAtom(storeAddrExpr) );
      helperName = "log_1I_1Dw_cache_access";
      helperAddr = &log_1I_1Dw_cache_access;
      argc = 2;
      arg2 = storeAddrExpr;
      argv = mkIRExprVec_2(arg1, arg2);
 
   } else {
      tl_assert( loadAddrExpr && storeAddrExpr );
      tl_assert( isIRAtom(loadAddrExpr) );
      tl_assert( isIRAtom(storeAddrExpr) );

      if ( loadStoreAddrsMatch(loadAddrExpr, storeAddrExpr) ) {
         // modify
         helperName = "log_1I_1Dr_cache_access";
         helperAddr = &log_1I_1Dr_cache_access;
         argc = 2;
         arg2 = loadAddrExpr;
         argv = mkIRExprVec_2(arg1, arg2);

      } else {
         // load/store
         helperName = "log_1I_2D_cache_access";
         helperAddr = &log_1I_2D_cache_access;
         argc = 3;
         arg2 = loadAddrExpr;
         arg3 = storeAddrExpr;
         argv = mkIRExprVec_3(arg1, arg2, arg3);
      }
   }

   // Add call to the instrumentation function
   di = unsafeIRDirty_0_N( argc, helperName, helperAddr, argv);
   addStmtToIRBB( bbOut, IRStmt_Dirty(di) );
}
예제 #6
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_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));
}
예제 #7
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;
}
예제 #8
0
파일: mv_main.c 프로젝트: giraldeau/memview
/* This version of flushEvents (currently unused) is similar to the one in
   lackey with the primary difference that it groups together pairs of
   events for a single callback.  This helps to reduce the total amount of
   function call overhead. */
static void flushEventsCB(IRSB* sb)
{
    IRDirty*   di;
    Int        i;
    for (i = 0; i < events_used; i++) {

        Event*       ev = &events[i];

        const HChar* helperName;
        void*        helperAddr;
        IRExpr**     argv;
        Event*       ev2;
        Int          regparms;

        ev2 = i < events_used-1 ? &events[i+1] : NULL;

        if (ev2 &&
                ev->ekind == ev2->ekind &&
                ev->size == ev2->size)
        {
            // Decide on helper fn to call and args to pass it.
            switch (ev->ekind) {
                case Event_Ir: helperName = "trace_2instr";
                               helperAddr =  trace_2instr;  break;

                case Event_Dr: helperName = "trace_2load";
                               helperAddr =  trace_2load;   break;

                case Event_Dw: helperName = "trace_2store";
                               helperAddr =  trace_2store;  break;

                case Event_Dm: helperName = "trace_2modify";
                               helperAddr =  trace_2modify; break;
                default:
                               tl_assert(0);
            }

            argv = mkIRExprVec_3( ev->addr,
                                  ev2->addr, mkIRExpr_HWord( ev->size ));
            regparms = 3;

            // Skip the next event, since we paired it
            i++;
        }
        else if (ev2 &&
                ev->ekind == Event_Dr &&
                ev2->ekind == Event_Dw &&
                ev->size == ev2->size)
        {
            // Load then store
            helperName = "trace_loadstore";
            helperAddr = trace_loadstore;

            argv = mkIRExprVec_3( ev->addr,
                                  ev2->addr, mkIRExpr_HWord( ev->size ));
            regparms = 3;
            i++;
        }
        else if (ev2 &&
                ev->ekind == Event_Dw &&
                ev2->ekind == Event_Dr &&
                ev->size == ev2->size)
        {
            // Store then load
            helperName = "trace_storeload";
            helperAddr = trace_storeload;

            argv = mkIRExprVec_3( ev->addr,
                                  ev2->addr, mkIRExpr_HWord( ev->size ));
            regparms = 3;
            i++;
        }
        else
        {

            // Decide on helper fn to call and args to pass it.
            switch (ev->ekind) {
                case Event_Ir: helperName = "trace_instr";
                               helperAddr =  trace_instr;  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);
            }

            argv = mkIRExprVec_2( ev->addr, mkIRExpr_HWord( ev->size ) );
            regparms = 2;
        }

        // Add the helper.
        di   = unsafeIRDirty_0_N(regparms,
                helperName, VG_(fnptr_to_fnentry)( helperAddr ),
                argv );

        addStmtToIRSB( sb, IRStmt_Dirty(di) );
    }

    events_used = 0;
}
예제 #9
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;
}
예제 #10
0
IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
                 /*IN*/ void*            callback_opaque,
                 /*IN*/ DisOneInstrFn    dis_instr_fn,
                 /*IN*/ UChar*           guest_code,
                 /*IN*/ Addr64           guest_IP_bbstart,
                 /*IN*/ Bool             (*chase_into_ok)(void*,Addr64),
                 /*IN*/ Bool             host_bigendian,
                 /*IN*/ VexArch          arch_guest,
                 /*IN*/ VexArchInfo*     archinfo_guest,
                 /*IN*/ IRType           guest_word_type,
                 /*IN*/ Bool             do_self_check,
                 /*IN*/ Bool             (*preamble_function)(void*,IRBB*),
                 /*IN*/ Int              offB_TISTART,
                 /*IN*/ Int              offB_TILEN )
{
   Long       delta;
   Int        i, n_instrs, first_stmt_idx;
   Bool       resteerOK, need_to_put_IP, debug_print;
   DisResult  dres;
   IRStmt*    imark;
   static Int n_resteers = 0;
   Int        d_resteers = 0;
   Int        selfcheck_idx = 0;
   IRBB*      irbb;
   Addr64     guest_IP_curr_instr;
   IRConst*   guest_IP_bbstart_IRConst = NULL;

   Bool (*resteerOKfn)(void*,Addr64) = NULL;

   debug_print = toBool(vex_traceflags & VEX_TRACE_FE);

   /* Note: for adler32 to work without % operation for the self
      check, need to limit length of stuff it scans to 5552 bytes.
      Therefore limiting the max bb len to 100 insns seems generously
      conservative. */

   /* check sanity .. */
   vassert(sizeof(HWord) == sizeof(void*));
   vassert(vex_control.guest_max_insns >= 1);
   vassert(vex_control.guest_max_insns < 100);
   vassert(vex_control.guest_chase_thresh >= 0);
   vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns);
   vassert(guest_word_type == Ity_I32 || guest_word_type == Ity_I64);

   /* Start a new, empty extent. */
   vge->n_used  = 1;
   vge->base[0] = guest_IP_bbstart;
   vge->len[0]  = 0;

   /* And a new IR BB to dump the result into. */
   irbb = emptyIRBB();

   /* Delta keeps track of how far along the guest_code array we have
      so far gone. */
   delta    = 0;
   n_instrs = 0;

   /* Guest addresses as IRConsts.  Used in the two self-checks
      generated. */
   if (do_self_check) {
      guest_IP_bbstart_IRConst
         = guest_word_type==Ity_I32 
              ? IRConst_U32(toUInt(guest_IP_bbstart))
              : IRConst_U64(guest_IP_bbstart);
   }

   /* If asked to make a self-checking translation, leave 5 spaces
      in which to put the check statements.  We'll fill them in later
      when we know the length and adler32 of the area to check. */
   if (do_self_check) {
      selfcheck_idx = irbb->stmts_used;
      addStmtToIRBB( irbb, IRStmt_NoOp() );
      addStmtToIRBB( irbb, IRStmt_NoOp() );
      addStmtToIRBB( irbb, IRStmt_NoOp() );
      addStmtToIRBB( irbb, IRStmt_NoOp() );
      addStmtToIRBB( irbb, IRStmt_NoOp() );
   }

   /* If the caller supplied a function to add its own preamble, use
      it now. */
   if (preamble_function) {
      Bool stopNow = preamble_function( callback_opaque, irbb );
      if (stopNow) {
         /* The callback has completed the IR block without any guest
            insns being disassembled into it, so just return it at
            this point, even if a self-check was requested - as there
            is nothing to self-check.  The five self-check no-ops will
            still be in place, but they are harmless. */
         return irbb;
      }
   }

   /* Process instructions. */
   while (True) {
      vassert(n_instrs < vex_control.guest_max_insns);

      /* Regardless of what chase_into_ok says, is chasing permissible
         at all right now?  Set resteerOKfn accordingly. */
      resteerOK 
         = toBool(
              n_instrs < vex_control.guest_chase_thresh
              /* If making self-checking translations, don't chase
                 .. it makes the checks too complicated.  We only want
                 to scan just one sequence of bytes in the check, not
                 a whole bunch. */
              && !do_self_check
              /* we can't afford to have a resteer once we're on the
                 last extent slot. */
              && vge->n_used < 3
           );

      resteerOKfn
         = resteerOK ? chase_into_ok : const_False;

      /* This is the IP of the instruction we're just about to deal
         with. */
      guest_IP_curr_instr = guest_IP_bbstart + delta;

      /* This is the irbb statement array index of the first stmt in
         this insn.  That will always be the instruction-mark
         descriptor. */
      first_stmt_idx = irbb->stmts_used;

      /* Add an instruction-mark statement.  We won't know until after
         disassembling the instruction how long it instruction is, so
         just put in a zero length and we'll fix it up later. */
      addStmtToIRBB( irbb, IRStmt_IMark( guest_IP_curr_instr, 0 ));

      /* for the first insn, the dispatch loop will have set
         %IP, but for all the others we have to do it ourselves. */
      need_to_put_IP = toBool(n_instrs > 0);

      /* Finally, actually disassemble an instruction. */
      dres = dis_instr_fn ( irbb,
                            need_to_put_IP,
                            resteerOKfn,
                            callback_opaque,
                            guest_code,
                            delta,
                            guest_IP_curr_instr,
                            arch_guest,
                            archinfo_guest,
                            host_bigendian );

      /* stay sane ... */
      vassert(dres.whatNext == Dis_StopHere
              || dres.whatNext == Dis_Continue
              || dres.whatNext == Dis_Resteer);
      vassert(dres.len >= 0 && dres.len <= 20);
      if (dres.whatNext != Dis_Resteer)
         vassert(dres.continueAt == 0);

      /* Fill in the insn-mark length field. */
      vassert(first_stmt_idx >= 0 && first_stmt_idx < irbb->stmts_used);
      imark = irbb->stmts[first_stmt_idx];
      vassert(imark);
      vassert(imark->tag == Ist_IMark);
      vassert(imark->Ist.IMark.len == 0);
      imark->Ist.IMark.len = toUInt(dres.len);

      /* Print the resulting IR, if needed. */
      if (vex_traceflags & VEX_TRACE_FE) {
         for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
            vex_printf("              ");
            ppIRStmt(irbb->stmts[i]);
            vex_printf("\n");
         }
      }

      /* If dis_instr_fn terminated the BB at this point, check it
	 also filled in the irbb->next field. */
      if (dres.whatNext == Dis_StopHere) {
         vassert(irbb->next != NULL);
         if (debug_print) {
            vex_printf("              ");
            vex_printf( "goto {");
            ppIRJumpKind(irbb->jumpkind);
            vex_printf( "} ");
            ppIRExpr( irbb->next );
            vex_printf( "\n");
         }
      }

      /* Update the VexGuestExtents we are constructing. */
      /* If vex_control.guest_max_insns is required to be < 100 and
	 each insn is at max 20 bytes long, this limit of 5000 then
	 seems reasonable since the max possible extent length will be
	 100 * 20 == 2000. */
      vassert(vge->len[vge->n_used-1] < 5000);
      vge->len[vge->n_used-1] 
         = toUShort(toUInt( vge->len[vge->n_used-1] + dres.len ));
      n_instrs++;
      if (debug_print) 
         vex_printf("\n");

      /* Advance delta (inconspicuous but very important :-) */
      delta += (Long)dres.len;

      switch (dres.whatNext) {
         case Dis_Continue:
            vassert(irbb->next == NULL);
            if (n_instrs < vex_control.guest_max_insns) {
               /* keep going */
            } else {
               /* We have to stop. */
               irbb->next 
                  = IRExpr_Const(
                       guest_word_type == Ity_I32
                          ? IRConst_U32(toUInt(guest_IP_bbstart+delta))
                          : IRConst_U64(guest_IP_bbstart+delta)
                    );
               goto done;
            }
            break;
         case Dis_StopHere:
            vassert(irbb->next != NULL);
            goto done;
         case Dis_Resteer:
            /* Check that we actually allowed a resteer .. */
            vassert(resteerOK);
            vassert(irbb->next == NULL);
            /* figure out a new delta to continue at. */
            vassert(resteerOKfn(callback_opaque,dres.continueAt));
            delta = dres.continueAt - guest_IP_bbstart;
            /* we now have to start a new extent slot. */
            vge->n_used++;
            vassert(vge->n_used <= 3);
            vge->base[vge->n_used-1] = dres.continueAt;
            vge->len[vge->n_used-1] = 0;
            n_resteers++;
            d_resteers++;
            if (0 && (n_resteers & 0xFF) == 0)
            vex_printf("resteer[%d,%d] to 0x%llx (delta = %lld)\n",
                       n_resteers, d_resteers,
                       dres.continueAt, delta);
            break;
         default:
            vpanic("bb_to_IR");
      }
   }
   /*NOTREACHED*/
   vassert(0);

  done:
   /* We're done.  The only thing that might need attending to is that
      a self-checking preamble may need to be created. */
   if (do_self_check) {

      UInt     len2check, adler32;
      IRTemp   tistart_tmp, tilen_tmp;

      vassert(vge->n_used == 1);
      len2check = vge->len[0];
      if (len2check == 0) 
         len2check = 1;

     adler32 = genericg_compute_adler32( (HWord)guest_code, len2check );

     /* Set TISTART and TILEN.  These will describe to the despatcher
        the area of guest code to invalidate should we exit with a
        self-check failure. */

     tistart_tmp = newIRTemp(irbb->tyenv, guest_word_type);
     tilen_tmp   = newIRTemp(irbb->tyenv, guest_word_type);

     irbb->stmts[selfcheck_idx+0]
        = IRStmt_Tmp(tistart_tmp, IRExpr_Const(guest_IP_bbstart_IRConst) );

     irbb->stmts[selfcheck_idx+1]
        = IRStmt_Tmp(tilen_tmp,
                     guest_word_type==Ity_I32 
                        ? IRExpr_Const(IRConst_U32(len2check)) 
                        : IRExpr_Const(IRConst_U64(len2check))
          );

     irbb->stmts[selfcheck_idx+2]
        = IRStmt_Put( offB_TISTART, IRExpr_Tmp(tistart_tmp) );

     irbb->stmts[selfcheck_idx+3]
        = IRStmt_Put( offB_TILEN, IRExpr_Tmp(tilen_tmp) );

     irbb->stmts[selfcheck_idx+4]
        = IRStmt_Exit( 
             IRExpr_Binop( 
                Iop_CmpNE32, 
                mkIRExprCCall( 
                   Ity_I32, 
                   2/*regparms*/, 
                   "genericg_compute_adler32",
#if defined(__powerpc__) && defined(__powerpc64__)
                   (void*)((ULong*)(&genericg_compute_adler32))[0],
#else
                   &genericg_compute_adler32,
#endif
                   mkIRExprVec_2( 
                      mkIRExpr_HWord( (HWord)guest_code ), 
                      mkIRExpr_HWord( (HWord)len2check )
                   )
                ),
                IRExpr_Const(IRConst_U32(adler32))
             ),
             Ijk_TInval,
             guest_IP_bbstart_IRConst
          );
   }

   return irbb;
}
예제 #11
0
void findRepMovIRExpr(IRBB * bb, IRStmt * s, findRepMovContext * context, UInt tagVal)
{
  IROp theOp; 
  IRExpr * expr; 
  IRExpr * arg1;
  IRExpr * arg2; 
  UInt tmpName; 
  IRDirty * d; 

  expr = s->Ist.Tmp.data; 
  
  switch (expr->tag)
  {
  case Iex_Binop:
    theOp = expr->Iex.Binop.op;
    arg1 = expr->Iex.Binop.arg1;
    arg2 = expr->Iex.Binop.arg2; 

    switch(theOp)
    {
    case Iop_Sub32:
    case Iop_Sub16:
    case Iop_Sub8:
      if (arg2->tag == Iex_Const && arg1->tag == Iex_Tmp)
      {
	tmpName = (UInt) arg1->Iex.Tmp.tmp; 
	context->subTmpVars[tmpName] = 1; 

	if (checkTmpRepMov(tmpName, context) == 1)
	{
	  //	  VG_(printf)("XXX tmpName: %u BB %u flagged by checkTmpRepMov! \n", tmpName, tagVal);

	  d = unsafeIRDirty_0_N(0,
				"emitFlaggedTmpRepMov",
				&emitFlaggedTmpRepMov,
				mkIRExprVec_2(
					      mkIRExpr_HWord(tmpName),
					      mkIRExpr_HWord(tagVal)
					      )
				);
	  setHelperAnns(d); 
	  addStmtToIRBB(bb, IRStmt_Dirty(d)); 
	}
      }
      break; 

    case Iop_CmpEQ32:
    case Iop_CmpEQ16:
    case Iop_CmpEQ8:
      if (arg2->tag == Iex_Const && arg1->tag == Iex_Tmp)
	{
	  tmpName = (UInt) arg1->Iex.Tmp.tmp; 
	  if (arg2->Iex.Const.con->Ico.U32 == 0)
	  {
	    context->cmpZeroTmpVars[tmpName] = 1; 

	    if (checkTmpRepMov(tmpName, context) == 1)
	    {
	      //	      VG_(printf)("XXX tmpName: %u BB %u flagged by checkTmpRepMov! \n", tmpName, tagVal);
	      d = unsafeIRDirty_0_N(0,
				    "emitFlaggedTmpRepMov",
				    &emitFlaggedTmpRepMov,
				    mkIRExprVec_2(
						  mkIRExpr_HWord(tmpName),
						  mkIRExpr_HWord(tagVal)
						  )
				    );
	      setHelperAnns(d); 
	      addStmtToIRBB(bb, IRStmt_Dirty(d)); 
	    }
	  }
      }
      break; 

    default:
      break; 
    }
  default:
    break; 
  }
  return; 
}
예제 #12
0
파일: fr_main.c 프로젝트: mbbill/Freya
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;
}