Ejemplo n.º 1
0
static void
test_x86_mode(void *dc)
{
    byte *pc, *end;
    instr_t *instr;

    /* create instr that looks different in x86 vs x64 */
    instr = INSTR_CREATE_add(dc, opnd_create_reg(REG_RAX), OPND_CREATE_INT32(42));
    end = instr_encode(dc, instr, buf);
    ASSERT(end - buf < BUFFER_SIZE_ELEMENTS(buf));

    /* read back in */
    set_x86_mode(dc, false/*64-bit*/);
    instr_reset(dc, instr);
    pc = decode(dc, buf, instr);
    ASSERT(pc != NULL);
    ASSERT(instr_get_opcode(instr) == OP_add);

    /* now interpret as 32-bit where rex will be an inc */
    set_x86_mode(dc, true/*32-bit*/);
    instr_reset(dc, instr);
    pc = decode(dc, buf, instr);
    ASSERT(pc != NULL);
    ASSERT(instr_get_opcode(instr) == OP_dec);

    instr_free(dc, instr);
    set_x86_mode(dc, false/*64-bit*/);
}
Ejemplo n.º 2
0
/* Insert arithmetic flags restore code with more control.
 * For x86:
 * - skip %eax restore if !restore_reg
 * - restore %eax from reg if reg is not DR_REG_NULL
 * - restore %eax from slot otherwise
 * For ARM:
 * - restores flags from reg
 * - restores reg to slot, unless !restore_reg.
 * Routine merge_prev_drx_aflags_switch looks for labels inserted by
 * drx_restore_arith_flags, so changes to this routine may affect
 * merge_prev_drx_aflags_switch.
 */
static void
drx_restore_arith_flags(void *drcontext, instrlist_t *ilist, instr_t *where,
                        bool restore_reg, bool restore_oflag,
                        dr_spill_slot_t slot, reg_id_t reg)
{
    instr_t *instr;
    ilist_insert_note_label(drcontext, ilist, where,
                            NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_BEGIN));
#ifdef X86
    if (restore_oflag) {
        /* add 0x7f, %al */
        instr = INSTR_CREATE_add(drcontext, opnd_create_reg(DR_REG_AL),
                                 OPND_CREATE_INT8(0x7f));
        MINSERT(ilist, where, instr);
    }
    /* sahf */
    instr = INSTR_CREATE_sahf(drcontext);
    instr_set_note(instr, NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_SAHF));
    MINSERT(ilist, where, instr);
    /* restore eax if necessary */
    if (restore_reg) {
        if (reg != DR_REG_NULL) {
            ASSERT(reg >= DR_REG_START_GPR && reg <= DR_REG_STOP_GPR &&
                   reg != DR_REG_XAX, "wrong dead reg");
            MINSERT(ilist, where,
                    INSTR_CREATE_mov_st(drcontext,
                                        opnd_create_reg(DR_REG_XAX),
                                        opnd_create_reg(reg)));
        } else {
            ASSERT(slot >= SPILL_SLOT_1 && slot <= SPILL_SLOT_MAX,
                   "wrong spill slot");
            dr_restore_reg(drcontext, ilist, where, DR_REG_XAX, slot);
        }
    }
#elif defined(ARM)
    ASSERT(reg >= DR_REG_START_GPR && reg <= DR_REG_STOP_GPR, "reg must be a GPR");
    instr = INSTR_CREATE_mrs(drcontext, opnd_create_reg(reg),
                             opnd_create_reg(DR_REG_CPSR));
    instr_set_note(instr, NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_SAHF));
    MINSERT(ilist, where, instr);
    if (restore_reg) {
        ASSERT(slot >= SPILL_SLOT_1 && slot <= SPILL_SLOT_MAX,
               "wrong spill slot");
        dr_restore_reg(drcontext, ilist, where, reg, slot);
    }
