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

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

   /* Set up BB, including copying of the where-next stuff. */
   cgs.bbOut           = emptyIRBB();
   cgs.bbOut->tyenv    = dopyIRTypeEnv(tyenv);
   tl_assert( isIRAtom(bbIn->next) );
   cgs.bbOut->next     = dopyIRExpr(bbIn->next);
   cgs.bbOut->jumpkind = bbIn->jumpkind;

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

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

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

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

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

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

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

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

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

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

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

            addEvent_Ir( &cgs, curr_inode );
            break;

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

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

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

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

         default:
            tl_assert(0);
            break;
      }

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

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

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

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

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

   return cgs.bbOut;
}
Example #3
0
static IRBB* cg_instrument ( IRBB* bbIn, VexGuestLayout* layout, 
                             IRType gWordTy, IRType hWordTy )
{
   Int      i, dataSize = 0, bbInfo_i;
   IRBB*    bbOut;
   IRStmt*  st;
   BB_info* bbInfo;
   Bool     bbSeenBefore = False, addedInstrumentation, addInstNow;
   Addr     instrAddr, origAddr;
   UInt     instrLen;
   IRExpr  *loadAddrExpr, *storeAddrExpr;

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

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

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

   // Get block info
   bbInfo = get_BB_info(bbIn, origAddr, &bbSeenBefore);
   bbInfo_i = 0;

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

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

      // Process all the statements for this original instruction (ie. until
      // the next IMark statement, or the end of the block)
      do {
         IRStmt* st2 = ( i+1 < bbIn->stmts_used ? bbIn->stmts[i+1] : NULL );

         addInstNow = handleOneStatement(bbIn->tyenv, bbOut, st, st2,
                                         &instrAddr, &instrLen, &loadAddrExpr,
                                         &storeAddrExpr, &dataSize);
         if (addInstNow) {
            tl_assert(!addedInstrumentation);
            addedInstrumentation = True;
            
            // Add instrumentation before this statement.
            instrumentInstr(bbOut, &bbInfo->instrs[ bbInfo_i ], bbSeenBefore,
                      instrAddr, instrLen, dataSize, loadAddrExpr, storeAddrExpr);
         }

         addStmtToIRBB( bbOut, st );

         i++;
         st = st2;
      } 
      while (st && Ist_IMark != st->tag);

      if (!addedInstrumentation) {
         // Add instrumentation now, after all the instruction's statements.
         instrumentInstr(bbOut, &bbInfo->instrs[ bbInfo_i ], bbSeenBefore,
                         instrAddr, instrLen, dataSize, loadAddrExpr, storeAddrExpr);
      }

      bbInfo_i++;
   }
   while (st);

   return bbOut;
}