static dr_emit_flags_t event_bb ( void* drcontext, void* tag, instrlist_t* bb, bool for_trace, bool translating ) { /* refer to dr_ir_instr.h */ instr_t* insn = instrlist_first(bb); for (; insn != NULL; insn = instr_get_next(insn)) { ++insn_count; if (instr_reads_memory(insn)) { ++read_count; read_size += instr_memory_reference_size(insn); dr_printf("read_size:%u\n", instr_memory_reference_size(insn)); } if (instr_writes_memory(insn)) { ++writ_count; writ_size += instr_memory_reference_size(insn); } } return DR_EMIT_DEFAULT; }
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating) { int i; instr_t *instr, *first = instrlist_first(bb); for (instr = first; instr != NULL; instr = instr_get_next(instr)) { if (instr_reads_memory(instr)) { for (i = 0; i < instr_num_srcs(instr); i++) { if (opnd_is_memory_reference(instr_get_src(instr, i))) { instrument_mem(drcontext, bb, instr, i, false); } } } if (instr_writes_memory(instr)) { for (i = 0; i < instr_num_dsts(instr); i++) { if (opnd_is_memory_reference(instr_get_dst(instr, i))) { instrument_mem(drcontext, bb, instr, i, true); } } } } // dr_printf("count %d\n",count); return DR_EMIT_DEFAULT; }
/* event_bb_insert calls instrument_mem to instrument every * application memory reference. */ dr_emit_flags_t memtrace_bb_instrumentation(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr, bool for_trace, bool translating, void *user_data) { int i; reg_id_t reg; file_t out_file; instr_t * first = NULL; instr_t * current; //DR_ASSERT(instr_ok_to_mangle(instr)); if (instr_ok_to_mangle(instr)){ /* FIXME - need to generalize the filtering library */ for (current = instrlist_first(bb); current != NULL; current = instr_get_next(current)){ if (instr_ok_to_mangle(current)){ first = current; break; } } if ((first != NULL) && filter_from_list(head, first, client_arg->filter_mode)){ if (instr_reads_memory(instr)) { for (i = 0; i < instr_num_srcs(instr); i++) { if (opnd_is_memory_reference(instr_get_src(instr, i))) { instrument_mem(drcontext, bb, instr, i, false); } } } if (instr_writes_memory(instr)) { for (i = 0; i < instr_num_dsts(instr); i++) { if (opnd_is_memory_reference(instr_get_dst(instr, i))) { instrument_mem(drcontext, bb, instr, i, true); } } } } } return DR_EMIT_DEFAULT; }
/* For each memory reference app instr, we insert inline code to fill the buffer * with an instruction entry and memory reference entries. */ static dr_emit_flags_t event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr, bool for_trace, bool translating, void *user_data) { int i; if (!instr_is_app(instr)) return DR_EMIT_DEFAULT; if (!instr_reads_memory(instr) && !instr_writes_memory(instr)) return DR_EMIT_DEFAULT; /* insert code to add an entry for app instruction */ instrument_instr(drcontext, bb, instr); /* insert code to add an entry for each memory reference opnd */ for (i = 0; i < instr_num_srcs(instr); i++) { if (opnd_is_memory_reference(instr_get_src(instr, i))) instrument_mem(drcontext, bb, instr, instr_get_src(instr, i), false); } for (i = 0; i < instr_num_dsts(instr); i++) { if (opnd_is_memory_reference(instr_get_dst(instr, i))) instrument_mem(drcontext, bb, instr, instr_get_dst(instr, i), true); } /* insert code to call clean_call for processing the buffer */ if (/* XXX i#1698: there are constraints for code between ldrex/strex pairs, * so we minimize the instrumentation in between by skipping the clean call. * As we're only inserting instrumentation on a memory reference, and the * app should be avoiding memory accesses in between the ldrex...strex, * the only problematic point should be before the strex. * However, there is still a chance that the instrumentation code may clear the * exclusive monitor state. * Using a fault to handle a full buffer should be more robust, and the * forthcoming buffer filling API (i#513) will provide that. */ IF_AARCHXX_ELSE(!instr_is_exclusive_store(instr), true)) dr_insert_clean_call(drcontext, bb, instr, (void *)clean_call, false, 0); return DR_EMIT_DEFAULT; }
/* event_bb_insert calls instrument_mem to instrument every * application memory reference. */ static dr_emit_flags_t event_bb_insert(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr, bool for_trace, bool translating, void *user_data) { int i; if (instr_get_app_pc(instr) == NULL) return DR_EMIT_DEFAULT; if (instr_reads_memory(instr)) { for (i = 0; i < instr_num_srcs(instr); i++) { if (opnd_is_memory_reference(instr_get_src(instr, i))) { instrument_mem(drcontext, bb, instr, i, false); } } } if (instr_writes_memory(instr)) { for (i = 0; i < instr_num_dsts(instr); i++) { if (opnd_is_memory_reference(instr_get_dst(instr, i))) { instrument_mem(drcontext, bb, instr, i, true); } } } return DR_EMIT_DEFAULT; }
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); } } }
/* * The main function called to instrument each machine instruction. */ static dr_emit_flags_t instrument_instr( void *drcontext, void *tag, instrlist_t *bb, instr_t *instr, bool for_trace, bool translating, void *user_data) { char *loc = NULL; /* * If this instruction is the first in its basic block, call * log_pc to record that we're executing this block at all. */ if (drmgr_is_first_instr(drcontext, instr)) { instr_format_location(instr, &loc); dr_insert_clean_call( drcontext, bb, instr, (void *)log_pc, false, 1, OPND_CREATE_INTPTR(loc)); } /* * If the instruction reads or writes memory, log its access. */ if (instr_reads_memory(instr) || instr_writes_memory(instr)) { for (int i = 0, limit = instr_num_srcs(instr); i < limit; i++) try_mem_opnd(drcontext, bb, instr, &loc, instr_get_src(instr, i), false); for (int i = 0, limit = instr_num_dsts(instr); i < limit; i++) try_mem_opnd(drcontext, bb, instr, &loc, instr_get_dst(instr, i), false); } /* * Now do opcode-specific checks. */ int opcode = instr_get_opcode(instr); switch (opcode) { case OP_div: case OP_idiv: /* * x86 hardware divisions. The operand order for DR's * representation of these seem to be: 0 = denominator, 1 = * numerator MSW, 2 = numerator LSW. */ instr_format_location(instr, &loc); dr_insert_clean_call( drcontext, bb, instr, (void *)log_div, false, 3, instr_get_src(instr, 2), instr_get_src(instr, 0), OPND_CREATE_INTPTR(loc)); break; case OP_shl: case OP_shr: case OP_sar: case OP_shlx: case OP_shrx: case OP_sarx: case OP_rol: case OP_ror: case OP_rcl: case OP_rcr: /* * Shift instructions. If they're register-controlled, log the * shift count. */ { opnd_t shiftcount = instr_get_src(instr, 0); if (!opnd_is_immed(shiftcount)) { reg_id_t r0; drreg_status_t st; st = drreg_reserve_register(drcontext, bb, instr, NULL, &r0); DR_ASSERT(st == DRREG_SUCCESS); opnd_t op_r0 = opnd_create_reg(r0); instrlist_preinsert(bb, instr, INSTR_CREATE_movzx( drcontext, op_r0, shiftcount)); instr_format_location(instr, &loc); dr_insert_clean_call( drcontext, bb, instr, (void *)log_var_shift, false, 2, op_r0, OPND_CREATE_INTPTR(loc)); st = drreg_unreserve_register(drcontext, bb, instr, r0); DR_ASSERT(st == DRREG_SUCCESS); } } break; } return DR_EMIT_DEFAULT; }