示例#1
0
drcovlib_status_t
drcovlib_init(drcovlib_options_t *ops)
{
    int count = dr_atomic_add32_return_sum(&drcovlib_init_count, 1);
    if (count > 1)
        return DRCOVLIB_SUCCESS;

    if (ops->struct_size != sizeof(options))
        return DRCOVLIB_ERROR_INVALID_PARAMETER;
    if ((ops->flags & (~(DRCOVLIB_DUMP_AS_TEXT|DRCOVLIB_THREAD_PRIVATE))) != 0)
        return DRCOVLIB_ERROR_INVALID_PARAMETER;
    if (TEST(DRCOVLIB_THREAD_PRIVATE, ops->flags)) {
        if (!dr_using_all_private_caches())
            return DRCOVLIB_ERROR_INVALID_SETUP;
        drcov_per_thread = true;
    }
    options = *ops;
    if (options.logdir != NULL)
        dr_snprintf(logdir, BUFFER_SIZE_ELEMENTS(logdir), "%s", ops->logdir);
    else /* default */
        dr_snprintf(logdir, BUFFER_SIZE_ELEMENTS(logdir), ".");
    NULL_TERMINATE_BUFFER(logdir);
    options.logdir = logdir;
    if (options.native_until_thread > 0)
        go_native = true;

    drmgr_init();
    drx_init();

    /* We follow a simple model of the caller requesting the coverage dump,
     * either via calling the exit routine, using its own soft_kills nudge, or
     * an explicit dump call for unusual cases.  This means that drx's
     * soft_kills remains inside the outer later, i.e., the drcov client.  This
     * is the easiest approach for coordinating soft_kills among many libraries.
     * Thus, we do *not* register for an exit event here.
     */

    drmgr_register_thread_init_event(event_thread_init);
    drmgr_register_thread_exit_event(event_thread_exit);
    drmgr_register_bb_instrumentation_event(event_basic_block_analysis, NULL, NULL);
    dr_register_filter_syscall_event(event_filter_syscall);
    drmgr_register_pre_syscall_event(event_pre_syscall);
#ifdef UNIX
    dr_register_fork_init_event(event_fork);
#endif

    tls_idx = drmgr_register_tls_field();
    if (tls_idx == -1)
        return DRCOVLIB_ERROR;

    return event_init();
}
示例#2
0
static void
insert_counter_update(void *drcontext, instrlist_t *bb, instr_t *where, int offset)
{
    /* Since the inc instruction clobbers 5 of the arithmetic eflags,
     * we have to save them around the inc. We could be more efficient
     * by not bothering to save the overflow flag and constructing our
     * own sequence of instructions to save the other 5 flags (using
     * lahf).
     */
    if (drreg_reserve_aflags(drcontext, bb, where) != DRREG_SUCCESS) {
        DR_ASSERT(false); /* cannot recover */
        return;
    }

    /* Increment the global counter using the lock prefix to make it atomic
     * across threads. It would be cheaper to aggregate the thread counters
     * in the exit events, but this sample is intended to illustrate inserted
     * instrumentation.
     */
    instrlist_meta_preinsert(
        bb, where,
        LOCK(INSTR_CREATE_inc(
            drcontext, OPND_CREATE_ABSMEM(((byte *)&global_count) + offset, OPSZ_4))));

    /* Increment the thread private counter. */
    if (dr_using_all_private_caches()) {
        per_thread_t *data = (per_thread_t *)drmgr_get_tls_field(drcontext, tls_idx);
        /* private caches - we can use an absolute address */
        instrlist_meta_preinsert(
            bb, where,
            INSTR_CREATE_inc(drcontext,
                             OPND_CREATE_ABSMEM(((byte *)&data) + offset, OPSZ_4)));
    } else {
        /* shared caches - we must indirect via thread local storage */
        reg_id_t scratch;
        if (drreg_reserve_register(drcontext, bb, where, NULL, &scratch) != DRREG_SUCCESS)
            DR_ASSERT(false);
        drmgr_insert_read_tls_field(drcontext, tls_idx, bb, where, scratch);
        instrlist_meta_preinsert(
            bb, where, INSTR_CREATE_inc(drcontext, OPND_CREATE_MEM32(scratch, offset)));
        if (drreg_unreserve_register(drcontext, bb, where, scratch) != DRREG_SUCCESS)
            DR_ASSERT(false);
    }

    if (drreg_unreserve_aflags(drcontext, bb, where) != DRREG_SUCCESS)
        DR_ASSERT(false); /* cannot recover */
}
示例#3
0
static void
insert_counter_update(void *drcontext, instrlist_t *bb, instr_t *where, int offset)
{
    /* Since the inc instruction clobbers 5 of the arithmetic eflags,
     * we have to save them around the inc. We could be more efficient
     * by not bothering to save the overflow flag and constructing our
     * own sequence of instructions to save the other 5 flags (using
     * lahf) or by doing a liveness analysis on the flags and saving
     * only if live.
     */
    dr_save_reg(drcontext, bb, where, DR_REG_XAX, SPILL_SLOT_1);
    dr_save_arith_flags_to_xax(drcontext, bb, where);

    /* Increment the global counter using the lock prefix to make it atomic
     * across threads. It would be cheaper to aggregate the thread counters
     * in the exit events, but this sample is intended to illustrate inserted
     * instrumentation.
     */
    instrlist_meta_preinsert(bb, where, LOCK(INSTR_CREATE_inc
        (drcontext, OPND_CREATE_ABSMEM(((byte *)&global_count) + offset, OPSZ_4))));

    /* Increment the thread private counter. */
    if (dr_using_all_private_caches()) {
        per_thread_t *data = (per_thread_t *) dr_get_tls_field(drcontext);
        /* private caches - we can use an absolute address */
        instrlist_meta_preinsert(bb, where, INSTR_CREATE_inc(drcontext, 
            OPND_CREATE_ABSMEM(((byte *)&data) + offset, OPSZ_4)));
    } else {
        /* shared caches - we must indirect via thread local storage */
        /* We spill xbx to use a scratch register (we could do a liveness
         * analysis to try and find a dead register to use). Note that xax
         * is currently holding the saved eflags. */
        dr_save_reg(drcontext, bb, where, DR_REG_XBX, SPILL_SLOT_2);
        dr_insert_read_tls_field(drcontext, bb, where, DR_REG_XBX);
        instrlist_meta_preinsert(bb, where,
            INSTR_CREATE_inc(drcontext, OPND_CREATE_MEM32(DR_REG_XBX, offset)));
        dr_restore_reg(drcontext, bb, where, DR_REG_XBX, SPILL_SLOT_2);
    }

    /* Restore flags and xax. */
    dr_restore_arith_flags_from_xax(drcontext, bb, where);
    dr_restore_reg(drcontext, bb, where, DR_REG_XAX, SPILL_SLOT_1);
}