Example #1
0
DR_EXPORT
bool
drx_aflags_are_dead(instr_t *where)
{
    instr_t *instr;
    uint flags;
    for (instr = where; instr != NULL; instr = instr_get_next(instr)) {
        /* we treat syscall/interrupt as aflags read */
        if (instr_is_syscall(instr) || instr_is_interrupt(instr))
            return false;
        flags = instr_get_arith_flags(instr, DR_QUERY_DEFAULT);
        if (TESTANY(EFLAGS_READ_ARITH, flags))
            return false;
        if (TESTALL(EFLAGS_WRITE_ARITH, flags))
            return true;
        if (instr_is_cti(instr)) {
            if (instr_is_app(instr) &&
                (instr_is_ubr(instr) || instr_is_call_direct(instr))) {
                instr_t *next = instr_get_next(instr);
                opnd_t   tgt  = instr_get_target(instr);
                /* continue on elision */
                if (next != NULL && instr_is_app(next) &&
                    opnd_is_pc(tgt) &&
                    opnd_get_pc(tgt) == instr_get_app_pc(next))
                    continue;
            }
            /* unknown target, assume aflags is live */
            return false;
        }
    }
    return false;
}
Example #2
0
static dr_emit_flags_t
event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr,
                      bool for_trace, bool translating, void *user_data)
{
    /* We test reserving across app instrs by reserving on each store and
     * unreserving on the subsequent instr.
     */
    drvector_t allowed;
    if (reg != DR_REG_NULL) {
        if (drreg_unreserve_register(drcontext, bb, instr, reg) != DRREG_SUCCESS)
            CHECK(false, "failed to unreserve");
        reg = DR_REG_NULL;
    }

    if (!instr_is_app(instr))
        return DR_EMIT_DEFAULT;
    if (!instr_writes_memory(instr))
        return DR_EMIT_DEFAULT;

    if (!drmgr_is_last_instr(drcontext, instr)) {
        drreg_init_and_fill_vector(&allowed, true);
        /* Limit the registers for more of a stress test: */
        drreg_set_vector_entry(&allowed, IF_X86_ELSE(DR_REG_XCX, DR_REG_R0), false);
        drreg_set_vector_entry(&allowed, IF_X86_ELSE(DR_REG_XDX, DR_REG_R1), false);
        if (drreg_reserve_register(drcontext, bb, instr, &allowed, &reg) != DRREG_SUCCESS)
            DR_ASSERT(false);
        drvector_delete(&allowed);
    }
    return DR_EMIT_DEFAULT;
}
Example #3
0
/* For each memory reference app instr, we insert inline code to fill the buffer
 * with an instruction entry and memory reference entries.
 */
static dr_emit_flags_t
event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr,
                      bool for_trace, bool translating, void *user_data)
{
    int i;
    reg_id_t *reg_next = (reg_id_t *)user_data;
    bool seen_memref = false;

    /* If the previous instruction was a write, we should handle it. */
    if (*reg_next != DR_REG_NULL)
        handle_post_write(drcontext, bb, instr, *reg_next);
    *reg_next = DR_REG_NULL;

    if (!instr_is_app(instr))
        return DR_EMIT_DEFAULT;
    if (!instr_writes_memory(instr))
        return DR_EMIT_DEFAULT;

    /* XXX: See above, in handle_post_write(). To simplify the handling of registers, we
     * assume no instruction has multiple distinct memory destination operands.
     */
    for (i = 0; i < instr_num_dsts(instr); ++i) {
        if (opnd_is_memory_reference(instr_get_dst(instr, i))) {
            if (seen_memref) {
                DR_ASSERT_MSG(false, "Found inst with multiple memory destinations");
                break;
            }
            *reg_next = instrument_mem(drcontext, bb, instr, instr_get_dst(instr, i));
            seen_memref = true;
        }
    }
    return DR_EMIT_DEFAULT;
}
Example #4
0
instr_t *
instrlist_last_app(instrlist_t *ilist)
{
    instr_t *last = ilist->last;
    if (last == NULL)
        return NULL;
    if (instr_is_app(last))
        return last;
    return instr_get_prev_app(last);
}
Example #5
0
/* event_bb_insert calls instrument_instr to instrument every
 * application memory reference.
 */
