static
dr_emit_flags_t bb_event(void* drcontext, void *tag, instrlist_t* bb,
                         bool for_trace, bool translating)
{
    instr_t *instr;
    instr_t *next_instr;
    reg_t in_eax = -1;

    for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
        next_instr = instr_get_next(instr);
        if (instr_get_opcode(instr) == OP_mov_imm &&
            opnd_get_reg(instr_get_dst(instr, 0)) == REG_EAX)
            in_eax = opnd_get_immed_int(instr_get_src(instr, 0));
        if (instr_is_syscall(instr) &&
            in_eax == SYS_getpid) {
            instr_t *myval = INSTR_CREATE_mov_imm
                (drcontext, opnd_create_reg(REG_EAX), OPND_CREATE_INT32(-7));
            instr_set_translation(myval, instr_get_app_pc(instr));
            instrlist_preinsert(bb, instr, myval);
            instrlist_remove(bb, instr);
            instr_destroy(drcontext, instr);
        }
    }
    return DR_EMIT_DEFAULT;
}
Example #2
0
static dr_emit_flags_t
bb_event(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating)
{
    instr_t *instr, *next_instr;
    
    for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
        next_instr = instr_get_next(instr);

        if (instr_is_cbr(instr)) {
            /* Conditional branch.  We can determine the target and
             * fallthrough addresses here, but we want to note the
             * edge if and when it actually executes at runtime.
             * Instead of using dr_insert_cbr_instrumentation(), we'll
             * insert separate instrumentation for the taken and not
             * taken cases and remove the instrumentation for an edge
             * after it executes.
             */
            cbr_state_t state;
            bool insert_taken, insert_not_taken;
            app_pc src = instr_get_app_pc(instr);
            
            /* First look up the state of this branch so we
             * know what instrumentation to insert, if any.
             */
            elem_t *elem = lookup(table, src);
            
            if (elem == NULL) {
                state = CBR_NEITHER;
                insert(table, src, CBR_NEITHER);
            }
            else {
                state = elem->state;
            }
            
            insert_taken = (state & CBR_TAKEN) == 0;
            insert_not_taken = (state & CBR_NOT_TAKEN) == 0;
            
            if (insert_taken || insert_not_taken) {
                app_pc fall = (app_pc)decode_next_pc(drcontext, (byte *)src);
                app_pc targ = instr_get_branch_target_pc(instr);
                
                /* Redirect the existing cbr to jump to a callout for
                 * the 'taken' case.  We'll insert a 'not-taken'
                 * callout at the fallthrough address.
                 */
                instr_t *label = INSTR_CREATE_label(drcontext);
                /* should be meta, and meta-instrs shouldn't have translations */
                instr_set_meta_no_translation(instr);
                /* it may not reach (in particular for x64) w/ our added clean call */
                if (instr_is_cti_short(instr)) {
                    /* if jecxz/loop we want to set the target of the long-taken
                     * so set instr to the return value
                     */
                    instr = instr_convert_short_meta_jmp_to_long(drcontext, bb, instr);
                }
                instr_set_target(instr, opnd_create_instr(label));
                
                if (insert_not_taken) {
                    /* Callout for the not-taken case.  Insert after
                     * the cbr (i.e., 3rd argument is NULL). 
                     */
                    dr_insert_clean_call(drcontext, bb, NULL, 
                                         (void*)at_not_taken,
                                         false /* don't save fp state */, 
                                         2 /* 2 args for at_not_taken */,
                                         OPND_CREATE_INTPTR(src),
                                         OPND_CREATE_INTPTR(fall));
                }
                
                /* After the callout, jump to the original fallthrough
                 * address.  Note that this is an exit cti, and should
                 * not be a meta-instruction.  Therefore, we use
                 * preinsert instead of meta_preinsert, and we must
                 * set the translation field.  On Windows, this jump
                 * and the final jump below never execute since the
                 * at_taken and at_not_taken callouts redirect
                 * execution and never return.  However, since the API
                 * expects clients to produced well-formed code, we
                 * insert explicit exits from the block for Windows as
                 * well as Linux.
                 */
                instrlist_preinsert(bb, NULL,
                                    INSTR_XL8(INSTR_CREATE_jmp
                                              (drcontext, opnd_create_pc(fall)), fall));
                
                /* label goes before the 'taken' callout */
                MINSERT(bb, NULL, label);
                
                if (insert_taken) {
                    /* Callout for the taken case */
                    dr_insert_clean_call(drcontext, bb, NULL,
                                         (void*)at_taken,
                                         false /* don't save fp state */,
                                         2 /* 2 args for at_taken */,
                                         OPND_CREATE_INTPTR(src),
                                         OPND_CREATE_INTPTR(targ));
                }
                
                /* After the callout, jump to the original target
                 * block (this should not be a meta-instruction).
                 */
                instrlist_preinsert(bb, NULL,
                                    INSTR_XL8(INSTR_CREATE_jmp
                                              (drcontext, opnd_create_pc(targ)), targ));
            }
        }
    }
    /* since our added instrumentation is not constant, we ask to store
     * translations now
     */
    return DR_EMIT_STORE_TRANSLATIONS;
}
Example #3
0
dr_emit_flags_t
bb_event(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating)
{
    instr_t *instr, *next_instr;

    app_pc bb_addr = dr_fragment_app_pc(tag);
    if (bb_addr == start_pc) {
        instrument = true;
    } else if (bb_addr == stop_pc) {
        instrument = false;
    }

    if (!instrument) {
        return DR_EMIT_DEFAULT;
    }

    for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
        next_instr = instr_get_next(instr);

        /*
         * Conditional branch. We can determine the target and
         * fallthrough addresses here, but we need to instrument if we
         * want to record the edge only if it actually executes at
         * runtime. Instead of using dr_insert_cbr_instrumentation,
         * we'll insert separate instrumentation for the taken and not
         * taken cases and remove it separately after we see each
         * case.
         */
        if (instr_is_cbr(instr)) {
            app_pc src = instr_get_app_pc(instr);

            cbr_state_t state;
            bool insert_taken, insert_not_taken;

            /* First look up the state of this branch so we
             * know what instrumentation to insert, if any.
             */
            elem_t *elem = lookup(table, src);

            if (elem == NULL) {
                state = CBR_NONE;
                insert(table, src, CBR_NONE);
            } else {
                state = elem->state;
            }

            insert_taken = (state & CBR_TAKEN) == 0;
            insert_not_taken = (state & CBR_NOT_TAKEN) == 0;

            if (insert_taken || insert_not_taken) {
                app_pc fall = (app_pc)decode_next_pc(drcontext, (byte *)src);
                app_pc targ = instr_get_branch_target_pc(instr);

                /*
                 * Redirect the cbr to jump to the 'taken' callout.
                 * We'll insert a 'not-taken' callout at fallthrough
                 * address.
                 */
                instr_t *label = INSTR_CREATE_label(drcontext);
                instr_set_meta(instr);
                instr_set_translation(instr, NULL);
                /* If this is a short cti, make sure it can reach its new target */
                if (instr_is_cti_short(instr)) {
                    /* if jecxz/loop we want to set the target of the long-taken
                     * so set instr to the return value
                     */
                    instr = instr_convert_short_meta_jmp_to_long(drcontext, bb, instr);
                }
                instr_set_target(instr, opnd_create_instr(label));

                if (insert_not_taken) {
                    /*
                     * Callout for the not-taken case
                     */
                    dr_insert_clean_call(drcontext, bb, NULL, (void *)at_not_taken,
                                         false /* don't save fp state */,
                                         2 /* 2 args for at_not_taken */,
                                         OPND_CREATE_INTPTR((ptr_uint_t)src),
                                         OPND_CREATE_INTPTR((ptr_uint_t)fall));
                }

                /*
                 * Jump to the original fall-through address.
                 * (This should not be a meta-instruction).
                 */
                instrlist_preinsert(
                    bb, NULL,
                    INSTR_XL8(INSTR_CREATE_jmp(drcontext, opnd_create_pc(fall)), fall));

                /* label goes before the 'taken' callout */
                MINSERT(bb, NULL, label);

                if (insert_taken) {
                    /*
                     * Callout for the taken case
                     */
                    dr_insert_clean_call(drcontext, bb, NULL, (void *)at_taken,
                                         false /* don't save fp state */,
                                         2 /* 2 args for at_taken */,
                                         OPND_CREATE_INTPTR((ptr_uint_t)src),
                                         OPND_CREATE_INTPTR((ptr_uint_t)targ));
                }

                /*
                 * Jump to the original target block (this should
                 * not be a meta-instruction).
                 */
                instrlist_preinsert(
                    bb, NULL,
                    INSTR_XL8(INSTR_CREATE_jmp(drcontext, opnd_create_pc(targ)), targ));
            }
        }
    }
    /* since our added instrumentation is not constant, we ask to store
     * translations now
     */
    return DR_EMIT_STORE_TRANSLATIONS;
}
Example #4
0
void
test_dr_insert_it_instrs_cbr(void *dcontext)
{
    instrlist_t *ilist = instrlist_create(dcontext);
    instr_t *where = INSTR_CREATE_label(dcontext);

    instr_t *instr_it1, *instr_it2, *instr_it3;
    byte buffer[4096];

    instrlist_append(ilist, where);
    instrlist_preinsert(ilist, where, XINST_CREATE_move
            (dcontext,
             opnd_create_reg(DR_REG_R1),
             opnd_create_reg(DR_REG_R2)));
    instrlist_preinsert(ilist, where, XINST_CREATE_jump
            (dcontext,
             opnd_create_instr(where)));
    instrlist_preinsert(ilist, where, XINST_CREATE_move
            (dcontext,
             opnd_create_reg(DR_REG_R1),
             opnd_create_reg(DR_REG_R2)));
    instrlist_preinsert(ilist, where, XINST_CREATE_move
            (dcontext,
             opnd_create_reg(DR_REG_R1),
             opnd_create_reg(DR_REG_R2)));
    instrlist_preinsert(ilist, where, XINST_CREATE_jump
            (dcontext,
             opnd_create_instr(where)));
    instrlist_preinsert(ilist, where, XINST_CREATE_move
            (dcontext,
             opnd_create_reg(DR_REG_R1),
             opnd_create_reg(DR_REG_R2)));
    instrlist_preinsert(ilist, where, XINST_CREATE_move
            (dcontext,
             opnd_create_reg(DR_REG_R1),
             opnd_create_reg(DR_REG_R2)));
    instrlist_preinsert(ilist, where, XINST_CREATE_move
            (dcontext,
             opnd_create_reg(DR_REG_R1),
             opnd_create_reg(DR_REG_R2)));
    instrlist_preinsert(ilist, where, XINST_CREATE_jump
            (dcontext,
             opnd_create_instr(where)));
    /* set them all to be predicated and reinstate it instrs */
    for (where = instrlist_first(ilist); where; where = instr_get_next(where)) {
        bool ok = instr_set_isa_mode(where, DR_ISA_ARM_THUMB);
        DR_ASSERT(ok);
        instr_set_predicate(where, DR_PRED_LS);
    }
    dr_insert_it_instrs(dcontext, ilist);

    /* Make sure it was encoded properly, noting that the branches
     * should *not* be in any IT-block.
     *  it
     *  mov.ls r1, r2
     *  b.ls   @0x47366864
     *  itt
     *  mov.ls r1, r2
     *  mov.ls r1, r2
     *  b.ls   @0x47366864
     *  ittt
     *  mov.ls r1, r2
     *  mov.ls r1, r2
     *  mov.ls r1, r2
     *  b.ls   @0x47366864
     */
    instr_it1 = instrlist_first(ilist);
    instr_it2 = instr_get_next(instr_get_next(instr_get_next(instr_it1)));
    instr_it3 = instr_get_next(instr_get_next(instr_get_next(instr_get_next(instr_it2))));
    DR_ASSERT(instr_get_opcode(instr_it1) == OP_it);
    DR_ASSERT(instr_it_block_get_count(instr_it1) == 1);
    DR_ASSERT(instr_get_opcode(instr_it2) == OP_it);
    DR_ASSERT(instr_it_block_get_count(instr_it2) == 2);
    DR_ASSERT(instr_get_opcode(instr_it3) == OP_it);
    DR_ASSERT(instr_it_block_get_count(instr_it3) == 3);
    instrlist_encode(dcontext, ilist, buffer, true);
}
Example #5
0
/*
 * The main function called to instrument each machine instruction.
 */
