Ejemplo n.º 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;
}
Ejemplo n.º 2
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;
   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;

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

      // Add instrumentation for this original instruction.
      endOfInstr(bbOut, &bbInfo->instrs[ bbInfo_i ], bbSeenBefore,
                 instrAddr, instrLen, dataSize, loadAddrExpr, storeAddrExpr);

      bbInfo_i++;
   } 
   while (st);

   return bbOut;
}