Exemplo n.º 1
0
/* This event is called separately for each individual instruction in the bb. */
static dr_emit_flags_t
event_insert_instrumentation(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr,
                             bool for_trace, bool translating, void *user_data)
{
    bool bb_in_app;
    if (dr_fragment_app_pc(tag) >= app_base && dr_fragment_app_pc(tag) < app_end)
        bb_in_app = true;
    else
        bb_in_app = false;

    if (drmgr_is_first_instr(drcontext, instr)) {
        uint num_instrs = (uint)(ptr_uint_t)user_data;
        dr_insert_clean_call(drcontext, bb, instr,
                             (void *)(bb_in_app ? app_update : lib_update),
                             false /* save fpstate */, 1, OPND_CREATE_INT32(num_instrs));
    }

    if (instr_is_mbr(instr) && !instr_is_return(instr)) {
        /* Assuming most of the transfers between app and lib are paired, we
         * instrument indirect branches but not returns for better performance.
         */
        dr_insert_mbr_instrumentation(
            drcontext, bb, instr, (void *)(bb_in_app ? app_mbr : lib_mbr), SPILL_SLOT_1);
    }

    return DR_EMIT_DEFAULT;
}
Exemplo n.º 2
0
static dr_emit_flags_t
event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
                  bool for_trace, bool translating)
{
    instr_t *instr, *mbr = NULL;
    uint num_instrs;
    bool bb_in_app;

#ifdef VERBOSE
    dr_printf("in dynamorio_basic_block(tag="PFX")\n", tag);
# ifdef VERBOSE_VERBOSE
    instrlist_disassemble(drcontext, tag, bb, STDOUT);
# endif
#endif

    for (instr  = instrlist_first(bb), num_instrs = 0;
         instr != NULL;
         instr = instr_get_next(instr)) {
        /* only care about app instr */
        if (!instr_ok_to_mangle(instr))
            continue;
        num_instrs++;
        /* Assuming most of the transfers between app and lib are paired, we
         * instrument indirect branches but not returns for better performance.
         */
        if (instr_is_mbr(instr) && !instr_is_return(instr))
            mbr = instr;
    }

    if (dr_fragment_app_pc(tag) >= app_base &&
        dr_fragment_app_pc(tag) <  app_end)
        bb_in_app = true;
    else
        bb_in_app = false;
    dr_insert_clean_call(drcontext, bb, instrlist_first(bb),
                         (void *)(bb_in_app ? app_update : lib_update),
                         false /* save fpstate */, 1,
                         OPND_CREATE_INT32(num_instrs));
    if (mbr != NULL) {
        dr_insert_mbr_instrumentation(drcontext, bb, mbr,
                                      (void *)(bb_in_app ? app_mbr : lib_mbr),
                                      SPILL_SLOT_1);
    }

#if defined(VERBOSE) && defined(VERBOSE_VERBOSE)
    dr_printf("Finished instrumenting dynamorio_basic_block(tag="PFX")\n", tag);
    instrlist_disassemble(drcontext, tag, bb, STDOUT);
#endif
    return DR_EMIT_DEFAULT;
}
Exemplo n.º 3
0
// We stored the instr count in *bb_field in bb_analysis().
int
offline_instru_t::instrument_instr(void *drcontext, void *tag, void **bb_field,
                                   instrlist_t *ilist, instr_t *where,
                                   reg_id_t reg_ptr, reg_id_t reg_tmp, int adjust,
                                   instr_t *app)
{
    app_pc pc, modbase;
    uint modidx;
    offline_entry_t entry;
    // We write just once per bb.
    if ((ptr_uint_t)*bb_field > MAX_INSTR_COUNT)
        return adjust;

    pc = dr_fragment_app_pc(tag);
    if (drmodtrack_lookup(drcontext, pc, &modidx, &modbase) != DRCOVLIB_SUCCESS) {
        // FIXME i#2062: add non-module support.  The plan for instrs is to have
        // one entry w/ the start abs pc, and subsequent entries that pack the instr
        // length for 10 instrs, 4 bits each, into a pc.modoffs field.  We will
        // also need to store the type (read/write/prefetch*) and size for the
        // memrefs.
        modidx = 0;
        modbase = pc;
    }
    entry.pc.type = OFFLINE_TYPE_PC;
    // We put the ARM vs Thumb mode into the modoffs to ensure proper decoding.
    entry.pc.modoffs =
        dr_app_pc_as_jump_target(instr_get_isa_mode(where), pc) - modbase;
    entry.pc.modidx = modidx;
    entry.pc.instr_count = (ptr_uint_t)*bb_field;
    insert_save_pc(drcontext, ilist, where, reg_ptr, reg_tmp, adjust,
                   entry.combined_value);
    *(ptr_uint_t*)bb_field = MAX_INSTR_COUNT + 1;
    return (adjust + sizeof(offline_entry_t));
}
Exemplo n.º 4
0
static dr_emit_flags_t
bb_event(void* drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating)
{
    app_pc pc = dr_fragment_app_pc(tag);

    if (pc == start_pc) {
        dr_fprintf(STDERR, "starting syscall monitoring\n");
        monitoring = true;
    }
    else if (pc == stop_pc) {
        dr_fprintf(STDERR, "stopping syscall monitoring\n");
        monitoring = false;
    }
    else {
        instr_t* instr;
        instr_t* next_instr;

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

            next_instr = instr_get_next(instr);

            /* Insert a callback to at_syscall before every system call */
            if (instr_is_syscall(instr)) {
                dr_insert_clean_call(drcontext, bb, instr, at_syscall, false, 0);
            }
        }
    }
    return DR_EMIT_DEFAULT;
}
Exemplo n.º 5
0
static dr_emit_flags_t
event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *inst,
                      bool for_trace, bool translating, void *user_data)
{
    app_pc pc = dr_fragment_app_pc(tag);
    reg_id_t reg;
    /* We need a 2nd scratch reg for several operations on AArch32 and AArch64 only. */
    reg_id_t reg2 = DR_REG_NULL;

    /* We do all our work at the start of the block prior to the first instr */
    if (!drmgr_is_first_instr(drcontext, inst))
        return DR_EMIT_DEFAULT;

    /* We need a scratch register */
    if (drreg_reserve_register(drcontext, bb, inst, NULL, &reg) != DRREG_SUCCESS) {
        DR_ASSERT(false); /* cannot recover */
        return DR_EMIT_DEFAULT;
    }

#ifdef AARCHXX
    /* We need a second register here, because the drx_buf routines need a scratch reg
     * for AArch32 and AArch64.
     */
    if (drreg_reserve_register(drcontext, bb, inst, NULL, &reg2) != DRREG_SUCCESS) {
        DR_ASSERT(false); /* cannot recover */
        return DR_EMIT_DEFAULT;
    }
#endif

    /* load buffer pointer from TLS field */
    drx_buf_insert_load_buf_ptr(drcontext, buf, bb, inst, reg);


    /* store bb's start pc into the buffer */
    drx_buf_insert_buf_store(drcontext, buf, bb, inst, reg, reg2,
                             OPND_CREATE_INTPTR(pc), OPSZ_PTR, 0);

    /* Internally this will update the TLS buffer pointer by incrementing just the bottom
     * 16 bits of the pointer.
     */
    drx_buf_insert_update_buf_ptr(drcontext, buf, bb, inst, reg, reg2, sizeof(app_pc));

    if (drreg_unreserve_register(drcontext, bb, inst, reg) != DRREG_SUCCESS)
        DR_ASSERT(false);

#ifdef AARCHXX
    if (drreg_unreserve_register(drcontext, bb, inst, reg2) != DRREG_SUCCESS)
        DR_ASSERT(false);
#endif

    return DR_EMIT_DEFAULT;
}
Exemplo n.º 6
0
/* We collect the basic block information including offset from module base,
 * size, and num of instructions, and add it into a basic block table without
 * instrumentation.
 */