static dr_emit_flags_t instrument_instr(
    void *drcontext, void *tag, instrlist_t *bb, instr_t *instr,
    bool for_trace, bool translating, void *user_data)
{
    char *loc = NULL;

    /*
     * If this instruction is the first in its basic block, call
     * log_pc to record that we're executing this block at all.
     */
    if (drmgr_is_first_instr(drcontext, instr)) {
        instr_format_location(instr, &loc);
        dr_insert_clean_call(
            drcontext, bb, instr, (void *)log_pc, false,
            1, OPND_CREATE_INTPTR(loc));
    }

    /*
     * If the instruction reads or writes memory, log its access.
     */
    if (instr_reads_memory(instr) || instr_writes_memory(instr)) {
        for (int i = 0, limit = instr_num_srcs(instr); i < limit; i++)
            try_mem_opnd(drcontext, bb, instr, &loc,
                         instr_get_src(instr, i), false);
        for (int i = 0, limit = instr_num_dsts(instr); i < limit; i++)
            try_mem_opnd(drcontext, bb, instr, &loc,
                         instr_get_dst(instr, i), false);
    }

    /*
     * Now do opcode-specific checks.
     */
    int opcode = instr_get_opcode(instr);

    switch (opcode) {
      case OP_div:
      case OP_idiv:
        /*
         * x86 hardware divisions. The operand order for DR's
         * representation of these seem to be: 0 = denominator, 1 =
         * numerator MSW, 2 = numerator LSW.
         */
        instr_format_location(instr, &loc);
        dr_insert_clean_call(
            drcontext, bb, instr, (void *)log_div, false,
            3, instr_get_src(instr, 2), instr_get_src(instr, 0),
            OPND_CREATE_INTPTR(loc));
        break;
      case OP_shl:
      case OP_shr:
      case OP_sar:
      case OP_shlx:
      case OP_shrx:
      case OP_sarx:
      case OP_rol:
      case OP_ror:
      case OP_rcl:
      case OP_rcr:
        /*
         * Shift instructions. If they're register-controlled, log the
         * shift count.
         */
        {
            opnd_t shiftcount = instr_get_src(instr, 0);
            if (!opnd_is_immed(shiftcount)) {
                reg_id_t r0;
                drreg_status_t st;
                st = drreg_reserve_register(drcontext, bb, instr, NULL, &r0);
                DR_ASSERT(st == DRREG_SUCCESS);
                opnd_t op_r0 = opnd_create_reg(r0);
                instrlist_preinsert(bb, instr, INSTR_CREATE_movzx(
                                        drcontext, op_r0, shiftcount));
                instr_format_location(instr, &loc);
                dr_insert_clean_call(
                    drcontext, bb, instr, (void *)log_var_shift, false,
                    2, op_r0, OPND_CREATE_INTPTR(loc));
                st = drreg_unreserve_register(drcontext, bb, instr, r0);
                DR_ASSERT(st == DRREG_SUCCESS);
            }
        }
        break;
    }

    return DR_EMIT_DEFAULT;
}