void cfi_call_instrumentation_snapahot(void *dcontext, instrlist_t *ilist, instr_t *where, void *callee) { uint dstack_offs = 0, pad = 0; unsigned int eflags_offs; CFI_ASSERT(dcontext != NULL, "cfi_call_instrumentation_snapahot: dcontext cannot be NULL"); instr_t *next_snapshot = INSTR_CREATE_label(dcontext); PRE(ilist, where, INSTR_CREATE_pushf(dcontext)); dstack_offs += XSP_SZ; eflags_offs = dstack_offs; PRE(ilist, where, INSTR_CREATE_push(dcontext, opnd_create_reg(DR_REG_RDI))); dstack_offs += XSP_SZ; PRE(ilist, where, INSTR_CREATE_mov_imm(dcontext, opnd_create_reg(DR_REG_RDI), OPND_CREATE_INT64(&flag_memory_snapshot))); PRE(ilist, where, INSTR_CREATE_mov_ld(dcontext, opnd_create_reg(DR_REG_RDI), opnd_create_base_disp(DR_REG_RDI, DR_REG_NULL, 0, 0, OPSZ_PTR))); PRE(ilist, where, INSTR_CREATE_cmp(dcontext, opnd_create_reg(DR_REG_RDI), OPND_CREATE_INT8(0x0))); PRE(ilist, where, INSTR_CREATE_jcc(dcontext, OP_je, opnd_create_instr(next_snapshot))); PRE(ilist, where, INSTR_CREATE_push(dcontext, opnd_create_base_disp(DR_REG_RSP, DR_REG_NULL, 0, dstack_offs - eflags_offs, OPSZ_STACK))); PRE(ilist, where, INSTR_CREATE_and(dcontext, opnd_create_base_disp(DR_REG_RSP, DR_REG_NULL, 0, 0, OPSZ_STACK), OPND_CREATE_INT32(~(EFLAGS_NON_SYSTEM | EFLAGS_IF)))); PRE(ilist, where, INSTR_CREATE_popf(dcontext)); instrlist_set_our_mangling(ilist, true); cfi_insert_meta_native_call_vargs(dcontext, ilist, where, true/*clean*/, callee); instrlist_set_our_mangling(ilist, false); cfi_insert_native_call(dcontext, ilist, where, callee /*, opnd_create_reg(DR_REG_RAX)*/); PRE(ilist, where, next_snapshot); PRE(ilist, where, INSTR_CREATE_pop(dcontext, opnd_create_reg(DR_REG_RDI))); PRE(ilist, where, INSTR_CREATE_popf(dcontext)); /* dstack_offs = cfi_prepare_for_native_call(dcontext, ilist, where); instrlist_set_our_mangling(ilist, true); cfi_insert_meta_native_call_vargs(dcontext, ilist, where, true*//*clean*//*, callee); instrlist_set_our_mangling(ilist, false); cfi_cleanup_after_native_call(dcontext, ilist, where);*/ }
/* 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)); }
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; }
/* 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; }