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 test_modrm16_helper(void *dc, reg_id_t base, reg_id_t scale, uint disp, uint len) { instr_t *instr; /* Avoid REG_EAX b/c of the special 0xa0-0xa3 opcodes */ instr = INSTR_CREATE_mov_ld(dc, opnd_create_reg(REG_EBX), opnd_create_base_disp(base, scale, (scale == REG_NULL ? 0 : 1), /* we need OPSZ_4_short2 to match * instr_same on decode! */ disp, OPSZ_4_short2)); if (base == REG_NULL && scale == REG_NULL) { /* Don't need _ex unless abs addr, in which case should get 32-bit * disp! Test both sides. */ test_instr_encode(dc, instr, len + 1/*32-bit disp but no prefix*/); instr = INSTR_CREATE_mov_ld(dc, opnd_create_reg(REG_EBX), opnd_create_base_disp_ex(base, scale, (scale == REG_NULL ? 0 : 1), /* we need OPSZ_4_short2 to match * instr_same on decode! */ disp, OPSZ_4_short2, false, false, true)); test_instr_encode(dc, instr, len); } else { test_instr_encode(dc, instr, len); } }
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))); }
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);*/ }
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))); }
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; }
/* 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)); }
dr_emit_flags_t memdump_bb_instrumentation(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr, bool for_trace, bool translating, void *user_data) { reg_id_t reg1 = DR_REG_XAX; reg_id_t reg2 = DR_REG_XBX; int i = 0; if(filter_bb_level_from_list(app_pc_head, instr)){ dr_save_reg(drcontext, bb, instr, reg1, SPILL_SLOT_1); dr_save_reg(drcontext, bb, instr, reg2, SPILL_SLOT_2); dr_mutex_lock(mutex); DEBUG_PRINT("instrumenting %x pc\n", instr_get_app_pc(instr)); instr_clones[instr_clone_amount] = instr_clone(drcontext, instr); for (i = 0; i < instr_num_srcs(instr); i++){ if (opnd_is_memory_reference(instr_get_src(instr, i))) { drutil_insert_get_mem_addr(drcontext, bb, instr, instr_get_src(instr,i), reg1, reg2); dr_insert_clean_call(drcontext, bb, instr, clean_call_mem_information, false, 3, OPND_CREATE_INTPTR(instr_clones[instr_clone_amount]), opnd_create_reg(reg1), OPND_CREATE_INTPTR(false)); } } for (i = 0; i < instr_num_dsts(instr); i++){ if (opnd_is_memory_reference(instr_get_dst(instr, i))) { drutil_insert_get_mem_addr(drcontext, bb, instr, instr_get_dst(instr, i), reg1, reg2); dr_insert_clean_call(drcontext, bb, instr, clean_call_mem_information, false, 3, OPND_CREATE_INTPTR(instr_clones[instr_clone_amount]), opnd_create_reg(reg1), OPND_CREATE_INTPTR(true)); } } instr_clone_amount++; dr_mutex_unlock(mutex); dr_restore_reg(drcontext, bb, instr, reg1, SPILL_SLOT_1); dr_restore_reg(drcontext, bb, instr, reg2, SPILL_SLOT_2); } return DR_EMIT_DEFAULT; }
static void test_instr_as_immed(void) { void *drcontext = dr_get_current_drcontext(); instrlist_t *ilist = instrlist_create(drcontext); byte *pc; instr_t *ins0, *ins1, *ins2; opnd_t opnd; byte *highmem = PREFERRED_ADDR; pc = dr_raw_mem_alloc(PAGE_SIZE, DR_MEMPROT_READ|DR_MEMPROT_WRITE| DR_MEMPROT_EXEC, highmem); ASSERT(pc == highmem); /* Test push_imm of instr */ ins0 = INSTR_CREATE_nop(drcontext); instrlist_append(ilist, ins0); instrlist_insert_push_instr_addr(drcontext, ins0, highmem, ilist, NULL, &ins1, &ins2); ASSERT(ins2 != NULL); instrlist_append(ilist, INSTR_CREATE_pop (drcontext, opnd_create_reg(DR_REG_RAX))); instrlist_append(ilist, INSTR_CREATE_ret(drcontext)); pc = instrlist_encode(drcontext, ilist, highmem, true); instrlist_clear(drcontext, ilist); ASSERT(pc < highmem + PAGE_SIZE); pc = ((byte* (*)(void))highmem)(); ASSERT(pc == highmem); /* Test mov_imm of instr */ ins0 = INSTR_CREATE_nop(drcontext); instrlist_append(ilist, ins0); /* Beyond TOS, but a convenient mem dest */ opnd = opnd_create_base_disp(DR_REG_RSP, DR_REG_NULL, 0, -8, OPSZ_8); instrlist_insert_mov_instr_addr(drcontext, ins0, highmem, opnd, ilist, NULL, &ins1, &ins2); ASSERT(ins2 != NULL); instrlist_append(ilist, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(DR_REG_RAX), opnd)); instrlist_append(ilist, INSTR_CREATE_ret(drcontext)); pc = instrlist_encode(drcontext, ilist, highmem, true); instrlist_clear(drcontext, ilist); ASSERT(pc < highmem + PAGE_SIZE); pc = ((byte* (*)(void))highmem)(); ASSERT(pc == highmem); instrlist_clear_and_destroy(drcontext, ilist); dr_raw_mem_free(highmem, PAGE_SIZE); }
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*/); }
static dr_emit_flags_t bb_event(void* drcontext, void *tag, instrlist_t* bb, bool for_trace, bool translating) { instr_t *instr; instr_t *next_instr; reg_t in_eax = -1; for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) { next_instr = instr_get_next(instr); if (instr_get_opcode(instr) == OP_mov_imm && opnd_get_reg(instr_get_dst(instr, 0)) == REG_EAX) in_eax = opnd_get_immed_int(instr_get_src(instr, 0)); if (instr_is_syscall(instr) && in_eax == SYS_getpid) { instr_t *myval = INSTR_CREATE_mov_imm (drcontext, opnd_create_reg(REG_EAX), OPND_CREATE_INT32(-7)); instr_set_translation(myval, instr_get_app_pc(instr)); instrlist_preinsert(bb, instr, myval); instrlist_remove(bb, instr); instr_destroy(drcontext, instr); } } return DR_EMIT_DEFAULT; }
/* * Function that tests a single operand of an instruction to see if * it's a memory reference, and if so, adds a call to log_mem. */ static void try_mem_opnd( void *drcontext, instrlist_t *bb, instr_t *instr, char **loc, opnd_t opnd, bool write) { if (!opnd_is_memory_reference(opnd)) return; instr_format_location(instr, loc); reg_id_t r0, r1; drreg_status_t st; st = drreg_reserve_register(drcontext, bb, instr, NULL, &r0); DR_ASSERT(st == DRREG_SUCCESS); st = drreg_reserve_register(drcontext, bb, instr, NULL, &r1); DR_ASSERT(st == DRREG_SUCCESS); bool ok = drutil_insert_get_mem_addr(drcontext, bb, instr, opnd, r0, r1); DR_ASSERT(ok); uint size = drutil_opnd_mem_size_in_bytes(opnd, instr); dr_insert_clean_call( drcontext, bb, instr, (void *)log_mem, false, 4, opnd_create_reg(r0), OPND_CREATE_INT32(size), OPND_CREATE_INT32(write), OPND_CREATE_INTPTR(*loc)); st = drreg_unreserve_register(drcontext, bb, instr, r1); DR_ASSERT(st == DRREG_SUCCESS); st = drreg_unreserve_register(drcontext, bb, instr, r0); DR_ASSERT(st == DRREG_SUCCESS); }
static void test_disp_control_helper(void *dc, int disp, bool encode_zero_disp, bool force_full_disp, bool disp16, uint len_expect) { byte *pc; uint len; instr_t *instr = INSTR_CREATE_mov_ld (dc, opnd_create_reg(REG_ECX), opnd_create_base_disp_ex(disp16 ? IF_X64_ELSE(REG_EBX, REG_BX) : REG_XBX, REG_NULL, 0, disp, OPSZ_4, encode_zero_disp, force_full_disp, disp16)); pc = instr_encode(dc, instr, buf); len = (int) (pc - (byte *)buf); #if VERBOSE pc = disassemble_with_info(dc, buf, STDOUT, true, true); #endif ASSERT(len == len_expect); instr_reset(dc, instr); decode(dc, buf, instr); ASSERT(instr_num_srcs(instr) == 1 && opnd_is_base_disp(instr_get_src(instr, 0)) && BOOLS_MATCH(encode_zero_disp, opnd_is_disp_encode_zero(instr_get_src(instr, 0))) && BOOLS_MATCH(force_full_disp, opnd_is_disp_force_full(instr_get_src(instr, 0))) && BOOLS_MATCH(disp16, opnd_is_disp_short_addr(instr_get_src(instr, 0)))); instr_destroy(dc, instr); }
/* code cache to hold the call to "clean_call" and return to DR code cache */ static void code_cache_init(void) { void *drcontext; instrlist_t *ilist; instr_t *where; byte *end; drcontext = dr_get_current_drcontext(); code_cache = dr_nonheap_alloc(PAGE_SIZE, DR_MEMPROT_READ | DR_MEMPROT_WRITE | DR_MEMPROT_EXEC); ilist = instrlist_create(drcontext); /* The lean procecure simply performs a clean call, and then jump back */ /* jump back to the DR's code cache */ where = INSTR_CREATE_jmp_ind(drcontext, opnd_create_reg(DR_REG_XCX)); instrlist_meta_append(ilist, where); /* clean call */ dr_insert_clean_call(drcontext, ilist, where, (void *)clean_call_ins_trace, false, 0); /* Encodes the instructions into memory and then cleans up. */ end = instrlist_encode(drcontext, ilist, code_cache, false); DR_ASSERT((end - code_cache) < PAGE_SIZE); instrlist_clear_and_destroy(drcontext, ilist); /* set the memory as just +rx now */ dr_memory_protect(code_cache, PAGE_SIZE, DR_MEMPROT_READ | DR_MEMPROT_EXEC); }
static void test_x64_abs_addr(void *dc) { /* 48 a1 ef be ad de ef be ad de mov 0xdeadbeefdeadbeef -> %rax * 48 a3 ef be ad de ef be ad de mov %rax -> 0xdeadbeefdeadbeef */ instr_t *instr; opnd_t abs_addr = opnd_create_abs_addr((void*)0xdeadbeefdeadbeef, OPSZ_8); /* movabs load */ instr = INSTR_CREATE_mov_ld(dc, opnd_create_reg(DR_REG_RAX), abs_addr); test_instr_encode(dc, instr, 10); /* REX + op + 8 */ /* movabs store */ instr = INSTR_CREATE_mov_st(dc, abs_addr, opnd_create_reg(DR_REG_RAX)); test_instr_encode(dc, instr, 10); /* REX + op + 8 */ }
static void test_x64_inc(void *dc) { /* i#842: inc/dec should not be encoded as 40-4f in x64 */ instr_t *instr; instr = INSTR_CREATE_inc(dc, opnd_create_reg(REG_EAX)); test_instr_encode(dc, instr, 2); }
static print_base_disp_for_lea(file_t file, opnd_t opnd){ /* [base + index * scale + disp] */ dr_fprintf(file, " base - %d %s\n", opnd_get_base(opnd), get_register_name(opnd_get_base(opnd))); dr_fprintf(file, " index - %d %s\n", opnd_get_index(opnd), get_register_name(opnd_get_index(opnd))); dr_fprintf(file, "reg - %d\n", opnd_is_reg(opnd_create_reg(opnd_get_index(opnd)))); dr_fprintf(file, " scale - %d\n", opnd_get_scale(opnd)); dr_fprintf(file, " disp - %d\n", opnd_get_disp(opnd)); }
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); }
/* 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 dr_emit_flags_t event_bb(void *dc, void *tag, instrlist_t *bb, bool for_trace, bool translating) { instr_t *where = instrlist_first(bb); instr_t *ret_label = INSTR_CREATE_label(dc); dr_save_reg(dc, bb, where, DR_REG_XAX, SPILL_SLOT_1); PRE(bb, where, INSTR_CREATE_mov_imm(dc, opnd_create_reg(DR_REG_XAX), opnd_create_instr(ret_label))); PRE(bb, where, INSTR_CREATE_jmp(dc, opnd_create_pc(slowpath))); PRE(bb, where, ret_label); dr_restore_reg(dc, bb, where, DR_REG_XAX, SPILL_SLOT_1); return DR_EMIT_DEFAULT; }
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) { /* hack to instrument every nth bb. assumes DR serializes bb events. */ static int freq; freq++; if (freq % 100 == 0 && inst == (instr_t*)user_data/*first instr*/) { /* test read from cache */ dr_save_reg(drcontext, bb, inst, DR_REG_XAX, SPILL_SLOT_1); drmgr_insert_read_tls_field(drcontext, tls_idx, bb, inst, DR_REG_XAX); dr_insert_clean_call(drcontext, bb, inst, (void *)check_tls_from_cache, false, 1, opnd_create_reg(DR_REG_XAX)); drmgr_insert_read_cls_field(drcontext, cls_idx, bb, inst, DR_REG_XAX); dr_insert_clean_call(drcontext, bb, inst, (void *)check_cls_from_cache, false, 1, opnd_create_reg(DR_REG_XAX)); dr_restore_reg(drcontext, bb, inst, DR_REG_XAX, SPILL_SLOT_1); } if (freq % 300 == 0 && inst == (instr_t*)user_data/*first instr*/) { /* test write from cache */ dr_save_reg(drcontext, bb, inst, DR_REG_XAX, SPILL_SLOT_1); dr_save_reg(drcontext, bb, inst, DR_REG_XCX, SPILL_SLOT_2); instrlist_meta_preinsert(bb, inst, INSTR_CREATE_mov_imm (drcontext, opnd_create_reg(DR_REG_EAX), OPND_CREATE_INT32(MAGIC_NUMBER_FROM_CACHE))); drmgr_insert_write_tls_field(drcontext, tls_idx, bb, inst, DR_REG_XAX, DR_REG_XCX); 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, DR_REG_XAX, DR_REG_XCX); dr_insert_clean_call(drcontext, bb, inst, (void *)check_cls_write_from_cache, false, 0); dr_restore_reg(drcontext, bb, inst, DR_REG_XCX, SPILL_SLOT_2); dr_restore_reg(drcontext, bb, inst, DR_REG_XAX, SPILL_SLOT_1); } return DR_EMIT_DEFAULT; }
/* save aflags from eax */ void umbra_save_eax_aflags(void *drcontext, umbra_info_t *info, instrlist_t *ilist, instr_t *where) { instr_t *instr; instr = INSTR_CREATE_mov_st(drcontext, OPND_CREATE_ABSMEM(&info->aflags, OPSZ_4), opnd_create_reg(DR_REG_EAX)); instrlist_meta_preinsert(ilist, where, instr); }
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))); }
DR_EXPORT void dr_init(client_id_t id) { /* Generate the "slowpath" which just returns to eax. */ void *dc = dr_get_current_drcontext(); instrlist_t *ilist = instrlist_create(dc); PRE(ilist, NULL, INSTR_CREATE_jmp_ind(dc, opnd_create_reg(DR_REG_XAX))); slowpath = dr_nonheap_alloc(SLOWPATH_SIZE, (DR_MEMPROT_READ| DR_MEMPROT_WRITE| DR_MEMPROT_EXEC)); instrlist_encode(dc, ilist, slowpath, false /*no relative jumps*/); instrlist_clear_and_destroy(dc, ilist); dr_register_bb_event(event_bb); dr_register_exit_event(event_exit); }
DR_EXPORT bool drmgr_insert_read_tls_field(void *drcontext, int idx, instrlist_t *ilist, instr_t *where, reg_id_t reg) { tls_array_t *tls = (tls_array_t *) dr_get_tls_field(drcontext); if (idx < 0 || idx > MAX_NUM_TLS || !tls_taken[idx] || tls == NULL) return false; if (!reg_is_gpr(reg) || !reg_is_pointer_sized(reg)) return false; dr_insert_read_tls_field(drcontext, ilist, where, reg); instrlist_meta_preinsert(ilist, where, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(reg), OPND_CREATE_MEMPTR(reg, offsetof(tls_array_t, tls) + idx*sizeof(void*)))); return true; }
/* save reg before where in ilist */ void umbra_save_reg(void *drcontext, umbra_info_t *info, instrlist_t *ilist, instr_t *where, reg_id_t reg) { int slot; instr_t *instr; DR_ASSERT(reg >= REG_SPILL_START && reg <= REG_SPILL_STOP); slot = reg - REG_SPILL_START; instr = INSTR_CREATE_mov_st(drcontext, OPND_CREATE_ABSMEM(&info->spill_regs[slot], OPSZ_PTR), opnd_create_reg(reg)); instrlist_meta_preinsert(ilist, where, instr); }
/* PR 332254: test xchg vs nop */ static void test_nop_xchg(void *dc) { /* 0x0000000000671460 87 c0 xchg %eax %eax -> %eax %eax * 0x0000000000671460 48 87 c0 xchg %rax %rax -> %rax %rax * 0x0000000000671460 41 87 c0 xchg %r8d %eax -> %r8d %eax * 0x0000000000671460 46 90 nop * 0x0000000000671460 4e 90 nop * 0x0000000000671460 41 90 xchg %r8d %eax -> %r8d %eax */ instr_t *instr; instr = INSTR_CREATE_xchg(dc, opnd_create_reg(REG_EAX), opnd_create_reg(REG_EAX)); test_instr_encode(dc, instr, 2); #ifdef X64 /* we don't do the optimal "48 90" instead of "48 87 c0" */ instr = INSTR_CREATE_xchg(dc, opnd_create_reg(REG_RAX), opnd_create_reg(REG_RAX)); test_instr_encode(dc, instr, 3); /* we don't do the optimal "41 90" instead of "41 87 c0" */ instr = INSTR_CREATE_xchg(dc, opnd_create_reg(REG_R8D), opnd_create_reg(REG_EAX)); test_instr_encode(dc, instr, 3); /* ensure we treat as nop and NOT xchg if doesn't have rex.b */ buf[0] = 0x46; buf[1] = 0x90; instr = instr_create(dc); # if VERBOSE disassemble_with_info(dc, buf, STDOUT, true, true); # endif decode(dc, buf, instr); ASSERT(instr_get_opcode(instr) == OP_nop); instr_destroy(dc, instr); buf[0] = 0x4e; buf[1] = 0x90; instr = instr_create(dc); # if VERBOSE disassemble_with_info(dc, buf, STDOUT, true, true); # endif decode(dc, buf, instr); ASSERT(instr_get_opcode(instr) == OP_nop); instr_destroy(dc, instr); buf[0] = 0x41; buf[1] = 0x90; instr = instr_create(dc); # if VERBOSE disassemble_with_info(dc, buf, STDOUT, true, true); # endif decode(dc, buf, instr); ASSERT(instr_get_opcode(instr) == OP_xchg); instr_destroy(dc, instr); #endif }
static bool reg_update_is_limited(instr_t *instr, reg_id_t reg) { int opcode; int offset; opcode = instr_get_opcode(instr); if (opcode == OP_inc || opcode == OP_dec) return true; if (opcode == OP_and) /* for 0xffffffd0 & reg => reg */ return true; if ((opcode == OP_add || opcode == OP_sub || opcode == OP_adc || opcode == OP_sbb) && opnd_is_immed_int(instr_get_src(instr, 0))) { offset = opnd_get_immed_int(instr_get_src(instr, 0)); if (offset > PAGE_SIZE || offset < -PAGE_SIZE) return false; return true; } if (reg != DR_REG_XSP) return false; if (opcode >= OP_push && opcode <= OP_popa) { if (opcode == OP_pop && opnd_same(instr_get_dst(instr, 0), opnd_create_reg(DR_REG_XSP))) return false; return true; } if (opcode >= OP_call && opcode <= OP_call_far_ind) return true; if (opcode == OP_ret || opcode == OP_ret_far || opcode == OP_enter || opcode == OP_leave || opcode == OP_pushf || opcode == OP_popf) return true; return false; }
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. }
/* prints the trace and empties the instruction buffer */ static void ins_trace(void *drcontext) { per_thread_t *data; int num_refs; instr_trace_t *instr_trace; instr_t * instr; int i; int j; #ifdef READABLE_TRACE char disassembly[SHORT_STRING_LENGTH]; #else output_t * output; #endif data = drmgr_get_tls_field(drcontext, tls_index); instr_trace = (instr_trace_t *)data->buf_base; num_refs = (int)((instr_trace_t *)data->buf_ptr - instr_trace); uint mem_type; uint64 mem_addr; opnd_t opnd; #ifdef READABLE_TRACE //TODO for (i = 0; i < num_refs; i++) { instr = instr_trace->static_info_instr; instr_disassemble_to_buffer(drcontext,instr,disassembly,SHORT_STRING_LENGTH); dr_fprintf(data->outfile,"%u",instr_get_opcode(instr)); dr_fprintf(data->outfile,",%u",calculate_operands(instr,DST_TYPE)); for(j=0; j<instr_num_dsts(instr); j++){ get_address(instr_trace, j, DST_TYPE, &mem_type, &mem_addr); output_populator_printer(drcontext,instr_get_dst(instr,j),instr,mem_addr,mem_type,NULL); } dr_fprintf(data->outfile,",%u",calculate_operands(instr,SRC_TYPE)); for(j=0; j<instr_num_srcs(instr); j++){ get_address(instr_trace, j, SRC_TYPE, &mem_type, &mem_addr); opnd = instr_get_src(instr, j); if (instr_get_opcode(instr) == OP_lea && opnd_is_base_disp(opnd)){ /* four operands here for [base + index * scale + disp] */ output_populator_printer(drcontext, opnd_create_reg(opnd_get_base(opnd)), instr, mem_addr, mem_type, NULL); output_populator_printer(drcontext, opnd_create_reg(opnd_get_index(opnd)), instr, mem_addr, mem_type, NULL); output_populator_printer(drcontext, opnd_create_immed_int(opnd_get_scale(opnd),OPSZ_PTR), instr, mem_addr, mem_type, NULL); output_populator_printer(drcontext, opnd_create_immed_int(opnd_get_disp(opnd), OPSZ_PTR), instr, mem_addr, mem_type, NULL); } else{ output_populator_printer(drcontext, opnd, instr, mem_addr, mem_type, NULL); } } dr_fprintf(data->outfile,",%u,%u\n",instr_trace->eflags,instr_trace->pc); ++instr_trace; } #else /* we need to fill up the output array here */ for(i = 0; i< num_refs; i++){ instr = instr_trace->static_info_instr; output = &data->output_array[i]; //opcode output->opcode = instr_get_opcode(instr); output->num_dsts = 0; output->num_srcs = 0; for(j=0; j<instr_num_dsts(instr); j++){ output_populator_printer(drcontext,instr_get_dst(instr,j),instr,get_address(instr_trace,j,DST_TYPE),&output->dsts[output->num_dsts]); output->num_dsts++; } for(j=0; j<instr_num_srcs(instr); j++){ output_populator_printer(drcontext,instr_get_src(instr,j),instr,get_address(instr_trace,j,SRC_TYPE),&output->srcs[output->num_srcs]); output->num_srcs++; } output->eflags = instr_trace->eflags; ++instr_trace; } dr_write_file(data->outfile,data->output_array,num_refs * sizeof(output_t)); #endif memset(data->buf_base, 0, INSTR_BUF_SIZE); data->num_refs += num_refs; data->buf_ptr = data->buf_base; }