Beispiel #1
0
static void instrument_store(IRSB* const bb,
                             IRExpr* const addr_expr,
                             const HWord size)
{
    IRExpr* size_expr;
    IRExpr** argv;
    IRDirty* di;

    switch (size)
    {
    case 1:
        argv = mkIRExprVec_1(addr_expr);
        di = unsafeIRDirty_0_N(/*regparms*/1,
                                           "drd_trace_store_1",
                                           VG_(fnptr_to_fnentry)(drd_trace_store_1),
                                           argv);
        break;
    case 2:
        argv = mkIRExprVec_1(addr_expr);
        di = unsafeIRDirty_0_N(/*regparms*/1,
                                           "drd_trace_store_2",
                                           VG_(fnptr_to_fnentry)(drd_trace_store_2),
                                           argv);
        break;
    case 4:
        argv = mkIRExprVec_1(addr_expr);
        di = unsafeIRDirty_0_N(/*regparms*/1,
                                           "drd_trace_store_4",
                                           VG_(fnptr_to_fnentry)(drd_trace_store_4),
                                           argv);
        break;
    case 8:
        argv = mkIRExprVec_1(addr_expr);
        di = unsafeIRDirty_0_N(/*regparms*/1,
                                           "drd_trace_store_8",
                                           VG_(fnptr_to_fnentry)(drd_trace_store_8),
                                           argv);
        break;
    default:
        size_expr = mkIRExpr_HWord(size);
        argv = mkIRExprVec_2(addr_expr, size_expr);
        di = unsafeIRDirty_0_N(/*regparms*/2,
                                           "drd_trace_store",
                                           VG_(fnptr_to_fnentry)(drd_trace_store),
                                           argv);
        break;
    }
    addStmtToIRSB(bb, IRStmt_Dirty(di));
}
Beispiel #2
0
static void VG_(add_stmt_call_invalidate_if_not_gdbserved)
     ( IRSB* sb_in,
       VexGuestLayout* layout, 
       VexGuestExtents* vge,
       IRTemp jmp, 
       IRSB* irsb)
{
   
   void*    fn;
   const HChar*   nm;
   IRExpr** args;
   Int      nargs;
   IRDirty* di;

   fn    = &VG_(helperc_invalidate_if_not_gdbserved);
   nm    = "VG_(helperc_invalidate_if_not_gdbserved)";
   args  = mkIRExprVec_1(IRExpr_RdTmp (jmp));
   nargs = 1;
   
   di = unsafeIRDirty_0_N( nargs/*regparms*/, nm, 
                           VG_(fnptr_to_fnentry)( fn ), args );

   di->nFxState = 0;

   addStmtToIRSB(irsb, IRStmt_Dirty(di));
}
Beispiel #3
0
void addDynamicDisownNonNullDetached(IRSB* sbOut, IRExpr* st){
  runPureCCall(sbOut,
               mkIRCallee(1, "disownShadowTemp",
                          VG_(fnptr_to_fnentry)(disownShadowTemp)),
               Ity_I64,
               mkIRExprVec_1(st));
}
Beispiel #4
0
void addDynamicDisownNonNull(IRSB* sbOut, IRTemp idx){
  IRDirty* disownDirty =
    unsafeIRDirty_0_N(1, "disownShadowTempNonNullDynamic",
                      VG_(fnptr_to_fnentry)(disownShadowTempNonNullDynamic),
                      mkIRExprVec_1(mkU64(idx)));
  disownDirty->mFx = Ifx_Modify;
  disownDirty->mAddr = mkU64((uintptr_t)&(shadowTemps[idx]));
  disownDirty->mSize = sizeof(ShadowTemp*);
  addStmtToIRSB(sbOut, IRStmt_Dirty(disownDirty));
}
Beispiel #5
0
void instrument_WrTmp_Const(IRStmt* st, IRSB* sb_out)
{
    IRTemp tmp = st->Ist.WrTmp.tmp;
    IRDirty* di;

    di = unsafeIRDirty_0_N(0,
                           "helper_instrument_WrTmp_Const",
                           VG_(fnptr_to_fnentry)(helper_instrument_WrTmp_Const),
                           mkIRExprVec_1(mkIRExpr_HWord(tmp))
                           );
    addStmtToIRSB(sb_out, IRStmt_Dirty(di));
}
Beispiel #6
0
/* A helper that adds the instrumentation for a detail. */
static void instrument_detail(IRSB* sb, Op op, IRType type)
{
   IRDirty* di;
   IRExpr** argv;
   const UInt typeIx = type2index(type);

   tl_assert(op < N_OPS);
   tl_assert(typeIx < N_TYPES);

   argv = mkIRExprVec_1( mkIRExpr_HWord( (HWord)&detailCounts[op][typeIx] ) );
   di = unsafeIRDirty_0_N( 1, "increment_detail",
                              VG_(fnptr_to_fnentry)( &increment_detail ), 
                              argv);
   addStmtToIRSB( sb, IRStmt_Dirty(di) );
}
Beispiel #7
0
static
void addEvent_FnEntry ( IRSB* sb, char *fnname)
{
    IRExpr**   argv;
    IRDirty*   di;
    char *buf = (char *)VG_(malloc)("addEvent_FnEntry",100*sizeof(char));
    tl_assert(buf!=NULL);
    VG_(strcpy)(buf,fnname);
    argv = mkIRExprVec_1( mkIRExpr_HWord( (HWord) buf ));
    di   = unsafeIRDirty_0_N( /*regparms*/1, 
                              "trace_fnentry", VG_(fnptr_to_fnentry)( trace_fnentry ),
                              argv );
    if(events_used > 0)
      flushEvents(sb);
    addStmtToIRSB( sb, IRStmt_Dirty(di) );
}
Beispiel #8
0
void AddStoreHelper(IRSB* sb, IRExpr* addr, IRExpr* data)
{
  IRDirty* d;
  HWord tmpname;

  switch (addr->tag)
    {
    case (Iex_RdTmp):
      switch (data->tag)
	{
	case (Iex_RdTmp):
	  tmpname = (HWord) data->Iex.RdTmp.tmp; 	

	  d = unsafeIRDirty_0_N(0,
			    "EmitStoreAddr2TmpHelper",
			    &EmitStoreAddr2TmpHelper,
			    mkIRExprVec_3(addr,
					  mkIRExpr_HWord(tmpname),
					  mkIRExpr_HWord(counter)
					  )
			    );
	  setHelperAnns(d);
	  addStmtToIRSB(sb, IRStmt_Dirty(d)); 
	  break; 
	case (Iex_Const):
	  /* add code to emit new tyvar for memory address */ 
	  d = unsafeIRDirty_0_N(0,
				"EmitStoreAddr2ConstHelper",
				&EmitStoreAddr2ConstHelper,
				mkIRExprVec_1(addr
					      )
				);
	  setHelperAnns(d);
	  addStmtToIRSB(sb,IRStmt_Dirty(d)); 
	  break;
        default:
	  /* Should not reach here. */
	  ppIRExpr(data); 
	  vpanic("Bad store address!\n"); 
	  break; 
	}
      break; 
    default:
      break; 
    }
  return;
} 
Beispiel #9
0
static void instrument_store(IRSB* const bb,
                             IRExpr* const addr_expr,
                             const HWord size)
{
  IRExpr* size_expr;
  IRExpr** argv;
  IRDirty* di;

  if (UNLIKELY(drd_any_address_is_traced()))
  {
    addStmtToIRSB(bb,
		  IRStmt_Dirty(
		    unsafeIRDirty_0_N(/*regparms*/2,
				      "drd_trace_store",
				      VG_(fnptr_to_fnentry)
				      (drd_trace_mem_store),
				      mkIRExprVec_2(addr_expr,
						    mkIRExpr_HWord(size)))));
  }

  if (! s_drd_check_stack_accesses && is_stack_access(bb, addr_expr))
    return;

  switch (size)
  {
  case 1:
    argv = mkIRExprVec_1(addr_expr);
    di = unsafeIRDirty_0_N(/*regparms*/1,
                           "drd_trace_store_1",
                           VG_(fnptr_to_fnentry)(drd_trace_store_1),
                           argv);
    break;
  case 2:
    argv = mkIRExprVec_1(addr_expr);
    di = unsafeIRDirty_0_N(/*regparms*/1,
                           "drd_trace_store_2",
                           VG_(fnptr_to_fnentry)(drd_trace_store_2),
                           argv);
    break;
  case 4:
    argv = mkIRExprVec_1(addr_expr);
    di = unsafeIRDirty_0_N(/*regparms*/1,
                           "drd_trace_store_4",
                           VG_(fnptr_to_fnentry)(drd_trace_store_4),
                           argv);
    break;
  case 8:
    argv = mkIRExprVec_1(addr_expr);
    di = unsafeIRDirty_0_N(/*regparms*/1,
                           "drd_trace_store_8",
                           VG_(fnptr_to_fnentry)(drd_trace_store_8),
                           argv);
    break;
  default:
    size_expr = mkIRExpr_HWord(size);
    argv = mkIRExprVec_2(addr_expr, size_expr);
    di = unsafeIRDirty_0_N(/*regparms*/2,
                           "drd_trace_store",
                           VG_(fnptr_to_fnentry)(drd_trace_store),
                           argv);
    break;
  }
  addStmtToIRSB(bb, IRStmt_Dirty(di));
}
Beispiel #10
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;
}
Beispiel #11
0
static
IRBB* CLG_(instrument)( VgCallbackClosure* closure,
                        IRBB* bbIn,
                        VexGuestLayout* layout,
                        VexGuestExtents* vge,
                        IRType gWordTy, IRType hWordTy )
{
    Int      i;
    IRBB*    bbOut;
    IRStmt*  st, *stnext;
    Addr     instrAddr, origAddr;
    UInt     instrLen = 0, dataSize;
    UInt     instrCount, costOffset;
    IRExpr  *loadAddrExpr, *storeAddrExpr;

    BB*         bb;

    IRDirty* di;
    IRExpr  *arg1, **argv;

    Bool        bb_seen_before     = False;
    UInt        cJumps = 0, cJumpsCorrected;
    Bool        beforeIBoundary, instrIssued;

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

    // No instrumentation if it is switched off
    if (! CLG_(instrument_state)) {
        CLG_DEBUG(5, "instrument(BB %p) [Instrumentation OFF]\n",
                  (Addr)closure->readdr);
        return bbIn;
    }

    CLG_DEBUG(3, "+ instrument(BB %p)\n", (Addr)closure->readdr);

    /* Set up BB for instrumented IR */
    bbOut           = emptyIRBB();
    bbOut->tyenv    = dopyIRTypeEnv(bbIn->tyenv);
    bbOut->next     = dopyIRExpr(bbIn->next);
    bbOut->jumpkind = bbIn->jumpkind;

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

    // Get the first statement, and origAddr from it
    CLG_ASSERT(bbIn->stmts_used > 0);
    st = bbIn->stmts[i];
    CLG_ASSERT(Ist_IMark == st->tag);
    instrAddr = origAddr = (Addr)st->Ist.IMark.addr;
    CLG_ASSERT(origAddr == st->Ist.IMark.addr);  // XXX: check no overflow

    /* Get BB (creating if necessary).
     * JS: The hash table is keyed with orig_addr_noredir -- important!
     * JW: Why? If it is because of different chasing of the redirection,
     *     this is not needed, as chasing is switched off in callgrind
     */
    bb = CLG_(get_bb)(origAddr, bbIn, &bb_seen_before);
    //bb = CLG_(get_bb)(orig_addr_noredir, bbIn, &bb_seen_before);

    /*
     * Precondition:
     * - jmps_passed has number of cond.jumps passed in last executed BB
     * - current_bbcc has a pointer to the BBCC of the last executed BB
     *   Thus, if bbcc_jmpkind is != -1 (JmpNone),
     *     current_bbcc->bb->jmp_addr
     *   gives the address of the jump source.
     *
     * The BBCC setup does 2 things:
     * - trace call:
     *   * Unwind own call stack, i.e sync our ESP with real ESP
     *     This is for ESP manipulation (longjmps, C++ exec handling) and RET
     *   * For CALLs or JMPs crossing objects, record call arg +
     *     push are on own call stack
     *
     * - prepare for cache log functions:
     *   Set current_bbcc to BBCC that gets the costs for this BB execution
     *   attached
     */

    // helper call to setup_bbcc, with pointer to basic block info struct as argument
    arg1 = mkIRExpr_HWord( (HWord)bb );
    argv = mkIRExprVec_1(arg1);
    di = unsafeIRDirty_0_N( 1, "setup_bbcc",
                            VG_(fnptr_to_fnentry)( & CLG_(setup_bbcc) ),
                            argv);
    addStmtToIRBB( bbOut, IRStmt_Dirty(di) );

    instrCount = 0;
    costOffset = 0;

    // loop for each host instruction (starting from 'i')
    do {

        // We should be at an IMark statement
        CLG_ASSERT(Ist_IMark == st->tag);

        // Reset stuff for this original instruction
        loadAddrExpr = storeAddrExpr = NULL;
        instrIssued = False;
        dataSize = 0;

        // Process all the statements for this original instruction (ie. until
        // the next IMark statement, or the end of the block)
        do {
            i++;
            stnext = ( i < bbIn->stmts_used ? bbIn->stmts[i] : NULL );
            beforeIBoundary = !stnext || (Ist_IMark == stnext->tag);
            collectStatementInfo(bbIn->tyenv, bbOut, st, &instrAddr, &instrLen,
                                 &loadAddrExpr, &storeAddrExpr, &dataSize, hWordTy);

            // instrument a simulator call before conditional jumps
            if (st->tag == Ist_Exit) {
                // Nb: instrLen will be zero if Vex failed to decode it.
                // Also Client requests can appear to be very large (eg. 18
                // bytes on x86) because they are really multiple instructions.
                CLG_ASSERT( 0 == instrLen ||
                            bbIn->jumpkind == Ijk_ClientReq ||
                            (instrLen >= VG_MIN_INSTR_SZB &&
                             instrLen <= VG_MAX_INSTR_SZB) );

                // Add instrumentation before this statement
                endOfInstr(bbOut, &(bb->instr[instrCount]), bb_seen_before,
                           instrAddr - origAddr, instrLen, dataSize, &costOffset,
                           instrIssued, loadAddrExpr, storeAddrExpr);

                // prepare for a possible further simcall in same host instr
                loadAddrExpr = storeAddrExpr = NULL;
                instrIssued = True;

                if (!bb_seen_before) {
                    bb->jmp[cJumps].instr = instrCount;
                    bb->jmp[cJumps].skip = False;
                }

                /* Update global variable jmps_passed (this is before the jump!)
                 * A correction is needed if VEX inverted the last jump condition
                 */
                cJumpsCorrected = cJumps;
                if ((cJumps+1 == bb->cjmp_count) && bb->cjmp_inverted) cJumpsCorrected++;
                addConstMemStoreStmt( bbOut, (UWord) &CLG_(current_state).jmps_passed,
                                      cJumpsCorrected, hWordTy);

                cJumps++;
            }

            addStmtToIRBB( bbOut, st );
            st = stnext;
        }
        while (!beforeIBoundary);

        // Add instrumentation for this original instruction.
        if (!instrIssued || (loadAddrExpr != 0) || (storeAddrExpr !=0))
            endOfInstr(bbOut, &(bb->instr[instrCount]), bb_seen_before,
                       instrAddr - origAddr, instrLen, dataSize, &costOffset,
                       instrIssued, loadAddrExpr, storeAddrExpr);

        instrCount++;
    }
    while (st);

    /* Always update global variable jmps_passed (at end of BB)
     * A correction is needed if VEX inverted the last jump condition
     */
    cJumpsCorrected = cJumps;
    if (bb->cjmp_inverted) cJumpsCorrected--;
    addConstMemStoreStmt( bbOut, (UWord) &CLG_(current_state).jmps_passed,
                          cJumpsCorrected, hWordTy);

    /* This stores the instr of the call/ret at BB end */
    bb->jmp[cJumps].instr = instrCount-1;

    CLG_ASSERT(bb->cjmp_count == cJumps);
    CLG_ASSERT(bb->instr_count == instrCount);

    instrAddr += instrLen;
    if (bb_seen_before) {
        CLG_ASSERT(bb->instr_len == instrAddr - origAddr);
        CLG_ASSERT(bb->cost_count == costOffset);
        CLG_ASSERT(bb->jmpkind == bbIn->jumpkind);
    }
    else {
        bb->instr_len = instrAddr - origAddr;
        bb->cost_count = costOffset;
        bb->jmpkind = bbIn->jumpkind;
    }

    CLG_DEBUG(3, "- instrument(BB %p): byteLen %u, CJumps %u, CostLen %u\n",
              origAddr, bb->instr_len, bb->cjmp_count, bb->cost_count);
    if (cJumps>0) {
        CLG_DEBUG(3, "                     [ ");
        for (i=0; i<cJumps; i++)
            CLG_DEBUG(3, "%d ", bb->jmp[i].instr);
        CLG_DEBUG(3, "], last inverted: %s \n", bb->cjmp_inverted ? "yes":"no");
    }

    return bbOut;
}
Beispiel #12
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;
}
Beispiel #13
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;
}
Beispiel #14
0
/* If a tool wants to allow gdbserver to do something at Addr, then
   VG_(add_stmt_call_gdbserver) will add in IRSB a call to a helper
   function.  This helper function will check if the process must be
   stopped at the instruction Addr: either there is a break at Addr or
   the process is being single-stepped.  Typical usage of the below is to
   instrument an Ist_IMark to allow the debugger to interact at any
   instruction being executed.  As soon as there is one break in a block,
   then to allow single stepping in this block (and possible insertions
   of other breaks in the same sb_in while the process is stopped), a
   debugger statement will be inserted for all instructions of a block. */
