static void test_instr_opnds(void *dc) { /* Verbose disasm looks like this: * 32-bit: * 0x080f1ae0 ff 25 e7 1a 0f 08 jmp 0x080f1ae7 * 0x080f1ae6 b8 ef be ad de mov $0xdeadbeef -> %eax * 0x080f1ae0 a0 e6 1a 0f 08 mov 0x080f1ae6 -> %al * 0x080f1ae5 b8 ef be ad de mov $0xdeadbeef -> %eax * 64-bit: * 0x00000000006b8de0 ff 25 02 00 00 00 jmp <rel> 0x00000000006b8de8 * 0x00000000006b8de6 48 b8 ef be ad de 00 mov $0x00000000deadbeef -> %rax * 00 00 00 * 0x00000000006b8de0 8a 05 02 00 00 00 mov <rel> 0x00000000006b8de8 -> %al * 0x00000000006b8de6 48 b8 ef be ad de 00 mov $0x00000000deadbeef -> %rax * 00 00 00 */ instrlist_t *ilist; instr_t *tgt, *instr; byte *pc; short disp; ilist = instrlist_create(dc); /* test mem instr as ind jmp target */ tgt = INSTR_CREATE_mov_imm(dc, opnd_create_reg(DR_REG_XAX), opnd_create_immed_int(0xdeadbeef, OPSZ_PTR)); /* skip rex+opcode */ disp = IF_X64_ELSE(2,1); instrlist_append(ilist, INSTR_CREATE_jmp_ind (dc, opnd_create_mem_instr(tgt, disp, OPSZ_PTR))); instrlist_append(ilist, tgt); pc = instrlist_encode(dc, ilist, buf, true/*instr targets*/); ASSERT(pc != NULL); instrlist_clear(dc, ilist); #if VERBOSE pc = disassemble_with_info(dc, buf, STDOUT, true, true); pc = disassemble_with_info(dc, pc, STDOUT, true, true); #endif pc = buf; instr = instr_create(dc); pc = decode(dc, pc, instr); ASSERT(pc != NULL); ASSERT(instr_get_opcode(instr) == OP_jmp_ind); #ifdef X64 ASSERT(opnd_is_rel_addr(instr_get_src(instr, 0))); ASSERT(opnd_get_addr(instr_get_src(instr, 0)) == pc + disp); #else ASSERT(opnd_is_base_disp(instr_get_src(instr, 0))); ASSERT(opnd_get_base(instr_get_src(instr, 0)) == REG_NULL); ASSERT(opnd_get_index(instr_get_src(instr, 0)) == REG_NULL); ASSERT(opnd_get_disp(instr_get_src(instr, 0)) == (ptr_int_t)pc + disp); #endif /* test mem instr as TYPE_O */ tgt = INSTR_CREATE_mov_imm(dc, opnd_create_reg(DR_REG_XAX), opnd_create_immed_int(0xdeadbeef, OPSZ_PTR)); /* skip rex+opcode */ disp = IF_X64_ELSE(2,1); instrlist_append(ilist, INSTR_CREATE_mov_ld (dc, opnd_create_reg(DR_REG_AL), opnd_create_mem_instr(tgt, disp, OPSZ_1))); instrlist_append(ilist, tgt); pc = instrlist_encode(dc, ilist, buf, true/*instr targets*/); ASSERT(pc != NULL); instrlist_clear(dc, ilist); #if VERBOSE pc = disassemble_with_info(dc, buf, STDOUT, true, true); pc = disassemble_with_info(dc, pc, STDOUT, true, true); #endif pc = buf; instr_reset(dc, instr); pc = decode(dc, pc, instr); ASSERT(pc != NULL); ASSERT(instr_get_opcode(instr) == OP_mov_ld); #ifdef X64 ASSERT(opnd_is_rel_addr(instr_get_src(instr, 0))); ASSERT(opnd_get_addr(instr_get_src(instr, 0)) == pc + disp); #else ASSERT(opnd_is_base_disp(instr_get_src(instr, 0))); ASSERT(opnd_get_base(instr_get_src(instr, 0)) == REG_NULL); ASSERT(opnd_get_index(instr_get_src(instr, 0)) == REG_NULL); ASSERT(opnd_get_disp(instr_get_src(instr, 0)) == (ptr_int_t)pc + disp); #endif instr_free(dc, instr); instrlist_destroy(dc, ilist); }
void watchpoint_indirect_call_event(dcontext_t *drcontext, instrlist_t *ilist, instr_t *instr, instr_t *next_instr, bool mangle_calls, uint flags) { opnd_t instr_opnd; reg_id_t base_reg; unsigned long used_registers = 0; app_pc pc; struct memory_operand_modifier ops = {0}; instr_t *begin_instrumenting = INSTR_CREATE_label(drcontext); instr_t *done_instrumenting = INSTR_CREATE_label(drcontext); instr_t *nop = INSTR_CREATE_nop(drcontext); instr_t *emulated; memset(&ops, 0, sizeof(struct memory_operand_modifier)); if(instr_reads_memory(instr)) { instr_opnd = instr_get_src(instr, 0); if (opnd_is_rel_addr(instr_opnd) || opnd_is_abs_addr(instr_opnd)) { }else if (opnd_is_base_disp(instr_opnd)) { for_each_src_operand(instr, &ops, (opnd_callback_t *) memory_src_operand_finder); // base_reg = opnd_get_reg(instr_opnd); switch(ops.found_operand.value.base_disp.base_reg) { case DR_REG_RSP: case DR_REG_ESP: case DR_REG_SP: case DR_REG_RBP: case DR_REG_EBP: case DR_REG_BP: return; default: break; } collect_regs(&used_registers, instr, instr_num_srcs, instr_get_src ); collect_regs(&used_registers, instr, instr_num_dsts, instr_get_dst ); reg_id_t reg_watched_addr = get_next_free_reg(&used_registers); opnd_t opnd_watched_addr = opnd_create_reg(reg_watched_addr); reg_id_t reg_unwatched_addr = get_next_free_reg(&used_registers); opnd_t opnd_unwatched_addr = opnd_create_reg(reg_unwatched_addr); PRE(ilist, instr, begin_instrumenting); PRE(ilist, instr, INSTR_CREATE_push(drcontext, opnd_watched_addr)); PRE(ilist, instr, INSTR_CREATE_push(drcontext, opnd_unwatched_addr)); PRE(ilist, instr, INSTR_CREATE_pushf(drcontext)); PRE(ilist, instr, INSTR_CREATE_lea(drcontext, opnd_watched_addr, opnd_create_base_disp(opnd_get_base(ops.found_operand), opnd_get_index(ops.found_operand), opnd_get_scale(ops.found_operand), opnd_get_disp(ops.found_operand), OPSZ_lea))); PRE(ilist, instr, INSTR_CREATE_mov_imm(drcontext, opnd_unwatched_addr, OPND_CREATE_INT64(WATCHPOINT_INDEX_MASK))); PRE(ilist, instr, INSTR_CREATE_or(drcontext, opnd_unwatched_addr, opnd_watched_addr)); emulated = instr_clone(drcontext, instr); emulated->translation = 0; ops.replacement_operand = opnd_create_base_disp( reg_unwatched_addr, DR_REG_NULL,1, 0 , ops.found_operand.size); for_each_operand(emulated, &ops, (opnd_callback_t *) memory_operand_replacer); PRE(ilist, instr, INSTR_CREATE_popf(drcontext)); PRE(ilist, instr, emulated); PRE(ilist, instr, INSTR_CREATE_pop(drcontext, opnd_unwatched_addr)); PRE(ilist, instr, INSTR_CREATE_pop(drcontext, opnd_watched_addr)); PRE(ilist, instr, INSTR_CREATE_jmp_short(drcontext, opnd_create_instr(done_instrumenting))); pc = instr->translation; instr->translation = 0; // hack! instr_being_modified(instr, false); instr_set_ok_to_mangle(instr, false); if(NULL != pc){ nop->translation = pc + instr->length; } POST(ilist, instr, nop); POST(ilist, instr, done_instrumenting); } } }