/* this is only called when the instrace mode is operand trace (this happens at the instrumentation time) */ static void operand_trace(instr_t * instr, void * drcontext){ int i; char stringop[MAX_STRING_LENGTH]; int pc = 0; per_thread_t * data = drmgr_get_tls_field(drcontext, tls_index); module_data_t * module_data = dr_lookup_module(instr_get_app_pc(instr)); if (module_data != NULL){ pc = instr_get_app_pc(instr) - module_data->start; } instr_disassemble_to_buffer(drcontext, instr, stringop, MAX_STRING_LENGTH); if (client_arg->instrace_mode == OPERAND_TRACE){ dr_fprintf(data->outfile, "%s\n", stringop); for (i = 0; i < instr_num_dsts(instr); i++){ opnd_disassemble_to_buffer(drcontext, instr_get_dst(instr, i), stringop, MAX_STRING_LENGTH); if ((instr_get_opcode(instr) == OP_lea) && opnd_is_base_disp(instr_get_dst(instr,i))){ dr_fprintf(data->outfile, "dst-\n"); print_base_disp_for_lea(data->outfile, instr_get_dst(instr, i)); } else{ dr_fprintf(data->outfile, "dst-%d-%s\n", i, stringop); } } for (i = 0; i < instr_num_srcs(instr); i++){ opnd_disassemble_to_buffer(drcontext, instr_get_src(instr, i), stringop, MAX_STRING_LENGTH); if ((instr_get_opcode(instr) == OP_lea) && opnd_is_base_disp(instr_get_src(instr, i))){ dr_fprintf(data->outfile, "src-\n"); print_base_disp_for_lea(data->outfile, instr_get_src(instr, i)); } else{ dr_fprintf(data->outfile, "src-%d-%s\n", i, stringop); } } if (module_data != NULL){ dr_fprintf(data->outfile, "app_pc-%d\n", pc); } } else if (client_arg->instrace_mode == INS_DISASM_TRACE){ if (module_data != NULL){ if (md_get_module_position(instrace_head, module_data->full_path) == -1){ md_add_module(instrace_head, module_data->full_path, MAX_BBS_PER_MODULE); } dr_fprintf(data->outfile, "%d,%d,%s\n", md_get_module_position(instrace_head, module_data->full_path), pc, stringop); } else{ dr_fprintf(data->outfile, "%d,%d,%s\n",0, 0, stringop); } } dr_free_module_data(module_data); }
void clean_call_mem_information(instr_t * instr, app_pc mem_val, uint write){ void * drcontext = dr_get_current_drcontext(); module_data_t * data = dr_lookup_module(instr_get_app_pc(instr)); uint offset; app_pc base_pc; size_t size; uint prot; file_t dump_file; char * dump_filename; DR_ASSERT(data != NULL); offset = instr_get_app_pc(instr) - data->start; dr_mutex_lock(mutex); //if (!md_lookup_bb_in_module(done_head, data->full_path, offset)){ //md_add_bb_to_module(done_head, data->full_path, offset, MAX_BBS_PER_MODULE, false); dr_query_memory(mem_val, &base_pc, &size, &prot); //DEBUG_PRINT("base pc - %x, size - %u, write - %u\n", base_pc, size, write); if (write){ /* postpone till the end of the function */ if (!is_mem_region_present(write_regions, base_pc, size, write_region_size)){ DEBUG_PRINT("write registered - offset - %x memval %x\n", offset, mem_val); add_to_mem_region(write_regions, base_pc, size, &write_region_size); DEBUG_PRINT("base pc %x, size %d\n", base_pc, size); } } else{ if (!is_mem_region_present(read_regions, base_pc, size, read_region_size)){ add_to_mem_region(read_regions, base_pc, size, &read_region_size); //DEBUG_PRINT("size - %d\n", read_region_size); //DEBUG_PRINT("present - %d\n", is_mem_region_present(read_regions, base_pc, size, read_region_size)); //dr_abort(); DEBUG_PRINT("read registered - offset - %x memval %x\n", offset, mem_val); DEBUG_PRINT("base pc %x, size %d\n", base_pc, size); dump_filename = get_mem_dump_filename(base_pc, size, write,0); dump_file = dr_open_file(dump_filename, DR_FILE_WRITE_OVERWRITE); DEBUG_PRINT("%s dumping file\n", dump_filename); do_mem_dump(dump_file, base_pc, size); DEBUG_PRINT("file dumped\n"); dr_global_free(dump_filename, sizeof(char) * MAX_STRING_LENGTH); dr_close_file(dump_file); } } //} dr_mutex_unlock(mutex); dr_free_module_data(data); }
static dr_emit_flags_t bb_event(void* drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating) { instr_t *instr, *next_instr; int opcode; for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) { next_instr = instr_get_next(instr); opcode = instr_get_opcode(instr); if(instr_is_floating(instr)){ // dr_fprintf(logF, "Has seen FPU instruction with opcode %d\n",opcode); } else if(is_SIMD_packed(opcode)){ // dr_fprintf(logF, "Has seen SIMD packed instruction with opcode %d\n",opcode); } //AVX?rcpps? else if(is_SIMD_arithm(opcode)){ int is_single = 0; // printf("opcode is %d\n", opcode); // printf("number of sources %d\n", instr_num_srcs(instr)); // printf("number of dests %d\n", instr_num_dsts(instr)); //assert(number of sources = 2); opnd_t source1 = instr_get_src(instr,0); opnd_t source2 = instr_get_src(instr,1); opnd_t dest = instr_get_dst(instr,0); if(opnd_is_memory_reference(source1)){ // dr_print_instr(drcontext, logF, instr, "INSTR: "); // dr_print_opnd(drcontext, logF, source1, "OPND1: "); // dr_print_opnd(drcontext, logF, source2, "OPND2: "); reg_id_t rd = opnd_get_reg(source2); reg_id_t rs = opnd_get_reg_used(source1, 0); dr_insert_clean_call(drcontext, bb, instr, (void*) callback, true, 5, OPND_CREATE_INTPTR(rs), OPND_CREATE_INTPTR(opnd_get_disp(source1)), OPND_CREATE_INTPTR(rd), OPND_CREATE_INTPTR(opcode), OPND_CREATE_INTPTR(instr_get_app_pc(instr))); } else if(opnd_is_reg(source1) && opnd_is_reg(source2)){ reg_id_t reg1 = opnd_get_reg(source1); reg_id_t reg2 = opnd_get_reg(source2); dr_insert_clean_call(drcontext,bb,instr, (void*)getRegReg, true, 4, OPND_CREATE_INTPTR(reg1), OPND_CREATE_INTPTR(reg2) ,OPND_CREATE_INTPTR(opcode), OPND_CREATE_INTPTR(instr_get_app_pc(instr)) ); } else{ //should not be the case, throw an exception } fp_count++; } } return DR_EMIT_DEFAULT; }
/* We collect the basic block information including offset from module base, * size, and num of instructions, and add it into a basic block table without * instrumentation. */ static dr_emit_flags_t event_basic_block_analysis(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating, OUT void **user_data) { per_thread_t *data; instr_t *instr; app_pc tag_pc, start_pc, end_pc; /* do nothing for translation */ if (translating) return DR_EMIT_DEFAULT; data = (per_thread_t *)drmgr_get_tls_field(drcontext, tls_idx); /* Collect the number of instructions and the basic block size, * assuming the basic block does not have any elision on control * transfer instructions, which is true for default options passed * to DR but not for -opt_speed. */ /* We separate the tag from the instr pc ranges to handle displaced code * such as for the vsyscall hook. */ tag_pc = dr_fragment_app_pc(tag); start_pc = instr_get_app_pc(instrlist_first_app(bb)); end_pc = start_pc; /* for finding the size */ for (instr = instrlist_first_app(bb); instr != NULL; instr = instr_get_next_app(instr)) { app_pc pc = instr_get_app_pc(instr); int len = instr_length(drcontext, instr); /* -opt_speed (elision) is not supported */ /* For rep str expansion pc may be one back from start pc but equal to the tag. */ ASSERT(pc != NULL && (pc >= start_pc || pc == tag_pc), "-opt_speed is not supported"); if (pc + len > end_pc) end_pc = pc + len; } /* We allow duplicated basic blocks for the following reasons: * 1. Avoids handling issues like code cache consistency, e.g., * module load/unload, self-modifying code, etc. * 2. Avoids the overhead on duplication check. * 3. Stores more information on code cache events, e.g., trace building, * repeated bb building, etc. * 4. The duplication can be easily handled in a post-processing step, * which is required anyway. */ bb_table_entry_add(drcontext, data, tag_pc, (uint)(end_pc - start_pc)); if (go_native) return DR_EMIT_GO_NATIVE; else return DR_EMIT_DEFAULT; }
static dr_emit_flags_t event_app_analysis(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating, OUT void **user_data) { instr_t *inst, *label; bool prev_was_mov_const = false; ptr_int_t val1, val2; *user_data = NULL; /* Look for duplicate mov immediates telling us which subtest we're in */ for (inst = instrlist_first_app(bb); inst != NULL; inst = instr_get_next_app(inst)) { if (instr_is_mov_constant(inst, prev_was_mov_const ? &val2 : &val1)) { if (prev_was_mov_const && val1 == val2 && val1 != 0 && /* rule out xor w/ self */ opnd_is_reg(instr_get_dst(inst, 0)) && opnd_get_reg(instr_get_dst(inst, 0)) == TEST_REG) { *user_data = (void *) val1; label = INSTR_CREATE_label(drcontext); instr_set_translation(label, instr_get_app_pc(inst)); instrlist_meta_postinsert(bb, inst, label); } else prev_was_mov_const = true; } else prev_was_mov_const = false; } return DR_EMIT_DEFAULT; }
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; }
/* insert inline code to add an instruction entry into the buffer */ static void instrument_instr(void *drcontext, instrlist_t *ilist, instr_t *where) { /* We need two scratch registers */ reg_id_t reg_ptr, reg_tmp; /* we don't want to predicate this, because an instruction fetch always occurs */ instrlist_set_auto_predicate(ilist, DR_PRED_NONE); if (drreg_reserve_register(drcontext, ilist, where, NULL, ®_ptr) != DRREG_SUCCESS || drreg_reserve_register(drcontext, ilist, where, NULL, ®_tmp) != DRREG_SUCCESS) { DR_ASSERT(false); /* cannot recover */ return; } insert_load_buf_ptr(drcontext, ilist, where, reg_ptr); insert_save_type(drcontext, ilist, where, reg_ptr, reg_tmp, (ushort)instr_get_opcode(where)); insert_save_size(drcontext, ilist, where, reg_ptr, reg_tmp, (ushort)instr_length(drcontext, where)); insert_save_pc(drcontext, ilist, where, reg_ptr, reg_tmp, instr_get_app_pc(where)); insert_update_buf_ptr(drcontext, ilist, where, reg_ptr, sizeof(mem_ref_t)); /* Restore scratch registers */ if (drreg_unreserve_register(drcontext, ilist, where, reg_ptr) != DRREG_SUCCESS || drreg_unreserve_register(drcontext, ilist, where, reg_tmp) != DRREG_SUCCESS) DR_ASSERT(false); instrlist_set_auto_predicate(ilist, instr_get_predicate(where)); }
DR_EXPORT bool drx_aflags_are_dead(instr_t *where) { instr_t *instr; uint flags; for (instr = where; instr != NULL; instr = instr_get_next(instr)) { /* we treat syscall/interrupt as aflags read */ if (instr_is_syscall(instr) || instr_is_interrupt(instr)) return false; flags = instr_get_arith_flags(instr, DR_QUERY_DEFAULT); if (TESTANY(EFLAGS_READ_ARITH, flags)) return false; if (TESTALL(EFLAGS_WRITE_ARITH, flags)) return true; if (instr_is_cti(instr)) { if (instr_is_app(instr) && (instr_is_ubr(instr) || instr_is_call_direct(instr))) { instr_t *next = instr_get_next(instr); opnd_t tgt = instr_get_target(instr); /* continue on elision */ if (next != NULL && instr_is_app(next) && opnd_is_pc(tgt) && opnd_get_pc(tgt) == instr_get_app_pc(next)) continue; } /* unknown target, assume aflags is live */ return false; } } return false; }
/* event_bb_insert calls instrument_instr 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) { if (instr_get_app_pc(instr) == NULL || !instr_is_app(instr)) return DR_EMIT_DEFAULT; instrument_instr(drcontext, bb, instr); return DR_EMIT_DEFAULT; }
/* this is only called when the instrace mode is disassembly trace (this happens at the analysis time)*/ static void clean_call_disassembly_trace(){ char disassembly[SHORT_STRING_LENGTH]; per_thread_t * data = drmgr_get_tls_field(dr_get_current_drcontext(), tls_index); instr_trace_t * trace = (instr_trace_t *)data->buf_ptr; module_data_t * md; md = dr_lookup_module(instr_get_app_pc(trace->static_info_instr)); instr_disassemble_to_buffer(dr_get_current_drcontext(), trace->static_info_instr, disassembly, SHORT_STRING_LENGTH); dr_fprintf(data->outfile, "%s ", disassembly); if (md != NULL){ dr_fprintf(data->outfile, "%x", instr_get_app_pc(trace->static_info_instr) - md->start); dr_free_module_data(md); } dr_fprintf(data->outfile, "\n"); }
instr_t * instr_get_next_app_instr(instr_t *instr) { while (instr != NULL) { instr = instr_get_next(instr); if (instr_get_app_pc(instr) != NULL && !instr_is_meta_may_fault(instr)) return instr; } return NULL; }
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) { /* if find div, insert a clean call to our instrumentation routine */ opnd_t opnd; if (instr_is_div(instr, &opnd)) { dr_insert_clean_call(drcontext, bb, instr, (void *)callback, false /*no fp save*/, 2, OPND_CREATE_INTPTR(instr_get_app_pc(instr)), opnd); } return DR_EMIT_DEFAULT; }
dr_emit_flags_t funcwrap_bb_instrumentation(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr, bool for_trace, bool translating, void *user_data) { instr_t * first = instrlist_first(bb); app_pc pc = instr_get_app_pc(first); module_data_t * module_data; per_thread_t * data = drmgr_get_tls_field(dr_get_current_drcontext(), tls_index); module_t * md; app_pc offset; if (instr != first || data->nesting != 0){ return DR_EMIT_DEFAULT; } module_data = dr_lookup_module(pc); data = drmgr_get_tls_field(drcontext, tls_index); if (module_data != NULL){ md = md_lookup_module(head, module_data->full_path); if (md != NULL){ offset = pc - module_data->start; for (int i = 1; i <= md->bbs[0].start_addr; i++){ if (offset == md->bbs[i].start_addr){ DEBUG_PRINT("bb instrumenting function\n"); data->filter_func = true; dr_insert_clean_call(drcontext, bb, instr, clean_call, false, 1, OPND_CREATE_INTPTR(instr_get_app_pc(instr))); wrap_thread_id = dr_get_thread_id(drcontext); DEBUG_PRINT("done bb instrumenting function\n"); } } } } /*if (data->filter_func){ instrlist_disassemble(drcontext, instr_get_app_pc(instrlist_first(bb)), bb, logfile); }*/ dr_free_module_data(module_data); return DR_EMIT_DEFAULT; }
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) { /* if find div, insert a clean call to our instrumentation routine */ if (instr_get_opcode(instr) == OP_div) { dr_insert_clean_call(drcontext, bb, instr, (void *)callback, false /*no fp save*/, 2, OPND_CREATE_INTPTR(instr_get_app_pc(instr)), instr_get_src(instr, 0) /*divisor is 1st src*/); } return DR_EMIT_DEFAULT; }
void offline_instru_t::bb_analysis(void *drcontext, void *tag, void **bb_field, instrlist_t *ilist, bool repstr_expanded) { instr_t *instr; ptr_uint_t count = 0; app_pc last_xl8 = NULL; if (repstr_expanded) { // The same-translation check below is not sufficient as drutil uses // two different translations to deal with complexities. // Thus we hardcode this. count = 1; } else { for (instr = instrlist_first_app(ilist); instr != NULL; instr = instr_get_next_app(instr)) { // To deal with app2app changes, we do not double-count consecutive instrs // with the same translation. if (instr_get_app_pc(instr) != last_xl8) ++count; last_xl8 = instr_get_app_pc(instr); } } *bb_field = (void *)count; }
static dr_emit_flags_t drmgr_event_bb_insert(void *drcontext, void *tag, instrlist_t *bb, instr_t *inst, bool for_trace, bool translating, void *user_data) { if (instr_get_app_pc(inst) == addr_KiCallback) { dr_insert_clean_call(drcontext, bb, inst, (void *)drmgr_cls_stack_push, false, 0); } if (instr_get_opcode(inst) == OP_int && opnd_get_immed_int(instr_get_src(inst, 0)) == CBRET_INTERRUPT_NUM) { dr_insert_clean_call(drcontext, bb, inst, (void *)drmgr_cls_stack_pop, false, 0); } return DR_EMIT_DEFAULT; }
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 dr_emit_flags_t bb_event(void *drcontext, app_pc tag, instrlist_t *bb, bool for_trace, bool translating) { instr_t *instr, *next_instr; app_pc bb_addr, instr_addr; bool found_section; bb_addr = dr_fragment_app_pc(tag); /* vsyscall: some versions of windows jump to 0x7ffe0300 to * execute a syscall; this address is not contained in any module. */ if ((ptr_uint_t)bb_addr == 0x7ffe0300 || (ptr_uint_t)bb_addr == 0x7ffe0302) return DR_EMIT_DEFAULT; if (!is_in_known_module(bb_addr, &found_section, §ion)) { dr_fprintf(STDERR, "ERROR: BB addr "PFX" in unknown module\n", bb_addr); } if (!found_section) { dr_fprintf(STDERR, "ERROR: BB addr "PFX" isn't within a module section\n", bb_addr); } if ((section.Characteristics & IMAGE_SCN_CNT_CODE) == 0) { dr_fprintf(STDERR, "ERROR: BB addr "PFX" isn't within a code section\n", bb_addr); } for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) { next_instr = instr_get_next(instr); instr_addr = instr_get_app_pc(instr); if (!is_in_known_module(instr_addr, &found_section, §ion)) { dr_fprintf(STDERR, "ERROR: instr addr "PFX" in unknown module\n", instr_addr); } if (!found_section) { dr_fprintf(STDERR, "ERROR: instr addr "PFX" isn't within a module section\n", instr_addr); } if ((section.Characteristics & IMAGE_SCN_CNT_CODE) == 0) { dr_fprintf(STDERR, "ERROR: instr addr "PFX" isn't within a code section\n", instr_addr); } if (instr_addr == exit_proc_addr) { dr_fprintf(STDERR, "Hit kernel32!ExitProcess\n"); exit_proc_addr = NULL; } } return DR_EMIT_DEFAULT; }
static dr_emit_flags_t event_bb(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating) { app_pc pc = instr_get_app_pc(instrlist_first(bb)); if (pc == (app_pc)&func_0) took_over_thread[0] = true; if (pc == (app_pc)&func_1) took_over_thread[1] = true; if (pc == (app_pc)&func_2) took_over_thread[2] = true; if (pc == (app_pc)&func_3) took_over_thread[3] = true; if (pc == (app_pc)&func_4) took_over_thread[4] = true; if (pc == (app_pc)&func_5) took_over_thread[5] = true; if (pc == (app_pc)&func_6) took_over_thread[6] = true; if (pc == (app_pc)&func_7) took_over_thread[7] = true; if (pc == (app_pc)&func_8) took_over_thread[8] = true; if (pc == (app_pc)&func_9) took_over_thread[9] = true; return DR_EMIT_DEFAULT; }
static dr_emit_flags_t bb_event(void* drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating) { instr_t *instr; if (!translating) increment(tag); /* I'm looking for a specific BB in the test .exe. I've marked * it with a couple nops. */ #ifdef WINDOWS if ((app_pc)tag >= start && (app_pc)tag < end) { #endif instr = instrlist_first(bb); if (instr_is_nop(instr)) { instr_t *next = instr_get_next(instr); /* The test app uses two nops as a marker to identify a specific bb. Since * 2 nop instructions in a row aren't that uncommon on Linux (where we can't * restrict our search to just the test.exe module) we use an unusual nop * for the second one: xchg xbp, xbp */ if (next != NULL && instr_is_nop(next) && instr_get_opcode(next) == OP_xchg && instr_writes_to_exact_reg(next, REG_XBP, DR_QUERY_DEFAULT)) { bb_build_count++; if (delay_flush_at_next_build) { delay_flush_at_next_build = false; dr_delay_flush_region((app_pc)tag - 20, 30, callback_count, flush_event); } dr_insert_clean_call(drcontext, bb, instr, (void *)callback, false, 2, OPND_CREATE_INTPTR(tag), OPND_CREATE_INTPTR(instr_get_app_pc(instr))); } } #ifdef WINDOWS } #endif return DR_EMIT_DEFAULT; }
/* * Make a string representation of the address of an instruction, * including a function name and/or a file+line combination if * possible. These will be logged alongside every act of interest * where we can make one. */ static void instr_format_location(instr_t *instr, char **outloc) { app_pc addr = (app_pc)instr_get_app_pc(instr); char location[2048], symbol[512], fileline[1024]; bool got_sym = false, got_line = false; if (*outloc) return; symbol[0] = '\0'; fileline[0] = '\0'; module_data_t *data = dr_lookup_module(addr); if (data) { drsym_info_t sym; char file[MAXIMUM_PATH]; sym.struct_size = sizeof(sym); sym.name = symbol; sym.name_size = sizeof(symbol); sym.file = file; sym.file_size = sizeof(file); drsym_error_t status = drsym_lookup_address( data->full_path, addr - data->start, &sym, DRSYM_DEFAULT_FLAGS); got_line = (status == DRSYM_SUCCESS); got_sym = got_line || status == DRSYM_ERROR_LINE_NOT_AVAILABLE; if (got_line) snprintf(fileline, sizeof(fileline), " = %s:%"PRIu64, file, (uint64_t)sym.line); } snprintf(location, sizeof(location), "%"PRIx64"%s%s%s", (uint64_t)addr, got_sym ? " = " : "", got_sym ? symbol : "", fileline); size_t len = strlen(location) + 1; char *loc = dr_global_alloc(len); memcpy(loc, location, len); *outloc = loc; }
static dr_emit_flags_t bb_event(void* drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating) { instr_t *instr, *next_instr; int opcode; for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) { next_instr = instr_get_next(instr); opcode = instr_get_opcode(instr); /* if find div, insert a clean call to our instrumentation routine */ if (opcode == OP_div) { dr_insert_clean_call(drcontext, bb, instr, (void *)callback, false /*no fp save*/, 2, OPND_CREATE_INTPTR(instr_get_app_pc(instr)), instr_get_src(instr, 0) /*divisor is 1st src*/); } } return DR_EMIT_DEFAULT; }
/* this function to optimize some register stealing code away * for case like below: * * restore %reg * ... * save %reg * * if the %reg is not updated in between, the save %reg can be * optimized out */ static void optimize_register_stealing(void *drcontext, umbra_info_t *umbra_info, void *tag, instrlist_t *ilist) { instr_t *instr, *nexti; instr_t *reg_restore[NUM_SPILL_REGS]; reg_id_t regs[NUM_SPILL_REGS]; int i; /* skip reg eax */ for (i = 1; i < NUM_SPILL_REGS; i++) { reg_restore[i] = NULL; regs[i] = REG_SPILL_START + i; } for (instr = instrlist_first(ilist); instr != NULL; instr = nexti) { nexti = instr_get_next(instr); if (instr_get_app_pc(instr) != NULL && !instr_is_meta_may_fault(instr)) { /* check if app code update register */ for (i = 1; i < NUM_SPILL_REGS; i++) { if (register_is_updated(instr, regs[i])) reg_restore[i] = NULL; } } else { for (i = 1; i < NUM_SPILL_REGS; i++) { if (instr_is_reg_restore(instr, regs[i], umbra_info)) { reg_restore[i] = instr; break; } else if (instr_is_reg_save(instr, regs[i], umbra_info) && reg_restore[i] != NULL) { instrlist_remove(ilist, instr); instr_destroy(drcontext, instr); break; } } } } }
static void optimize_shadow_lookup(void *drcontext, umbra_info_t *umbra_info, void *tag, instrlist_t *ilist) { instr_t *instr, *nexti; ref_info_t ref_info[NUM_SPILL_REGS]; ref_info_init(ref_info); for (instr = instrlist_first(ilist); instr != NULL; instr = nexti) { if (instr_get_app_pc(instr) == NULL) { /* instrumented code */ nexti = analyze_client_code(drcontext, ilist, instr, ref_info); } else { /* application code */ nexti = analyze_app_code(drcontext, ilist, instr, ref_info); } } }
/** Returns code chunk of length up to _max_, corresponding to longest prefix of * instruction sequence. Changes _instr_ to instruction immediately following * prefix. */ struct chunk_info_t get_chunk_info(void* ctx, instr_t** instr, size_t max) { struct chunk_info_t chunk_info = { 0, 0 }; for(; *instr; *instr = instr_get_next(*instr)) { app_pc pc; size_t size; pc = dr_app_pc_for_decoding(instr_get_app_pc(*instr)); if(pc != chunk_info.pc + chunk_info.size) { if(chunk_info.pc == 0 && chunk_info.size == 0) { chunk_info.pc = pc; } else { break; } } size = chunk_info.size + instr_length(ctx, *instr); if(size > max) { break; } chunk_info.size = size; } return chunk_info; }
/* 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; }
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 void dynamic_info_instrumentation(void *drcontext, instrlist_t *ilist, instr_t *where, instr_t * static_info) { /* issues that may arise 1. pc and eflags is uint but in 64 bit mode 8 byte transfers are done -> so far no problem (need to see this) need to see whether there is a better way 2. double check all the printing */ /* this function does the acutal instrumentation arguments - we get a filled pointer here about the operand types for a given instruction (srcs and dests) 1) increment the pointer to the instr_trace buffers 2) add this pointer to instr_trace_t wrapper 3) check whether any of the srcs and dests have memory operations; if so add a lea instruction and get the dynamic address Add this address to instr_trace_t structure 4) if the buffer is full call a function to dump it to the file and restore the head ptr of the buffer (lean function is used utilizing a code cache to limit code bloat needed for a clean call before every instruction.) */ instr_t *instr, *call, *restore, *first, *second; opnd_t ref, opnd1, opnd2; reg_id_t reg1 = DR_REG_XBX; /* We can optimize it by picking dead reg */ reg_id_t reg2 = DR_REG_XCX; /* reg2 must be ECX or RCX for jecxz */ reg_id_t reg3 = DR_REG_XAX; per_thread_t *data; uint pc; uint i; module_data_t * module_data; if (client_arg->instrace_mode == DISASSEMBLY_TRACE){ dr_insert_clean_call(drcontext, ilist, where, clean_call_disassembly_trace, false, 0); return; } data = drmgr_get_tls_field(drcontext, tls_index); /* Steal the register for memory reference address * * We can optimize away the unnecessary register save and restore * by analyzing the code and finding the register is dead. */ dr_save_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2); dr_save_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3); dr_save_reg(drcontext, ilist, where, reg3, SPILL_SLOT_4); drmgr_insert_read_tls_field(drcontext, tls_index, ilist, where, reg2); /* Load data->buf_ptr into reg2 */ opnd1 = opnd_create_reg(reg2); opnd2 = OPND_CREATE_MEMPTR(reg2, offsetof(per_thread_t, buf_ptr)); instr = INSTR_CREATE_mov_ld(drcontext, opnd1, opnd2); instrlist_meta_preinsert(ilist, where, instr); /* buf_ptr->static_info_instr = static_info; */ /* Move static_info to static_info_instr field of buf (which is a instr_trace_t *) */ opnd1 = OPND_CREATE_MEMPTR(reg2, offsetof(instr_trace_t, static_info_instr)); instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)static_info, opnd1, ilist, where, &first, &second); /* buf_ptr->num_mem = 0; */ opnd1 = OPND_CREATE_MEMPTR(reg2, offsetof(instr_trace_t, num_mem)); instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)0, opnd1, ilist, where, &first, &second); for (i = 0; i<instr_num_dsts(where); i++){ if (opnd_is_memory_reference(instr_get_dst(where, i))){ ref = instr_get_dst(where, i); DR_ASSERT(opnd_is_null(ref) == false); dr_restore_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2); dr_restore_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3); #ifdef DEBUG_MEM_REGS dr_insert_clean_call(drcontext, ilist, where, clean_call_disassembly_trace, false, 0); dr_insert_clean_call(drcontext, ilist, where, clean_call_print_regvalues, false, 0); #endif drutil_insert_get_mem_addr(drcontext, ilist, where, ref, reg1, reg2); #ifdef DEBUG_MEM_REGS dr_insert_clean_call(drcontext, ilist, where, clean_call_print_regvalues, false, 0); #endif #ifdef DEBUG_MEM_STATS dr_insert_clean_call(drcontext, ilist, where, clean_call_disassembly_trace, false, 0); dr_insert_clean_call(drcontext, ilist, where, clean_call_mem_stats, false, 1, opnd_create_reg(reg1)); #endif dr_insert_clean_call(drcontext, ilist, where, clean_call_populate_mem, false, 3, opnd_create_reg(reg1), OPND_CREATE_INT32(i), OPND_CREATE_INT32(DST_TYPE)); } } for (i = 0; i<instr_num_srcs(where); i++){ if (opnd_is_memory_reference(instr_get_src(where, i))){ ref = instr_get_src(where, i); DR_ASSERT(opnd_is_null(ref) == false); dr_restore_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2); dr_restore_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3); #ifdef DEBUG_MEM_REGS dr_insert_clean_call(drcontext, ilist, where, clean_call_disassembly_trace, false, 0); dr_insert_clean_call(drcontext, ilist, where, clean_call_print_regvalues, false, 0); #endif drutil_insert_get_mem_addr(drcontext, ilist, where, ref, reg1, reg2); #ifdef DEBUG_MEM_REGS dr_insert_clean_call(drcontext, ilist, where, clean_call_print_regvalues, false, 0); #endif #ifdef DEBUG_MEM_STATS dr_insert_clean_call(drcontext, ilist, where, clean_call_disassembly_trace, false, 0); dr_insert_clean_call(drcontext, ilist, where, clean_call_mem_stats, false, 1, opnd_create_reg(reg1)); #endif dr_insert_clean_call(drcontext, ilist, where, clean_call_populate_mem, false, 3, opnd_create_reg(reg1), OPND_CREATE_INT32(i), OPND_CREATE_INT32(SRC_TYPE)); } } drmgr_insert_read_tls_field(drcontext, tls_index, ilist, where, reg2); /* Load data->buf_ptr into reg2 */ opnd1 = opnd_create_reg(reg2); opnd2 = OPND_CREATE_MEMPTR(reg2, offsetof(per_thread_t, buf_ptr)); instr = INSTR_CREATE_mov_ld(drcontext, opnd1, opnd2); instrlist_meta_preinsert(ilist, where, instr); /* arithmetic flags are saved here for buf_ptr->eflags filling */ dr_save_arith_flags_to_xax(drcontext, ilist, where); /* load the eflags */ opnd1 = OPND_CREATE_MEMPTR(reg2, offsetof(instr_trace_t, eflags)); opnd2 = opnd_create_reg(reg3); instr = INSTR_CREATE_mov_st(drcontext, opnd1, opnd2); instrlist_meta_preinsert(ilist, where, instr); /* load the app_pc */ opnd1 = OPND_CREATE_MEMPTR(reg2, offsetof(instr_trace_t, pc)); module_data = dr_lookup_module(instr_get_app_pc(where)); //dynamically generated code - module information not available - then just store 0 at the pc slot of the instr_trace data if (module_data != NULL){ pc = instr_get_app_pc(where) - module_data->start; dr_free_module_data(module_data); } else{ pc = 0; } instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)pc, opnd1, ilist, where, &first, &second); /* buf_ptr++; */ /* Increment reg value by pointer size using lea instr */ opnd1 = opnd_create_reg(reg2); opnd2 = opnd_create_base_disp(reg2, DR_REG_NULL, 0, sizeof(instr_trace_t), OPSZ_lea); instr = INSTR_CREATE_lea(drcontext, opnd1, opnd2); instrlist_meta_preinsert(ilist, where, instr); /* Update the data->buf_ptr */ drmgr_insert_read_tls_field(drcontext, tls_index, ilist, where, reg1); opnd1 = OPND_CREATE_MEMPTR(reg1, offsetof(per_thread_t, buf_ptr)); opnd2 = opnd_create_reg(reg2); instr = INSTR_CREATE_mov_st(drcontext, opnd1, opnd2); instrlist_meta_preinsert(ilist, where, instr); /* we use lea + jecxz trick for better performance * lea and jecxz won't disturb the eflags, so we won't insert * code to save and restore application's eflags. */ /* lea [reg2 - buf_end] => reg2 */ opnd1 = opnd_create_reg(reg1); opnd2 = OPND_CREATE_MEMPTR(reg1, offsetof(per_thread_t, buf_end)); instr = INSTR_CREATE_mov_ld(drcontext, opnd1, opnd2); instrlist_meta_preinsert(ilist, where, instr); opnd1 = opnd_create_reg(reg2); opnd2 = opnd_create_base_disp(reg1, reg2, 1, 0, OPSZ_lea); instr = INSTR_CREATE_lea(drcontext, opnd1, opnd2); instrlist_meta_preinsert(ilist, where, instr); /* jecxz call */ call = INSTR_CREATE_label(drcontext); opnd1 = opnd_create_instr(call); instr = INSTR_CREATE_jecxz(drcontext, opnd1); instrlist_meta_preinsert(ilist, where, instr); /* jump restore to skip clean call */ restore = INSTR_CREATE_label(drcontext); opnd1 = opnd_create_instr(restore); instr = INSTR_CREATE_jmp(drcontext, opnd1); instrlist_meta_preinsert(ilist, where, instr); /* clean call */ /* We jump to lean procedure which performs full context switch and * clean call invocation. This is to reduce the code cache size. */ instrlist_meta_preinsert(ilist, where, call); /* mov restore DR_REG_XCX */ opnd1 = opnd_create_reg(reg2); /* this is the return address for jumping back from lean procedure */ opnd2 = opnd_create_instr(restore); /* We could use instrlist_insert_mov_instr_addr(), but with a register * destination we know we can use a 64-bit immediate. */ instr = INSTR_CREATE_mov_imm(drcontext, opnd1, opnd2); instrlist_meta_preinsert(ilist, where, instr); /* jmp code_cache */ opnd1 = opnd_create_pc(code_cache); instr = INSTR_CREATE_jmp(drcontext, opnd1); instrlist_meta_preinsert(ilist, where, instr); /* restore %reg */ instrlist_meta_preinsert(ilist, where, restore); //dr_restore_arith_flags_from_xax(drcontext, ilist, where); dr_restore_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2); dr_restore_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3); dr_restore_reg(drcontext, ilist, where, reg3, SPILL_SLOT_4); //instrlist_disassemble(drcontext, instr_get_app_pc(instrlist_first(ilist)), ilist, logfile); }
static instr_t * analyze_client_code(void *drcontext, instrlist_t *ilist, instr_t *where, ref_info_t *ref_info) { instr_t *next, *lea, *and, *cmp, *jcc, *sub; opnd_t ref, opnd; ref_cache_t *cache; reg_id_t reg; int pos, i; next = instr_get_next(where); if (next == NULL) return NULL; if (instr_get_opcode(where) != OP_lea) return next; /* lea [ref] => r1 */ ref = instr_get_src(where, 0); if (!opnd_is_base_disp(ref) || opnd_get_index(ref) != DR_REG_NULL) return next; lea = where; and = next; cmp = instr_get_next(and); jcc = instr_get_next(cmp); if (instr_get_app_pc(and) == NULL && instr_get_opcode(and) == OP_and && instr_get_app_pc(cmp) == NULL && instr_get_opcode(cmp) == OP_cmp && instr_get_app_pc(jcc) == NULL && instr_get_opcode(jcc) == OP_jz) { /* find pattern of * lea [ref] => reg * and 0xffffffff00000000 reg * cmp cache->tag reg * jz */ opnd = instr_get_src(cmp, 1); cache = opnd_get_addr(opnd) - offsetof(ref_cache_t, tag); for (i = 0; i < 10; ) { lea = instr_get_next(lea); if (!instr_is_label(lea)) i++; } DR_ASSERT(instr_get_opcode(lea) == OP_lea); } else if (instr_get_app_pc(next) == NULL && instr_get_opcode(next) == OP_sub) { opnd = instr_get_src(next, 0); cache = opnd_get_addr(opnd) - offsetof(ref_cache_t, offset); } else { return next; } reg = opnd_get_base(ref); UMBRA_REG_TO_POS(reg, pos); if (ref_info[pos].cache == NULL) { ref_info[pos].cache = cache; } else { sub = instr_get_next(lea); DR_ASSERT(instr_get_opcode(sub) == OP_sub); while (lea != where) { next = instr_get_next(where); instrlist_remove(ilist, where); instr_destroy(drcontext, where); where = next; } opnd = OPND_CREATE_ABSMEM((void *)(reg_t)ref_info[pos].cache + offsetof(ref_cache_t, offset), OPSZ_PTR); instr_set_src(sub, 0, opnd); if (proc_info.client.app_unit_bits > 0 && proc_info.client.shd_unit_bits != 0) next = instr_get_next(sub); /* reg & mask => reg */ if (proc_info.client.orig_addr) { next = instr_get_next(next); /* mov reg => r2 */ next = instr_get_next(next); /* r2 & bit_mask => r2 */ } } next = instr_get_next(lea); return instr_get_next(next); }
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; }