void offline_instru_t::insert_save_pc(void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg_ptr, reg_id_t scratch, int adjust, uint64_t value) { int disp = adjust; #ifdef X64 instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t) value, opnd_create_reg(scratch), ilist, where, NULL, NULL); MINSERT(ilist, where, XINST_CREATE_store(drcontext, OPND_CREATE_MEMPTR(reg_ptr, disp), opnd_create_reg(scratch))); #else instrlist_insert_mov_immed_ptrsz(drcontext, (int)value, opnd_create_reg(scratch), ilist, where, NULL, NULL); MINSERT(ilist, where, XINST_CREATE_store(drcontext, OPND_CREATE_MEMPTR(reg_ptr, disp), opnd_create_reg(scratch))); instrlist_insert_mov_immed_ptrsz(drcontext, (int)(value >> 32), opnd_create_reg(scratch), ilist, where, NULL, NULL); MINSERT(ilist, where, XINST_CREATE_store(drcontext, OPND_CREATE_MEMPTR(reg_ptr, disp + 4), opnd_create_reg(scratch))); #endif }
static void insert_save_size(void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t base, reg_id_t scratch, ushort size) { scratch = reg_resize_to_opsz(scratch, OPSZ_2); MINSERT(ilist, where, XINST_CREATE_load_int(drcontext, opnd_create_reg(scratch), OPND_CREATE_INT16(size))); MINSERT(ilist, where, XINST_CREATE_store_2bytes(drcontext, OPND_CREATE_MEM16(base, offsetof(mem_ref_t, size)), opnd_create_reg(scratch))); }
/* 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)); }
/* insert a label instruction with note */ static void ilist_insert_note_label(void *drcontext, instrlist_t *ilist, instr_t *where, void *note) { instr_t *instr = INSTR_CREATE_label(drcontext); instr_set_note(instr, note); MINSERT(ilist, where, instr); }
static void insert_update_buf_ptr(void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg_ptr, int adjust) { MINSERT( ilist, where, XINST_CREATE_add(drcontext, opnd_create_reg(reg_ptr), OPND_CREATE_INT16(adjust))); dr_insert_write_raw_tls(drcontext, ilist, where, tls_seg, tls_offs + MEMTRACE_TLS_OFFS_BUF_PTR, reg_ptr); }
static dr_emit_flags_t bb_event(void* drcontext, app_pc tag, instrlist_t* bb, bool for_trace, bool translating) { if (tag >= start && tag < end) { instr_t* instr = instrlist_first(bb); dr_prepare_for_call(drcontext, bb, instr); MINSERT(bb, instr, INSTR_CREATE_push_imm (drcontext, OPND_CREATE_INT32((ptr_uint_t)tag))); MINSERT(bb, instr, INSTR_CREATE_push_imm (drcontext, OPND_CREATE_INT32((ptr_uint_t)drcontext))); MINSERT(bb, instr, INSTR_CREATE_call (drcontext, opnd_create_pc((void*)delete_fragment))); dr_cleanup_after_call(drcontext, bb, instr, 8); } return DR_EMIT_DEFAULT; }
/* Insert arithmetic flags saving code with more control. * For x86: * - skip %eax save if !save_reg * - save %eax to reg if reg is not DR_REG_NULL, * - save %eax to slot otherwise * For ARM: * - saves flags to reg * - saves reg first to slot, unless !save_reg. */ static void drx_save_arith_flags(void *drcontext, instrlist_t *ilist, instr_t *where, bool save_reg, bool save_oflag, dr_spill_slot_t slot, reg_id_t reg) { #ifdef X86 instr_t *instr; /* save %eax if necessary */ if (save_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(reg), opnd_create_reg(DR_REG_XAX))); } else { ASSERT(slot >= SPILL_SLOT_1 && slot <= SPILL_SLOT_MAX, "wrong spill slot"); dr_save_reg(drcontext, ilist, where, DR_REG_XAX, slot); } } /* lahf */ instr = INSTR_CREATE_lahf(drcontext); MINSERT(ilist, where, instr); if (save_oflag) { /* seto %al */ instr = INSTR_CREATE_setcc(drcontext, OP_seto, opnd_create_reg(DR_REG_AL)); MINSERT(ilist, where, instr); } #elif defined(ARM) ASSERT(reg >= DR_REG_START_GPR && reg <= DR_REG_STOP_GPR, "reg must be a GPR"); if (save_reg) { ASSERT(slot >= SPILL_SLOT_1 && slot <= SPILL_SLOT_MAX, "wrong spill slot"); dr_save_reg(drcontext, ilist, where, reg, slot); } MINSERT(ilist, where, INSTR_CREATE_msr (drcontext, opnd_create_reg(DR_REG_CPSR), OPND_CREATE_INT_MSR_NZCVQG(), opnd_create_reg(reg))); #endif }
static void insert_save_pc(void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t base, reg_id_t scratch, app_pc pc) { instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)pc, opnd_create_reg(scratch), ilist, where, NULL, NULL); MINSERT(ilist, where, XINST_CREATE_store(drcontext, OPND_CREATE_MEMPTR(base, offsetof(mem_ref_t, addr)), opnd_create_reg(scratch))); }
static void insert_save_addr(void *drcontext, instrlist_t *ilist, instr_t *where, opnd_t ref, reg_id_t reg_ptr, reg_id_t reg_addr) { bool ok; /* we use reg_ptr as scratch to get addr */ ok = drutil_insert_get_mem_addr(drcontext, ilist, where, ref, reg_addr, reg_ptr); DR_ASSERT(ok); insert_load_buf_ptr(drcontext, ilist, where, reg_ptr); MINSERT(ilist, where, XINST_CREATE_store(drcontext, OPND_CREATE_MEMPTR(reg_ptr, offsetof(mem_ref_t, addr)), opnd_create_reg(reg_addr))); }
int offline_instru_t::instrument_memref(void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg_ptr, reg_id_t reg_tmp, int adjust, opnd_t ref, bool write, dr_pred_type_t pred) { // Post-processor distinguishes read, write, prefetch, flush, and finds size. instr_t *label = INSTR_CREATE_label(drcontext); MINSERT(ilist, where, label); insert_save_addr(drcontext, ilist, where, reg_ptr, reg_tmp, adjust, ref); #ifdef ARM // X86 does not support general predicated execution if (pred != DR_PRED_NONE) { instr_t *instr; for (instr = instr_get_prev(where); instr != label; instr = instr_get_prev(instr)) { DR_ASSERT(!instr_is_predicated(instr)); instr_set_predicate(instr, pred); } } #endif return (adjust + sizeof(offline_entry_t)); }
void offline_instru_t::insert_save_addr(void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg_ptr, reg_id_t reg_addr, int adjust, opnd_t ref) { bool ok; int disp = adjust; if (opnd_uses_reg(ref, reg_ptr)) drreg_get_app_value(drcontext, ilist, where, reg_ptr, reg_ptr); if (opnd_uses_reg(ref, reg_addr)) drreg_get_app_value(drcontext, ilist, where, reg_addr, reg_addr); // We use reg_ptr as scratch to get the address. ok = drutil_insert_get_mem_addr(drcontext, ilist, where, ref, reg_addr, reg_ptr); DR_ASSERT(ok); // drutil_insert_get_mem_addr may clobber reg_ptr, so we need to re-load reg_ptr. // XXX i#2001: determine whether we have to and avoid it when we don't. insert_load_buf_ptr(drcontext, ilist, where, reg_ptr); MINSERT(ilist, where, XINST_CREATE_store(drcontext, OPND_CREATE_MEMPTR(reg_ptr, disp), opnd_create_reg(reg_addr))); // We allow either 0 or all 1's as the type so no need to write anything else. }
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; }
static reg_id_t instrument_mem(void *drcontext, instrlist_t *ilist, instr_t *where, opnd_t ref) { reg_id_t reg_ptr, reg_tmp, reg_addr; ushort type, size; bool ok; if (drreg_reserve_register(drcontext, ilist, where, NULL, ®_tmp) != DRREG_SUCCESS) { DR_ASSERT(false); return DR_REG_NULL; } if (drreg_reserve_register(drcontext, ilist, where, NULL, ®_ptr) != DRREG_SUCCESS) { DR_ASSERT(false); return DR_REG_NULL; } /* i#2449: In the situation that instrument_post_write, instrument_mem and ref all * have the same register reserved, drutil_insert_get_mem_addr will compute the * address of an operand using an incorrect register value, as drreg will elide the * save/restore. */ if (opnd_uses_reg(ref, reg_tmp) && drreg_get_app_value(drcontext, ilist, where, reg_tmp, reg_tmp) != DRREG_SUCCESS) { DR_ASSERT(false); return DR_REG_NULL; } if (opnd_uses_reg(ref, reg_ptr) && drreg_get_app_value(drcontext, ilist, where, reg_ptr, reg_ptr) != DRREG_SUCCESS) { DR_ASSERT(false); return DR_REG_NULL; } /* We use reg_ptr as scratch to get addr. Note we do this first as reg_ptr or reg_tmp * may be used in ref. */ ok = drutil_insert_get_mem_addr(drcontext, ilist, where, ref, reg_tmp, reg_ptr); DR_ASSERT(ok); drx_buf_insert_load_buf_ptr(drcontext, trace_buffer, ilist, where, reg_ptr); /* inserts memref addr */ drx_buf_insert_buf_store(drcontext, trace_buffer, ilist, where, reg_ptr, DR_REG_NULL, opnd_create_reg(reg_tmp), OPSZ_PTR, offsetof(mem_ref_t, addr)); if (IF_AARCHXX_ELSE(true, false)) { /* At this point we save the write address for later, because reg_tmp's value * will get clobbered on ARM. */ if (drreg_reserve_register(drcontext, ilist, where, NULL, ®_addr) != DRREG_SUCCESS) { DR_ASSERT(false); return DR_REG_NULL; } MINSERT(ilist, where, XINST_CREATE_move(drcontext, opnd_create_reg(reg_addr), opnd_create_reg(reg_tmp))); } /* inserts type */ type = (ushort)instr_get_opcode(where); drx_buf_insert_buf_store(drcontext, trace_buffer, ilist, where, reg_ptr, reg_tmp, OPND_CREATE_INT16(type), OPSZ_2, offsetof(mem_ref_t, type)); /* inserts size */ size = (ushort)drutil_opnd_mem_size_in_bytes(ref, where); drx_buf_insert_buf_store(drcontext, trace_buffer, ilist, where, reg_ptr, reg_tmp, OPND_CREATE_INT16(size), OPSZ_2, offsetof(mem_ref_t, size)); drx_buf_insert_update_buf_ptr(drcontext, trace_buffer, ilist, where, reg_ptr, DR_REG_NULL, sizeof(mem_ref_t)); if (instr_is_call(where)) { app_pc pc; /* Note that on ARM the call instruction writes only to the link register, so * we would never even get into instrument_mem() on ARM if this was a call. */ IF_AARCHXX(DR_ASSERT(false)); /* We simulate the call instruction's written memory by writing the next app_pc * to the written buffer, since we can't do this after the call has happened. */ drx_buf_insert_load_buf_ptr(drcontext, write_buffer, ilist, where, reg_ptr); pc = decode_next_pc(drcontext, instr_get_app_pc(where)); /* note that for a circular buffer, we don't need to specify a scratch register */ drx_buf_insert_buf_store(drcontext, trace_buffer, ilist, where, reg_ptr, DR_REG_NULL, OPND_CREATE_INTPTR((ptr_int_t)pc), OPSZ_PTR, 0); drx_buf_insert_update_buf_ptr(drcontext, write_buffer, ilist, where, reg_ptr, reg_tmp, sizeof(app_pc)); /* we don't need to persist reg_tmp to the next instruction */ if (drreg_unreserve_register(drcontext, ilist, where, reg_tmp) != DRREG_SUCCESS) DR_ASSERT(false); reg_tmp = DR_REG_NULL; } else if (IF_AARCHXX_ELSE(true, false)) { /* Now reg_tmp has the address of the write again. */ MINSERT(ilist, where, XINST_CREATE_move(drcontext, opnd_create_reg(reg_tmp), opnd_create_reg(reg_addr))); if (drreg_unreserve_register(drcontext, ilist, where, reg_addr) != DRREG_SUCCESS) DR_ASSERT(false); } if (drreg_unreserve_register(drcontext, ilist, where, reg_ptr) != DRREG_SUCCESS) DR_ASSERT(false); return reg_tmp; }
// 描画開始命令 void HERE::drawStartCall( int _layer, DrawInterface* _inter ) { MINSERT(HERE::m_inter,_layer,_inter); }
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) { reg_id_t reg_ptr = IF_X86_ELSE(DR_REG_XDX, TEST_REG); reg_id_t reg_tmp = IF_X86_ELSE(DR_REG_XCX, DR_REG_R3); /* We need a third register on ARM, because updating the buf pointer * requires a second scratch reg. */ reg_id_t scratch = IF_X86_ELSE(reg_tmp, DR_REG_R5); ptr_int_t subtest = (ptr_int_t) user_data; if (!instr_is_label(inst)) return DR_EMIT_DEFAULT; #ifdef X86 scratch = reg_resize_to_opsz(scratch, OPSZ_4); #endif if (subtest == DRX_BUF_TEST_1_C) { /* testing fast circular buffer */ /* test to make sure that on first invocation, the buffer is empty */ dr_insert_clean_call(drcontext, bb, inst, verify_buffers_empty, false, 1, OPND_CREATE_INTPTR(circular_fast)); /* load the buf pointer, and then write a garbage element to the buffer */ drx_buf_insert_load_buf_ptr(drcontext, circular_fast, bb, inst, reg_ptr); drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, DR_REG_NULL, opnd_create_reg(scratch), OPSZ_4, 0); drx_buf_insert_update_buf_ptr(drcontext, circular_fast, bb, inst, reg_ptr, reg_tmp, sizeof(int)); /* verify the buffer was written to */ dr_insert_clean_call(drcontext, bb, inst, verify_buffers_dirty, false, 2, OPND_CREATE_INTPTR(circular_fast), opnd_create_reg(scratch)); /* fast circular buffer: trigger an overflow */ drx_buf_insert_load_buf_ptr(drcontext, circular_fast, bb, inst, reg_ptr); drx_buf_insert_update_buf_ptr(drcontext, circular_fast, bb, inst, reg_ptr, reg_tmp, CIRCULAR_FAST_SZ - sizeof(int)); /* the buffer is now clean */ dr_insert_clean_call(drcontext, bb, inst, verify_buffers_empty, false, 1, OPND_CREATE_INTPTR(circular_fast)); } else if (subtest == DRX_BUF_TEST_2_C) { /* testing slow circular buffer */ /* test to make sure that on first invocation, the buffer is empty */ dr_insert_clean_call(drcontext, bb, inst, verify_buffers_empty, false, 1, OPND_CREATE_INTPTR(circular_slow)); /* load the buf pointer, and then write an element to the buffer */ drx_buf_insert_load_buf_ptr(drcontext, circular_slow, bb, inst, reg_ptr); drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, DR_REG_NULL, opnd_create_reg(scratch), OPSZ_4, 0); drx_buf_insert_update_buf_ptr(drcontext, circular_slow, bb, inst, reg_ptr, DR_REG_NULL, sizeof(int)); /* verify the buffer was written to */ dr_insert_clean_call(drcontext, bb, inst, verify_buffers_dirty, false, 2, OPND_CREATE_INTPTR(circular_slow), opnd_create_reg(scratch)); /* slow circular buffer: trigger a fault */ drx_buf_insert_load_buf_ptr(drcontext, circular_slow, bb, inst, reg_ptr); drx_buf_insert_update_buf_ptr(drcontext, circular_slow, bb, inst, reg_ptr, DR_REG_NULL, CIRCULAR_SLOW_SZ - sizeof(int)); /* the "trigger" is a write, so we write whatever garbage is in reg_tmp */ drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, DR_REG_NULL, opnd_create_reg(scratch), OPSZ_4, 0); /* the buffer is now clean */ dr_insert_clean_call(drcontext, bb, inst, verify_buffers_empty, false, 1, OPND_CREATE_INTPTR(circular_slow)); } else if (subtest == DRX_BUF_TEST_3_C) { /* testing trace buffer */ /* test to make sure that on first invocation, the buffer is empty */ dr_insert_clean_call(drcontext, bb, inst, verify_buffers_empty, false, 1, OPND_CREATE_INTPTR(trace)); /* load the buf pointer, and then write an element to the buffer */ drx_buf_insert_load_buf_ptr(drcontext, trace, bb, inst, reg_ptr); drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, DR_REG_NULL, opnd_create_reg(scratch), OPSZ_4, 0); drx_buf_insert_update_buf_ptr(drcontext, trace, bb, inst, reg_ptr, DR_REG_NULL, sizeof(int)); /* verify the buffer was written to */ dr_insert_clean_call(drcontext, bb, inst, verify_buffers_dirty, false, 2, OPND_CREATE_INTPTR(trace), opnd_create_reg(scratch)); /* trace buffer: trigger a fault and verify */ drx_buf_insert_load_buf_ptr(drcontext, trace, bb, inst, reg_ptr); drx_buf_insert_update_buf_ptr(drcontext, trace, bb, inst, reg_ptr, DR_REG_NULL, TRACE_SZ - sizeof(int)); /* the "trigger" is a write, so we write whatever garbage is in reg_tmp */ drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, DR_REG_NULL, opnd_create_reg(scratch), OPSZ_4, 0); /* the buffer is now clean */ dr_insert_clean_call(drcontext, bb, inst, verify_buffers_empty, false, 1, OPND_CREATE_INTPTR(trace)); } else if (subtest == DRX_BUF_TEST_4_C) { /* test immediate store: 8 bytes (if possible), 4 bytes, 2 bytes and 1 byte */ /* "ABCDEFGH\x00" (x2 for x64) */ drx_buf_insert_load_buf_ptr(drcontext, circular_fast, bb, inst, reg_ptr); drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, scratch, opnd_create_immed_int(0x41, OPSZ_1), OPSZ_1, 0); drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, scratch, opnd_create_immed_int(0x42, OPSZ_1), OPSZ_1, 1); drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, scratch, opnd_create_immed_int(0x4443, OPSZ_2), OPSZ_2, 2); drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, scratch, opnd_create_immed_int(0x48474645, OPSZ_4), OPSZ_4, 4); #ifdef X64 drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, scratch, opnd_create_immed_int(0x4847464544434241, OPSZ_8), OPSZ_8, 8); drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, scratch, opnd_create_immed_int(0x00, OPSZ_1), OPSZ_1, 17); #else drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, scratch, opnd_create_immed_int(0x00, OPSZ_1), OPSZ_1, 9); #endif dr_insert_clean_call(drcontext, bb, inst, verify_store, false, 1, OPND_CREATE_INTPTR(circular_fast)); } else if (subtest == DRX_BUF_TEST_5_C) { /* test register store: 8 bytes (if possible), 4 bytes, 2 bytes and 1 byte */ /* "ABCDEFGH\x00" (x2 for x64) */ drx_buf_insert_load_buf_ptr(drcontext, circular_fast, bb, inst, reg_ptr); scratch = reg_resize_to_opsz(scratch, OPSZ_1); MINSERT(bb, inst, XINST_CREATE_load_int (drcontext, opnd_create_reg(scratch), opnd_create_immed_int(0x41, OPSZ_1))); drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, DR_REG_NULL, opnd_create_reg(scratch), OPSZ_1, 0); MINSERT(bb, inst, XINST_CREATE_load_int (drcontext, opnd_create_reg(scratch), opnd_create_immed_int(0x42, OPSZ_1))); drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, DR_REG_NULL, opnd_create_reg(scratch), OPSZ_1, 1); scratch = reg_resize_to_opsz(scratch, OPSZ_2); MINSERT(bb, inst, XINST_CREATE_load_int (drcontext, opnd_create_reg(scratch), opnd_create_immed_int(0x4443, OPSZ_2))); drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, DR_REG_NULL, opnd_create_reg(scratch), OPSZ_2, 2); scratch = reg_resize_to_opsz(scratch, OPSZ_4); #ifdef X86 MINSERT(bb, inst, XINST_CREATE_load_int (drcontext, opnd_create_reg(scratch), opnd_create_immed_int(0x48474645, OPSZ_4))); #else instrlist_insert_mov_immed_ptrsz(drcontext, 0x48474645, opnd_create_reg(reg_resize_to_opsz (scratch, OPSZ_PTR)), bb, inst, NULL, NULL); #endif drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, DR_REG_NULL, opnd_create_reg(scratch), OPSZ_4, 4); #ifdef X64 scratch = reg_resize_to_opsz(scratch, OPSZ_8); /* only way to reliably move a 64 bit int into a register */ instrlist_insert_mov_immed_ptrsz(drcontext, 0x4847464544434241, opnd_create_reg(scratch), bb, inst, NULL, NULL); drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, DR_REG_NULL, opnd_create_reg(scratch), OPSZ_8, 8); drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, scratch, opnd_create_immed_int(0x00, OPSZ_1), OPSZ_1, 17); #else drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr, scratch, opnd_create_immed_int(0x00, OPSZ_1), OPSZ_1, 9); #endif dr_insert_clean_call(drcontext, bb, inst, verify_store, false, 1, OPND_CREATE_INTPTR(circular_fast)); } else if (subtest == DRX_BUF_TEST_6_C) { /* Currently, the fast circular buffer does not recommend variable-size * writes, for good reason. We don't test the memcpy operation on the * fast circular buffer. */ /* verify memcpy works on the slow clrcular buffer */ drx_buf_insert_load_buf_ptr(drcontext, circular_slow, bb, inst, reg_ptr); instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)test_copy, opnd_create_reg(reg_resize_to_opsz (scratch, OPSZ_PTR)), bb, inst, NULL, NULL); drx_buf_insert_buf_memcpy(drcontext, circular_slow, bb, inst, reg_ptr, reg_resize_to_opsz(scratch, OPSZ_PTR), sizeof(test_copy)); /* NULL out the buffer */ drx_buf_insert_load_buf_ptr(drcontext, circular_slow, bb, inst, reg_ptr); instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)test_null, opnd_create_reg(reg_resize_to_opsz (scratch, OPSZ_PTR)), bb, inst, NULL, NULL); drx_buf_insert_buf_memcpy(drcontext, circular_slow, bb, inst, reg_ptr, reg_resize_to_opsz(scratch, OPSZ_PTR), sizeof(test_null)); /* Unfortunately, we can't just use the check in verify_buffer_empty, because * drx_buf_insert_buf_memcpy() incrememnts the buffer pointer internally, unlike * drx_buf_insert_buf_store(). We simply check that the buffer was NULLed out. */ dr_insert_clean_call(drcontext, bb, inst, (void *)verify_buffers_nulled, false, 1, OPND_CREATE_INTPTR(circular_slow)); /* verify memcpy works on the trace buffer */ drx_buf_insert_load_buf_ptr(drcontext, trace, bb, inst, reg_ptr); instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)test_copy, opnd_create_reg(reg_resize_to_opsz (scratch, OPSZ_PTR)), bb, inst, NULL, NULL); drx_buf_insert_buf_memcpy(drcontext, trace, bb, inst, reg_ptr, reg_resize_to_opsz(scratch, OPSZ_PTR), sizeof(test_copy)); /* NULL out the buffer */ drx_buf_insert_load_buf_ptr(drcontext, trace, bb, inst, reg_ptr); instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)test_null, opnd_create_reg(reg_resize_to_opsz (scratch, OPSZ_PTR)), bb, inst, NULL, NULL); drx_buf_insert_buf_memcpy(drcontext, trace, bb, inst, reg_ptr, reg_resize_to_opsz(scratch, OPSZ_PTR), sizeof(test_null)); /* verify buffer was NULLed */ dr_insert_clean_call(drcontext, bb, inst, (void *)verify_buffers_nulled, false, 1, OPND_CREATE_INTPTR(trace)); } return DR_EMIT_DEFAULT; }
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; }
static dr_emit_flags_t bb_event(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating) { instr_t *instr, *next_instr; for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) { next_instr = instr_get_next(instr); if (instr_is_cbr(instr)) { /* Conditional branch. We can determine the target and * fallthrough addresses here, but we want to note the * edge if and when 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 the instrumentation for an edge * after it executes. */ cbr_state_t state; bool insert_taken, insert_not_taken; app_pc src = instr_get_app_pc(instr); /* 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_NEITHER; insert(table, src, CBR_NEITHER); } 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 existing cbr to jump to a callout for * the 'taken' case. We'll insert a 'not-taken' * callout at the fallthrough address. */ instr_t *label = INSTR_CREATE_label(drcontext); /* should be meta, and meta-instrs shouldn't have translations */ instr_set_meta_no_translation(instr); /* it may not reach (in particular for x64) w/ our added clean call */ 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. Insert after * the cbr (i.e., 3rd argument is NULL). */ 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(src), OPND_CREATE_INTPTR(fall)); } /* After the callout, jump to the original fallthrough * address. Note that this is an exit cti, and should * not be a meta-instruction. Therefore, we use * preinsert instead of meta_preinsert, and we must * set the translation field. On Windows, this jump * and the final jump below never execute since the * at_taken and at_not_taken callouts redirect * execution and never return. However, since the API * expects clients to produced well-formed code, we * insert explicit exits from the block for Windows as * well as Linux. */ 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(src), OPND_CREATE_INTPTR(targ)); } /* After the callout, 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; }
static dr_emit_flags_t bb_event(void* drcontext, void *tag, instrlist_t* bb, bool for_trace, bool translating) { instr_t* instr = instrlist_first(bb); instr_t *ins1, *ins2; global_var = (ptr_uint_t)INT_MAX + 1; dr_prepare_for_call(drcontext, bb, instr); /* test push_imm */ instrlist_insert_push_immed_ptrsz(drcontext, (ptr_int_t)1, bb, instr, &ins1, &ins2); instr_set_ok_to_mangle(ins1, false); if (ins2 != NULL) /* ins2 should be NULL */ dr_fprintf(STDERR, "Error on push 1\n"); #ifdef X64 MINSERT(bb, instr, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(IF_LINUX_ELSE(DR_REG_RDX, DR_REG_R8)), OPND_CREATE_MEMPTR(DR_REG_RSP, 0))); #endif instrlist_insert_push_immed_ptrsz(drcontext, (ptr_int_t)-1, bb, instr, &ins1, &ins2); instr_set_ok_to_mangle(ins1, false); if (ins2 != NULL) /* ins2 should be NULL */ dr_fprintf(STDERR, "Error on push -1\n"); #ifdef X64 MINSERT(bb, instr, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(IF_LINUX_ELSE(DR_REG_RSI, DR_REG_RDX)), OPND_CREATE_MEMPTR(DR_REG_RSP, 0))); #endif instrlist_insert_push_immed_ptrsz(drcontext, global_var, bb, instr, &ins1, &ins2); instr_set_ok_to_mangle(ins1, false); #ifdef X64 if (ins2 == NULL) /* ins2 should not be NULL */ dr_fprintf(STDERR, "Error on push tag\n"); else instr_set_ok_to_mangle(ins2, false); #endif #ifdef X64 MINSERT(bb, instr, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(IF_LINUX_ELSE(DR_REG_RDI, DR_REG_RCX)), OPND_CREATE_MEMPTR(DR_REG_RSP, 0))); #endif /* test mov_imm */ instrlist_insert_mov_immed_ptrsz(drcontext, global_var, OPND_CREATE_ABSMEM(&var0, OPSZ_PTR), bb, instr, &ins1, &ins2); instr_set_ok_to_mangle(ins1, false); #ifdef X64 if (ins2 == NULL) /* ins2 should not be NULL */ dr_fprintf(STDERR, "Error on mov %p\n", global_var); else instr_set_ok_to_mangle(ins2, false); #endif instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)-1, OPND_CREATE_ABSMEM(&var1, OPSZ_PTR), bb, instr, &ins1, &ins2); instr_set_ok_to_mangle(ins1, false); if (ins2 != NULL) /* ins2 should be NULL */ dr_fprintf(STDERR, "Error on mov -1\n"); instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)1, OPND_CREATE_ABSMEM(&var2, OPSZ_PTR), bb, instr, &ins1, &ins2); instr_set_ok_to_mangle(ins1, false); if (ins2 != NULL) /* ins2 should be NULL */ dr_fprintf(STDERR, "Error on mov 1\n"); /* call */ MINSERT(bb, instr, INSTR_CREATE_call (drcontext, opnd_create_pc((void*)my_abort))); dr_cleanup_after_call(drcontext, bb, instr, 0); return DR_EMIT_DEFAULT; }