Пример #1
0
static dr_emit_flags_t
event_bb_insert(void *drcontext, void *tag, instrlist_t *bb, instr_t *inst,
                bool for_trace, bool translating, void *user_data)
{
    static int freq;
    reg_id_t reg1 = IF_X86_ELSE(DR_REG_XAX, DR_REG_R0);
    reg_id_t reg2 = IF_X86_ELSE(DR_REG_XCX, DR_REG_R1);

    CHECK(drmgr_is_first_instr(drcontext, instrlist_first_app(bb)), "first incorrect");
    CHECK(!drmgr_is_first_instr(drcontext, instrlist_last(bb)) ||
          instrlist_first_app(bb) == instrlist_last(bb), "first incorrect");
    CHECK(drmgr_is_last_instr(drcontext, instrlist_last(bb)), "last incorrect");
    CHECK(!drmgr_is_last_instr(drcontext, instrlist_first_app(bb)) ||
          instrlist_first_app(bb) == instrlist_last(bb), "last incorrect");

    /* hack to instrument every nth bb.  assumes DR serializes bb events. */
    freq++;
    if (freq % 100 == 0 && inst == (instr_t*)user_data/*first instr*/) {
        /* test read from cache */
        dr_save_reg(drcontext, bb, inst, reg1, SPILL_SLOT_1);
        drmgr_insert_read_tls_field(drcontext, tls_idx, bb, inst, reg1);
        dr_insert_clean_call(drcontext, bb, inst, (void *)check_tls_from_cache,
                             false, 1, opnd_create_reg(reg1));
        drmgr_insert_read_cls_field(drcontext, cls_idx, bb, inst, reg1);
        dr_insert_clean_call(drcontext, bb, inst, (void *)check_cls_from_cache,
                             false, 1, opnd_create_reg(reg1));
        dr_restore_reg(drcontext, bb, inst, reg1, SPILL_SLOT_1);
    }
    if (freq % 300 == 0 && inst == (instr_t*)user_data/*first instr*/) {
        instr_t *first, *second;
        /* test write from cache */
        dr_save_reg(drcontext, bb, inst, reg1, SPILL_SLOT_1);
        dr_save_reg(drcontext, bb, inst, reg2, SPILL_SLOT_2);
        instrlist_insert_mov_immed_ptrsz(drcontext,
                                         (ptr_int_t)MAGIC_NUMBER_FROM_CACHE,
                                         opnd_create_reg(reg1),
                                         bb, inst, &first, &second);
        instr_set_meta(first);
        if (second != NULL)
            instr_set_meta(second);
        drmgr_insert_write_tls_field(drcontext, tls_idx, bb, inst, reg1, reg2);
        dr_insert_clean_call(drcontext, bb, inst, (void *)check_tls_write_from_cache,
                             false, 0);
        drmgr_insert_write_cls_field(drcontext, cls_idx, bb, inst, reg1, reg2);
        dr_insert_clean_call(drcontext, bb, inst, (void *)check_cls_write_from_cache,
                             false, 0);
        dr_restore_reg(drcontext, bb, inst, reg2, SPILL_SLOT_2);
        dr_restore_reg(drcontext, bb, inst, reg1, SPILL_SLOT_1);
    }
    return DR_EMIT_DEFAULT;
}
Пример #2
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)
{
    per_bb_data_t *per_bb = (per_bb_data_t *)user_data;
    /* We increment the per-bb counters just once, at the top of the bb. */
    if (drmgr_is_first_instr(drcontext, instr)) {
        /* drx will analyze whether to save the flags for us. */
        uint flags = DRX_COUNTER_LOCK;
        if (per_bb->num_instrs > 0) {
            drx_insert_counter_update(drcontext, bb, instr, SPILL_SLOT_MAX+1,
                                      &stats->num_instrs, per_bb->num_instrs, flags);
        }
        if (per_bb->num_flops > 0) {
            drx_insert_counter_update(drcontext, bb, instr, SPILL_SLOT_MAX+1,
                                      &stats->num_flops, per_bb->num_flops, flags);
        }
        if (per_bb->num_syscalls > 0) {
            drx_insert_counter_update(drcontext, bb, instr, SPILL_SLOT_MAX+1,
                                      &stats->num_syscalls, per_bb->num_syscalls, flags);
        }
    }
    if (drmgr_is_last_instr(drcontext, instr))
        dr_thread_free(drcontext, per_bb, sizeof(*per_bb));
    return DR_EMIT_DEFAULT;
}
Пример #3
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;
}
Пример #4
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;
}
Пример #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)
{
    if (!drmgr_is_first_instr(drcontext, inst))
        return DR_EMIT_DEFAULT;
    /* Exercise drreg's adjacent increment aflags spill removal code */
    drx_insert_counter_update(drcontext, bb, inst, SPILL_SLOT_MAX + 1,
                              IF_NOT_X86_(SPILL_SLOT_MAX + 1) & counterA, 1, 0);
    drx_insert_counter_update(drcontext, bb, inst, SPILL_SLOT_MAX + 1,
                              IF_NOT_X86_(SPILL_SLOT_MAX + 1) & counterB, 3, 0);
    return DR_EMIT_DEFAULT;
}
Пример #6
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)
{
#ifdef SHOW_RESULTS
    bool aflags_dead;
#endif

    if (!drmgr_is_first_instr(drcontext, inst))
        return DR_EMIT_DEFAULT;

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

#ifdef SHOW_RESULTS
    if (drreg_are_aflags_dead(drcontext, inst, &aflags_dead) == DRREG_SUCCESS &&
        !aflags_dead)
        bbs_eflags_saved++;
    else
        bbs_no_eflags_saved++;
#endif

    /* We demonstrate how to use drreg for aflags save/restore here.
     * We could use drx_insert_counter_update instead of drreg.
     * Xref sample opcodes.c as an example of using drx_insert_counter_update.
     */
    if (drreg_reserve_aflags(drcontext, bb, inst) != DRREG_SUCCESS)
        DR_ASSERT(false && "fail to reserve aflags!");
    /* racy update on the counter for better performance */
    instrlist_meta_preinsert
        (bb, inst,
         INSTR_CREATE_inc(drcontext, OPND_CREATE_ABSMEM
                          ((byte *)&global_count, OPSZ_4)));
    if (drreg_unreserve_aflags(drcontext, bb, inst) != DRREG_SUCCESS)
        DR_ASSERT(false && "fail to unreserve aflags!");

#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;
}
Пример #7
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;
}
Пример #8
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)
{
    uint num_instrs;
    /* By default drmgr enables auto-predication, which predicates all instructions with
     * the predicate of the current instruction on ARM.
     * We disable it here because we want to unconditionally execute the following
     * instrumentation.
     */
    drmgr_disable_auto_predication(drcontext, bb);
    if (!drmgr_is_first_instr(drcontext, instr))
        return DR_EMIT_DEFAULT;
    /* Only insert calls for in-app BBs */
    if (user_data == NULL)
        return DR_EMIT_DEFAULT;
    /* Insert clean call */
    num_instrs = (uint)(ptr_uint_t)user_data;
    dr_insert_clean_call(drcontext, bb, instrlist_first_app(bb), (void *)inscount,
                         false /* save fpstate */, 1, OPND_CREATE_INT32(num_instrs));
    return DR_EMIT_DEFAULT;
}
Пример #9
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;
}