static dr_emit_flags_t
event_basic_block_analysis(void *drcontext, void *tag, instrlist_t *bb,
                           bool for_trace, bool translating, OUT void **user_data)
{
    per_thread_t *data;
    instr_t *instr;
    app_pc tag_pc, start_pc, end_pc;

    /* do nothing for translation */
    if (translating)
        return DR_EMIT_DEFAULT;

    data = (per_thread_t *)drmgr_get_tls_field(drcontext, tls_idx);
    /* Collect the number of instructions and the basic block size,
     * assuming the basic block does not have any elision on control
     * transfer instructions, which is true for default options passed
     * to DR but not for -opt_speed.
     */
    /* We separate the tag from the instr pc ranges to handle displaced code
     * such as for the vsyscall hook.
     */
    tag_pc = dr_fragment_app_pc(tag);
    start_pc = instr_get_app_pc(instrlist_first_app(bb));
    end_pc   = start_pc; /* for finding the size */
    for (instr  = instrlist_first_app(bb);
         instr != NULL;
         instr  = instr_get_next_app(instr)) {
        app_pc pc = instr_get_app_pc(instr);
        int len = instr_length(drcontext, instr);
        /* -opt_speed (elision) is not supported */
        /* For rep str expansion pc may be one back from start pc but equal to the tag. */
        ASSERT(pc != NULL && (pc >= start_pc || pc == tag_pc),
               "-opt_speed is not supported");
        if (pc + len > end_pc)
            end_pc = pc + len;
    }
    /* We allow duplicated basic blocks for the following reasons:
     * 1. Avoids handling issues like code cache consistency, e.g.,
     *    module load/unload, self-modifying code, etc.
     * 2. Avoids the overhead on duplication check.
     * 3. Stores more information on code cache events, e.g., trace building,
     *    repeated bb building, etc.
     * 4. The duplication can be easily handled in a post-processing step,
     *    which is required anyway.
     */
    bb_table_entry_add(drcontext, data, tag_pc, (uint)(end_pc - start_pc));

    if (go_native)
        return DR_EMIT_GO_NATIVE;
    else
        return DR_EMIT_DEFAULT;
}
Exemplo n.º 7
0
static dr_emit_flags_t
event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
                  bool for_trace, bool translating)
{
    instr_t *instr;
    for (instr  = instrlist_first_app(bb);
         instr != NULL;
         instr  = instr_get_next_app(instr)) {
        if (instr_is_cbr(instr)) {
            dr_insert_cbr_instrumentation_ex
                (drcontext, bb, instr, (void *)at_cbr,
                 OPND_CREATE_INTPTR(dr_fragment_app_pc(tag)));
        }
    }
    return DR_EMIT_DEFAULT;
}
Exemplo n.º 8
0
static
dr_emit_flags_t bb_event(void *drcontext, app_pc tag, instrlist_t *bb, bool for_trace, bool translating)
{
    instr_t *instr, *next_instr;
    app_pc bb_addr, instr_addr;
    bool found_section;

    bb_addr = dr_fragment_app_pc(tag);

    /* vsyscall: some versions of windows jump to 0x7ffe0300 to
     * execute a syscall; this address is not contained in any module.
     */
    if ((ptr_uint_t)bb_addr == 0x7ffe0300 ||
        (ptr_uint_t)bb_addr == 0x7ffe0302)
        return DR_EMIT_DEFAULT;

    if (!is_in_known_module(bb_addr, &found_section, &section)) {
        dr_fprintf(STDERR, "ERROR: BB addr "PFX" in unknown module\n", bb_addr);
    }
    if (!found_section) {
        dr_fprintf(STDERR, "ERROR: BB addr "PFX" isn't within a module section\n", bb_addr);
    }
    if ((section.Characteristics & IMAGE_SCN_CNT_CODE) == 0) {
        dr_fprintf(STDERR, "ERROR: BB addr "PFX" isn't within a code section\n", bb_addr);
    }

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

        instr_addr = instr_get_app_pc(instr);
        if (!is_in_known_module(instr_addr, &found_section, &section)) {
            dr_fprintf(STDERR, "ERROR: instr addr "PFX" in unknown module\n", instr_addr);
        }
        if (!found_section) {
            dr_fprintf(STDERR, "ERROR: instr addr "PFX" isn't within a module section\n", instr_addr);
        }
        if ((section.Characteristics & IMAGE_SCN_CNT_CODE) == 0) {
            dr_fprintf(STDERR, "ERROR: instr addr "PFX" isn't within a code section\n", instr_addr);
        }
        if (instr_addr == exit_proc_addr) {
            dr_fprintf(STDERR, "Hit kernel32!ExitProcess\n");
            exit_proc_addr = NULL;
        }
    }
    return DR_EMIT_DEFAULT;
}
Exemplo n.º 9
0
dr_emit_flags_t bb_event(void *drcontext, void *tag, instrlist_t *bb,
                         bool for_trace, bool translating)
{
    app_pc bb_addr = dr_fragment_app_pc(tag);
    dr_emit_flags_t flags = DR_EMIT_DEFAULT;
    if (bb_addr == start_pc) {
        instrument = true;
    }
    else if (bb_addr == stop_pc) {
        instrument = false;
    }

    if (instrument) {
        flags = instrument_bb(drcontext, tag, bb, for_trace, translating);
    }
    return flags;
}
Exemplo n.º 10
0
/* This event is called separately for each individual instruction in the bb. */
static dr_emit_flags_t
event_insert_instrumentation(void *drcontext, void *tag, instrlist_t *bb,
                             instr_t *instr, bool for_trace, bool translating,
                             void *user_data)
{
    if (drmgr_is_first_instr(drcontext, instr)) {
        uint num_instrs = (uint)(ptr_uint_t)user_data;
        int i;
        app_pc bb_addr = dr_fragment_app_pc(tag);
        for (i = 0; i < num_mods; i++) {
            if (mod_array[i].loaded &&
                mod_array[i].base <= bb_addr &&
                mod_array[i].end  >  bb_addr)
                break;
        }
        if (i == num_mods)
            i = UNKNOW_MODULE_IDX;
        /* We pass SPILL_SLOT_MAX+1 as drx will use drreg for spilling. */
        drx_insert_counter_update(drcontext, bb, instr, SPILL_SLOT_MAX+1,
                                  (void *)&mod_cnt[i], num_instrs, DRX_COUNTER_64BIT);
        drx_insert_counter_update(drcontext, bb, instr, SPILL_SLOT_MAX+1,
                                  (void *)&ins_count, num_instrs, DRX_COUNTER_64BIT);
    }

    if (instr_is_mbr(instr) && !instr_is_return(instr)) {
        /* Assuming most of the transfers between modules are paired, we
         * instrument indirect branches but not returns for better performance.
         * We assume that most cross module transfers happens via indirect
         * branches.
         * Direct branch with DGC or self-modify may also cross modules, but
         * it should be ok to ignore, and we can handle them more efficiently.
         */
        /* dr_insert_mbr_instrumentation is going to read app values, so we need a
         * drreg lazy restore "barrier" here.
         */
        drreg_status_t res =
            drreg_restore_app_values(drcontext, bb, instr, instr_get_target(instr), NULL);
        DR_ASSERT(res == DRREG_SUCCESS || res == DRREG_ERROR_NO_APP_VALUE);
        dr_insert_mbr_instrumentation(drcontext, bb, instr,
                                      (void *)mbr_update, SPILL_SLOT_1);
    }

    return DR_EMIT_DEFAULT;
}
Exemplo n.º 11
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;
}
Exemplo n.º 12
0
static dr_emit_flags_t
event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
                  bool for_trace, bool translating)
{
    instr_t *first = instrlist_first(bb);
    app_pc   pc    = dr_fragment_app_pc(tag);
    instr_t *mov1, *mov2;
    /* We try to avoid register stealing by using "dead" register if possible.
     * However, technically, a fault could come in and want the original value
     * of the "dead" register, but that's too corner-case for us.
     */
    reg_id_t reg   = bb_find_dead_reg(bb);
    bool     steal = (reg == DR_REG_NULL);

    if (reg == DR_REG_NULL)
        reg = DR_REG_XCX; /* randomly use one if no dead reg found */

    /* save register if necessary */
    if (steal)
        dr_save_reg(drcontext, bb, first, reg, SPILL_SLOT_1);

    /* load buffer pointer from TLS field */
    MINSERT(bb, first, INSTR_CREATE_mov_ld
            (drcontext,
             opnd_create_reg(reg),
             opnd_create_far_base_disp(tls_seg, DR_REG_NULL, DR_REG_NULL,
                                       0, tls_offs, OPSZ_PTR)));

    /* store bb's start pc into the buffer */
    instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)pc,
                                     OPND_CREATE_MEMPTR(reg, 0),
                                     bb, first, &mov1, &mov2);
    DR_ASSERT(mov1 != NULL);
    instr_set_ok_to_mangle(mov1, false);
    if (mov2 != NULL)
        instr_set_ok_to_mangle(mov2, false);

    /* update the TLS buffer pointer by incrementing just the bottom 16 bits of
     * the pointer
     */
    if (bb_aflags_are_dead(bb, first)) {
        /* if aflags are dead, we use add directly */
        MINSERT(bb, first, INSTR_CREATE_add
                (drcontext,
                 opnd_create_far_base_disp(tls_seg, DR_REG_NULL, DR_REG_NULL,
                                           0, tls_offs, OPSZ_2),
                 OPND_CREATE_INT8(sizeof(app_pc))));
    } else {
        reg_id_t reg_16;
#ifdef X64
        reg_16 = reg_32_to_16(reg_64_to_32(reg));
#else
        reg_16 = reg_32_to_16(reg);
#endif
        /* we use lea to avoid aflags save/restore */
        MINSERT(bb, first, INSTR_CREATE_lea
                (drcontext,
                 opnd_create_reg(reg_16),
                 opnd_create_base_disp(reg, DR_REG_NULL, 0,
                                       sizeof(app_pc), OPSZ_lea)));
        MINSERT(bb, first, INSTR_CREATE_mov_st
                (drcontext,
                 opnd_create_far_base_disp(tls_seg, DR_REG_NULL, DR_REG_NULL,
                                           0, tls_offs, OPSZ_PTR),
                 opnd_create_reg(reg)));
    }

    /* restore register if necessary */
    if (steal)
        dr_restore_reg(drcontext, bb, first, reg, SPILL_SLOT_1);

    return DR_EMIT_DEFAULT;
}
Exemplo n.º 13
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;
}