static dr_emit_flags_t
event_bb_insert(void *drcontext, void *tag, instrlist_t *bb,
                instr_t *instr, bool for_trace, bool translating,
                void *user_data)
{
    if (instr_get_app_pc(instr) == NULL || !instr_is_app(instr))
        return DR_EMIT_DEFAULT;
    instrument_instr(drcontext, bb, instr);
    return DR_EMIT_DEFAULT;
}
Example #6
0
/* returns the first app (non-meta) inst in the list */
instr_t *
instrlist_first_app(instrlist_t *ilist)
{
    instr_t *first = ilist->first;

    if (first == NULL)
        return NULL;
    if (instr_is_app(first))
        return first;

    return instr_get_next_app(first);
}
Example #7
0
/* Check if current instrumentation can be merged into previous aflags
 * (or on ARM, GPR) save/restore inserted by drx_restore_arith_flags.
 * Returns NULL if cannot merge. Otherwise, returns the right insertion point,
 * i.e., DRX_NOTE_AFLAGS_RESTORE_BEGIN label instr.
 *
 * This routine looks for labels inserted by drx_restore_arith_flags,
 * so changes to drx_restore_arith_flags may affect this routine.
 * On ARM the labels are from drx_insert_counter_update.
 */
static instr_t *
merge_prev_drx_spill(instr_t *where, bool aflags)
{
    instr_t *instr;
#ifdef DEBUG
    bool has_sahf = false;
#endif

    if (where == NULL)
        return NULL;
    instr = instr_get_prev(where);
    if (instr == NULL)
        return NULL;
    if (!instr_is_label(instr))
        return NULL;
    /* Check if prev instr is DRX_NOTE_AFLAGS_RESTORE_END.
     * We bail even there is only a label instr in between, which
     * might be a target of internal cti.
     */
    if (instr_get_note(instr) != NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_END))
        return NULL;

    /* find DRX_NOTE_AFLAGS_RESTORE_BEGIN */
    for (instr  = instr_get_prev(instr);
         instr != NULL;
         instr  = instr_get_prev(instr)) {
        if (instr_is_app(instr)) {
            /* we do not expect any app instr */
            ASSERT(false, "drx aflags restore is corrupted");
            return NULL;
        }
        if (instr_is_label(instr)) {
            if (instr_get_note(instr) == NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_BEGIN)) {
                ASSERT(!aflags || has_sahf, "missing sahf");
                return instr;
            }
            /* we do not expect any other label instr */
            ASSERT(false, "drx aflags restore is corrupted");
            return NULL;
#ifdef DEBUG
        } else {
            if (instr_get_note(instr) == NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_SAHF))
                has_sahf = true;
#endif
        }
    }
    return NULL;
}
Example #8
0
/* For each memory reference app instr, we insert inline code to fill the buffer
 * with an instruction entry and memory reference entries.
 */