#endif
    ilist_insert_note_label(drcontext, ilist, where,
                            NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_END));
}
Ejemplo n.º 3
0
static dr_emit_flags_t
event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
                  bool for_trace, bool translating)
{
    instr_t *instr, *first = instrlist_first(bb), *point = NULL;
    uint num_instrs;
	uint flags;
	uint need_restore;

	/* count instruction */
    for (instr  = first, num_instrs = 0;
         instr != NULL;
         instr = instr_get_next(instr)) {

        num_instrs++;

    }
	
	need_restore = 0;
	flags = instr_get_arith_flags(instr);
	/* eflags are not dead save eflags to register */
	if (!(TESTALL(EFLAGS_WRITE_6, flags) && !TESTANY(EFLAGS_READ_6, flags))) {
		need_restore = 1;
		dr_save_reg(drcontext, bb, first, DR_REG_XAX, SPILL_SLOT_1);
		dr_save_arith_flags_to_xax(drcontext, bb, first);
	}

	/* add the instruction count */
    instrlist_meta_preinsert
        (bb, first,
         INSTR_CREATE_add(drcontext, OPND_CREATE_ABSMEM
                               ((byte *)&global_count, OPSZ_4), OPND_CREATE_INT32(num_instrs)));

	/* Need to carry since it is a 8 byte variable. */
    instrlist_meta_preinsert
        (bb, first,
         INSTR_CREATE_adc(drcontext, OPND_CREATE_ABSMEM
                               ((byte *)&global_count + 4, OPSZ_4), OPND_CREATE_INT32(0)));

	/* resotre eflags */
	if (need_restore) {
		dr_restore_arith_flags_from_xax(drcontext, bb, first);
		dr_restore_reg(drcontext, bb, first, DR_REG_XAX, SPILL_SLOT_1);
	}

    return DR_EMIT_DEFAULT;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
/* replaces inc with add 1, dec with sub 1 
 * returns true if successful, false if not
 */
static bool
replace_inc_with_add(void *drcontext, instr_t *instr, instrlist_t *trace)
{
    instr_t *in;
    uint eflags;
    int opcode = instr_get_opcode(instr);
    bool ok_to_replace = false;

    DR_ASSERT(opcode == OP_inc || opcode == OP_dec);
#ifdef VERBOSE
    dr_print_instr(drcontext, STDOUT, instr, "in replace_inc_with_add:\n\t");
#endif

    /* add/sub writes CF, inc/dec does not, make sure that's ok */
    for (in = instr; in != NULL; in = instr_get_next(in)) {
	eflags = instr_get_eflags(in);
	if ((eflags & EFLAGS_READ_CF) != 0) {
#ifdef VERBOSE
            dr_print_instr(drcontext, STDOUT, in,
                           "\treads CF => cannot replace inc with add: ");
#endif
	    return false;
	}
	if (instr_is_exit_cti(in)) {
	    /* to be more sophisticated, examine instructions at
	     * target of exit cti (if it is a direct branch).
	     * for this example, we give up if we hit a branch.
	     */
	    return false;
	}
	/* if writes but doesn't read, ok */
	if ((eflags & EFLAGS_WRITE_CF) != 0) {
	    ok_to_replace = true;
	    break;
	}
    }
    if (!ok_to_replace) {
#ifdef VERBOSE
        dr_printf("\tno write to CF => cannot replace inc with add\n");
#endif
	return false;
    }
    if (opcode == OP_inc) {
#ifdef VERBOSE
        dr_printf("\treplacing inc with add\n");
#endif
	in = INSTR_CREATE_add(drcontext, instr_get_dst(instr, 0),
			      OPND_CREATE_INT8(1));
    } else {
#ifdef VERBOSE
        dr_printf("\treplacing dec with sub\n");
#endif
	in = INSTR_CREATE_sub(drcontext, instr_get_dst(instr, 0),
			      OPND_CREATE_INT8(1));
    }
    if (instr_get_prefix_flag(instr, PREFIX_LOCK))
        instr_set_prefix_flag(in, PREFIX_LOCK);
    instr_set_translation(in, instr_get_app_pc(instr));
    instrlist_replace(trace, instr, in);
    instr_destroy(drcontext, instr);
    return true;
}