static void VG_(add_stmt_call_gdbserver) 
     (IRSB* sb_in,                /* block being translated */
      VexGuestLayout* layout, 
      VexGuestExtents* vge,
      IRType gWordTy, IRType hWordTy,
      Addr  iaddr,                /* Addr of instruction being instrumented */
      UChar delta,                /* delta to add to iaddr to obtain IP */
      IRSB* irsb)                 /* irsb block to which call is added */
{
   void*    fn;
   const HChar*   nm;
   IRExpr** args;
   Int      nargs;
   IRDirty* di;

   /* first store the address in the program counter so that the check
      done by VG_(helperc_CallDebugger) will be based on the correct
      program counter.  We might make this more efficient by rather
      searching for assignement to program counter and instrumenting
      that but the below is easier and I guess that the optimiser will
      remove the redundant store. And in any case, when debugging a
      piece of code, the efficiency requirement is not critical: very
      few blocks will be instrumented for debugging. */

   /* For platforms on which the IP can differ from the addr of the instruction
      being executed, we need to add the delta to obtain the IP.
      This IP will be given to gdb (e.g. if a breakpoint is put at iaddr).

      For ARM, this delta will ensure that the thumb bit is set in the
      IP when executing thumb code. gdb uses this thumb bit a.o.
      to properly guess the next IP for the 'step' and 'stepi' commands. */
   vg_assert(delta <= 1);
   addStmtToIRSB(irsb, IRStmt_Put(layout->offset_IP ,
                                  mkIRExpr_HWord(iaddr + (Addr)delta)));

   fn    = &VG_(helperc_CallDebugger);
   nm    = "VG_(helperc_CallDebugger)";
   args  = mkIRExprVec_1(mkIRExpr_HWord (iaddr));
   nargs = 1;
   
   di = unsafeIRDirty_0_N( nargs/*regparms*/, nm, 
                           VG_(fnptr_to_fnentry)( fn ), args );

   /* Note: in fact, a debugger call can read whatever register
      or memory. It can also write whatever register or memory.
      So, in theory, we have to indicate the whole universe
      can be read and modified. It is however not critical
      to indicate precisely what is being read/written
      as such indications are needed for tool error detection
      and we do not want to have errors being detected for
      gdb interactions. */
   
   di->nFxState = 2;
   di->fxState[0].fx        = Ifx_Read;
   di->fxState[0].offset    = layout->offset_SP;
   di->fxState[0].size      = layout->sizeof_SP;
   di->fxState[0].nRepeats  = 0;
   di->fxState[0].repeatLen = 0;
   di->fxState[1].fx        = Ifx_Modify;
   di->fxState[1].offset    = layout->offset_IP;
   di->fxState[1].size      = layout->sizeof_IP;
   di->fxState[1].nRepeats  = 0;
   di->fxState[1].repeatLen = 0;

   addStmtToIRSB(irsb, IRStmt_Dirty(di));

}
Beispiel #15
0
// This inserts an IR Statement responsible for calling func
// code before the instruction at addr is executed. This is primarily
// used for inserting the call to enter_function on function entry.
// It is also used for handling of 'function priming' for GCC 3 (see
// comment above prime_function). The result of looking up addr in
// table will be passed to func as it's only argument. This function
// does nothing if it is unable to successfully look up addr in the
// provided table.
static void handle_possible_entry_func(MCEnv *mce, Addr64 addr,
				       struct genhashtable *table,
				       const char *func_name,
				       entry_func func) {
  IRDirty  *di;
  FunctionEntry *entry = gengettable(table, (void *)(Addr)addr);

  if(!entry) {
      return;
  }

  // If fjalar_trace_prog_pts_filename is on (we are using a ppt list
  // file), then DO NOT generate IR code to call helper functions for
  // functions whose name is NOT located in prog_pts_tree. It's faster
  // to filter them out at translation-time instead of run-time
  if (entry && (!fjalar_trace_prog_pts_filename ||
		prog_pts_tree_entry_found(entry))) {
    UWord entry_w = (UWord)entry;
    di = unsafeIRDirty_0_N(1/*regparms*/, func_name, func,
			 mkIRExprVec_1(IRExpr_Const(IRConst_UWord(entry_w))));

    // For function entry, we are interested in observing the stack
    // and frame pointers so make sure that they're updated by setting
    // the proper annotations:

    entry->entryPC = addr;

    FJALAR_DPRINTF("Found a valid entry point at %x for\n", (UInt)addr);

    // We need all general purpose registers.
    di->nFxState = 9;
    vex_bzero(&di->fxState, sizeof(di->fxState));

    di->fxState[0].fx     = Ifx_Read;
    di->fxState[0].offset = mce->layout->offset_SP;
    di->fxState[0].size   = mce->layout->sizeof_SP;
    di->fxState[1].fx     = Ifx_Read;
    di->fxState[1].offset = mce->layout->offset_FP;
    di->fxState[1].size   = mce->layout->sizeof_FP;
    di->fxState[2].fx     = Ifx_Read;
    di->fxState[2].offset = mce->layout->offset_IP;
    di->fxState[2].size   = mce->layout->sizeof_IP;

    di->fxState[3].fx     = Ifx_Read;
    di->fxState[3].offset = mce->layout->offset_xAX;
    di->fxState[3].size   = mce->layout->sizeof_xAX;
    di->fxState[4].fx     = Ifx_Read;
    di->fxState[4].offset = mce->layout->offset_xBX;
    di->fxState[4].size   = mce->layout->sizeof_xBX;
    di->fxState[5].fx     = Ifx_Read;
    di->fxState[5].offset = mce->layout->offset_xCX;
    di->fxState[5].size   = mce->layout->sizeof_xCX;

    di->fxState[6].fx     = Ifx_Read;
    di->fxState[6].offset = mce->layout->offset_xDX;
    di->fxState[6].size   = mce->layout->sizeof_xDX;
    di->fxState[7].fx     = Ifx_Read;
    di->fxState[7].offset = mce->layout->offset_xSI;
    di->fxState[7].size   = mce->layout->sizeof_xSI;
    di->fxState[8].fx     = Ifx_Read;
    di->fxState[8].offset = mce->layout->offset_xDI;
    di->fxState[8].size   = mce->layout->sizeof_xDI;

    stmt('V',  mce, IRStmt_Dirty(di) );
  }
}
Beispiel #16
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) );
}
Beispiel #17
0
// Handle a function exit statement, which contains a jump kind of
// 'Ret'.  It seems pretty accurate to cue off of currentAddr, a value
// that is updated every time an Ist_IMark statement is translated,
// which is quite often
void handle_possible_exit(MCEnv* mce, IRJumpKind jk) {
  if (Ijk_Ret == jk) {
    IRDirty  *di;

    FunctionEntry* curFuncPtr = getFunctionEntryFromAddr(currentAddr);

    if (curFuncPtr &&
	// Also, if fjalar_trace_prog_pts_filename is on (we are
	// reading in a ppt list file), then DO NOT generate IR code
	// to call helper functions for functions whose names are NOT
	// located in prog_pts_tree.  This will greatly speed up
	// processing because these functions are filtered out at
	// translation-time, not at run-time
	(!fjalar_trace_prog_pts_filename ||
	 prog_pts_tree_entry_found(curFuncPtr))) {

      FJALAR_DPRINTF("[handle_possible_exit] %s - %x\n", curFuncPtr->fjalar_name, (UInt)currentAddr);

      // The only argument to exit_function() is a pointer to the
      // FunctionEntry for the function that we are exiting
      di = unsafeIRDirty_0_N(1/*regparms*/,
			     "exit_function",
			     &exit_function,
			     mkIRExprVec_1(IRExpr_Const(IRConst_UWord((Addr)curFuncPtr))));

      // For function exit, we are interested in observing  all general purpose
      // integer registers,  FTOP, and FPREG[], so make sure that they are
      // updated by setting the proper annotations.
      di->nFxState = 11;
      vex_bzero(&di->fxState, sizeof(di->fxState));

      di->fxState[0].fx     = Ifx_Read;
      di->fxState[0].offset = mce->layout->offset_SP;
      di->fxState[0].size   = mce->layout->sizeof_SP;
      di->fxState[1].fx     = Ifx_Read;
      di->fxState[1].offset = mce->layout->offset_FP;
      di->fxState[1].size   = mce->layout->sizeof_FP;
      di->fxState[2].fx     = Ifx_Read;
      di->fxState[2].offset = mce->layout->offset_IP;
      di->fxState[2].size   = mce->layout->sizeof_IP;

      di->fxState[3].fx     = Ifx_Read;
      di->fxState[3].offset = mce->layout->offset_xAX;
      di->fxState[3].size   = mce->layout->sizeof_xAX;
      di->fxState[4].fx     = Ifx_Read;
      di->fxState[4].offset = mce->layout->offset_xBX;
      di->fxState[4].size   = mce->layout->sizeof_xBX;
      di->fxState[5].fx     = Ifx_Read;
      di->fxState[5].offset = mce->layout->offset_xCX;
      di->fxState[5].size   = mce->layout->sizeof_xCX;

      di->fxState[6].fx     = Ifx_Read;
      di->fxState[6].offset = mce->layout->offset_xDX;
      di->fxState[6].size   = mce->layout->sizeof_xDX;
      di->fxState[7].fx     = Ifx_Read;
      di->fxState[7].offset = mce->layout->offset_xSI;
      di->fxState[7].size   = mce->layout->sizeof_xSI;
      di->fxState[8].fx     = Ifx_Read;
      di->fxState[8].offset = mce->layout->offset_xDI;
      di->fxState[8].size   = mce->layout->sizeof_xDI;

      di->fxState[9].fx     = Ifx_Read;
      di->fxState[9].offset = offsetof(VexGuestArchState, guest_FTOP);
      di->fxState[9].size   = sizeof(UInt); /* FTOP is 4 bytes even on x64 */
      di->fxState[10].fx     = Ifx_Read;
      di->fxState[10].offset = offsetof(VexGuestArchState, guest_FPREG);
      di->fxState[10].size   = 8 * sizeof(ULong);

      stmt('V',  mce, IRStmt_Dirty(di) );
    }
  }
}