static dr_emit_flags_t
event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr,
                      bool for_trace, bool translating, void *user_data)
{
    int i;

    if (!instr_is_app(instr))
        return DR_EMIT_DEFAULT;
    if (!instr_reads_memory(instr) && !instr_writes_memory(instr))
        return DR_EMIT_DEFAULT;

    /* insert code to add an entry for app instruction */
    instrument_instr(drcontext, bb, instr);

    /* insert code to add an entry for each memory reference opnd */
    for (i = 0; i < instr_num_srcs(instr); i++) {
        if (opnd_is_memory_reference(instr_get_src(instr, i)))
            instrument_mem(drcontext, bb, instr, instr_get_src(instr, i), false);
    }

    for (i = 0; i < instr_num_dsts(instr); i++) {
        if (opnd_is_memory_reference(instr_get_dst(instr, i)))
            instrument_mem(drcontext, bb, instr, instr_get_dst(instr, i), true);
    }

    /* insert code to call clean_call for processing the buffer */
    if (/* XXX i#1698: there are constraints for code between ldrex/strex pairs,
         * so we minimize the instrumentation in between by skipping the clean call.
         * As we're only inserting instrumentation on a memory reference, and the
         * app should be avoiding memory accesses in between the ldrex...strex,
         * the only problematic point should be before the strex.
         * However, there is still a chance that the instrumentation code may clear the
         * exclusive monitor state.
         * Using a fault to handle a full buffer should be more robust, and the
         * forthcoming buffer filling API (i#513) will provide that.
         */
        IF_AARCHXX_ELSE(!instr_is_exclusive_store(instr), true))
        dr_insert_clean_call(drcontext, bb, instr, (void *)clean_call, false, 0);

    return DR_EMIT_DEFAULT;
}
Example #9
0
static dr_emit_flags_t
event_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr,
                  bool for_trace, bool translating, void *user_data)
{
    /* ignore tool-inserted instrumentation */
    if (!instr_is_app(instr))
        return DR_EMIT_DEFAULT;

    /* instrument calls and returns -- ignore far calls/rets */
    if (instr_is_call_direct(instr)) {
        insert_counter_update(drcontext, bb, instr,
                              offsetof(per_thread_t, num_direct_calls));
    } else if (instr_is_call_indirect(instr)) {
        insert_counter_update(drcontext, bb, instr,
                              offsetof(per_thread_t, num_indirect_calls));
    } else if (instr_is_return(instr)) {
        insert_counter_update(drcontext, bb, instr, offsetof(per_thread_t, num_returns));
    }

    return DR_EMIT_DEFAULT;
}
Example #10
0
static dr_emit_flags_t
event_bb_analysis(void *drcontext, void *tag, instrlist_t *bb, bool for_trace,
                  bool translating, void **user_data)
{
    instr_t *instr;
    uint num_instrs;

#ifdef VERBOSE
    dr_printf("in dynamorio_basic_block(tag=" PFX ")\n", tag);
#    ifdef VERBOSE_VERBOSE
    instrlist_disassemble(drcontext, tag, bb, STDOUT);
#    endif
#endif
    /* Only count in app BBs */
    if (only_from_app.get_value()) {
        module_data_t *mod = dr_lookup_module(dr_fragment_app_pc(tag));
        if (mod != NULL) {
            bool from_exe = (mod->start == exe_start);
            dr_free_module_data(mod);
            if (!from_exe) {
                *user_data = NULL;
                return DR_EMIT_DEFAULT;
            }
        }
    }

    /* Count instructions. If an emulation client is running with this client,
     * we want to count all the original native instructions and the emulated
     * instruction but NOT the introduced native instructions used for emulation.
     */
    bool is_emulation = false;
    for (instr = instrlist_first(bb), num_instrs = 0; instr != NULL;
         instr = instr_get_next(instr)) {
        if (drmgr_is_emulation_start(instr)) {
            /* Each emulated instruction is replaced by a series of native
             * instructions delimited by labels indicating when the emulation
             * sequence begins and ends. It is the responsibility of the
             * emulation client to place the start/stop labels correctly.
             */
            num_instrs++;
            is_emulation = true;
            /* Data about the emulated instruction can be extracted from the
             * start label using the accessor function:
             * drmgr_get_emulated_instr_data()
             */
            continue;
        }
        if (drmgr_is_emulation_end(instr)) {
            is_emulation = false;
            continue;
        }
        if (is_emulation)
            continue;
        if (!instr_is_app(instr))
            continue;
        num_instrs++;
    }
    *user_data = (void *)(ptr_uint_t)num_instrs;

#if defined(VERBOSE) && defined(VERBOSE_VERBOSE)
    dr_printf("Finished counting for dynamorio_basic_block(tag=" PFX ")\n", tag);
    instrlist_disassemble(drcontext, tag, bb, STDOUT);
#endif
    return DR_EMIT_DEFAULT;
}