DR_EXPORT void dr_client_main(client_id_t id, int argc, const char *argv[]) { module_data_t *appmod; dr_set_client_name("DynamoRIO Sample Client 'modxfer_app2lib'", "http://dynamorio.org/issues"); appmod = dr_get_main_module(); DR_ASSERT(appmod != NULL); app_base = appmod->start; app_end = appmod->end; dr_free_module_data(appmod); if (!drmgr_init()) DR_ASSERT(false); /* register events */ dr_register_exit_event(event_exit); if (!drmgr_register_bb_instrumentation_event(event_analyze_bb, event_insert_instrumentation, NULL)) DR_ASSERT(false); /* make it easy to tell, by looking at log file, which client executed */ dr_log(NULL, DR_LOG_ALL, 1, "Client 'modxfer_app2lib' initializing\n"); #ifdef SHOW_RESULTS /* also give notification to stderr */ if (dr_is_notify_on()) { # ifdef WINDOWS /* ask for best-effort printing to cmd window. must be called at init. */ dr_enable_console_printing(); # endif dr_fprintf(STDERR, "Client modxfer_app2lib is running\n"); } #endif }
DR_EXPORT void dr_init(client_id_t id) { /* Look up start_monitor() and stop_monitor() in the target app. * These functions are dummy markers that tell us when to start * and stop printing syscalls. */ /* NOTE - we could use dr_module_lookup_by_name, but we use the iterator instead * to test it out. */ dr_module_iterator_t *iter = dr_module_iterator_start(); while (dr_module_iterator_hasnext(iter)) { module_data_t *data = dr_module_iterator_next(iter); if (strcmp(dr_module_preferred_name(data), TEST_NAME) == 0) { module_handle_t lib = data->handle; start_pc = (app_pc)dr_get_proc_address(lib, "start_monitor"); stop_pc = (app_pc)dr_get_proc_address(lib, "stop_monitor"); } dr_free_module_data(data); } dr_module_iterator_stop(iter); if (start_pc == NULL || stop_pc == NULL) { dr_fprintf(STDERR, "ERROR: did not find start/stop markers\n"); } /* Register the BB hook */ dr_register_bb_event(bb_event); #ifdef LINUX /* With early injection, libc won't be loaded until later. */ dr_register_module_load_event(event_module_load); #endif }
static dr_signal_action_t signal_event_redirect(void *dcontext, dr_siginfo_t *info) { if (info->sig == SIGSEGV) { app_pc addr; module_data_t *data = dr_lookup_module_by_name("client."EVENTS); dr_fprintf(STDERR, "signal event redirect\n"); if (data == NULL) { dr_fprintf(STDERR, "couldn't find client."EVENTS" module\n"); return DR_SIGNAL_DELIVER; } addr = (app_pc)dr_get_proc_address(data->handle, "redirect"); dr_free_module_data(data); if (addr == NULL) { dr_fprintf(STDERR, "Couldn't find function redirect in client."EVENTS"\n"); return DR_SIGNAL_DELIVER; } #ifdef X64 /* align properly in case redirect function relies on conventions (i#384) */ info->mcontext->xsp = ALIGN_BACKWARD(info->mcontext->xsp, 16) - sizeof(void*); #endif info->mcontext->pc = addr; return DR_SIGNAL_REDIRECT; } return DR_SIGNAL_DELIVER; }
static bool exception_event_redirect(void *dcontext, dr_exception_t *excpt) { app_pc addr; dr_mcontext_t mcontext = {sizeof(mcontext),DR_MC_ALL,}; module_data_t *data = dr_lookup_module_by_name("client."EVENTS".exe"); dr_fprintf(STDERR, "exception event redirect\n"); if (data == NULL) { dr_fprintf(STDERR, "couldn't find "EVENTS".exe module\n"); return true; } addr = (app_pc)dr_get_proc_address(data->handle, "redirect"); dr_free_module_data(data); mcontext = *excpt->mcontext; mcontext.pc = addr; if (addr == NULL) { dr_fprintf(STDERR, "Couldn't find function redirect in "EVENTS".exe\n"); return true; } #ifdef X64 /* align properly in case redirect function relies on conventions (i#419) */ mcontext.xsp = ALIGN_BACKWARD(mcontext.xsp, 16) - sizeof(void*); #endif dr_redirect_execution(&mcontext); dr_fprintf(STDERR, "should not be reached, dr_redirect_execution() should not return\n"); return true; }
DR_EXPORT void dr_init(client_id_t id) { module_data_t *appmod = dr_get_main_module(); DR_ASSERT(appmod != NULL); app_base = appmod->start; app_end = appmod->end; dr_free_module_data(appmod); /* register events */ dr_register_exit_event(event_exit); dr_register_bb_event(event_basic_block); /* make it easy to tell, by looking at log file, which client executed */ dr_log(NULL, LOG_ALL, 1, "Client 'modxfer_app2lib' initializing\n"); #ifdef SHOW_RESULTS /* also give notification to stderr */ if (dr_is_notify_on()) { # ifdef WINDOWS /* ask for best-effort printing to cmd window. must be called in dr_init(). */ dr_enable_console_printing(); # endif dr_fprintf(STDERR, "Client modxfer_app2lib is running\n"); } #endif }
/* 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); }
static void print_address(app_pc addr, int bits, double loss, double lossD) { testarr[testcount] = lossD; testcount++; char key_string[KEY_MAX_LENGTH]; snprintf(key_string, KEY_MAX_LENGTH, "%s", "main");//sym->name); const char* prefix = "PRINT ADDRESS: "; drsym_error_t symres; drsym_info_t *sym; char sbuf[sizeof(*sym) + MAX_SYM_RESULT]; module_data_t *data; data = dr_lookup_module(addr); if (data == NULL) { // dr_fprintf(logF, "%s data is null "PFX" \n", prefix, addr); return; } snprintf(process_path, MAXIMUM_PATH,"%s",data->full_path); if(!callgrind_log_created){ writeCallgrind(thread_id_for_log); callgrind_log_created = true; } sym = (drsym_info_t *) sbuf; sym->struct_size = sizeof(*sym); sym->name_size = MAX_SYM_RESULT; symres = drsym_lookup_address(data->full_path, addr - data->start, sym, DRSYM_DEFAULT_FLAGS); /* if (symres == DRSYM_SUCCESS || symres == DRSYM_ERROR_LINE_NOT_AVAILABLE) { const char *modname = dr_module_preferred_name(data); if (modname == NULL) modname = "<noname>"; //dr_fprintf(logF, "%s "PFX" %s, function name is: %s, "PIFX", line off "PFX" \n", prefix, addr, //modname, sym->name, addr - data->start - sym->start_offs, sym->line_offs); //printf("test ins %d\n", testcount); //add check for line not available if (symres == DRSYM_ERROR_LINE_NOT_AVAILABLE) { // dr_fprintf(logF, "%s Line is not available\n", prefix); } else { // dr_fprintf(logF, "Line number is %s:%"UINT64_FORMAT_CODE" %d\n", // sym->file, sym->line, sym->line_offs); } } else // dr_fprintf(logF, "%s some error "PFX" \n", prefix, addr); */ dr_free_module_data(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 int get_sysnum(const char *wrapper) { byte *entry; module_data_t *data = dr_lookup_module_by_name("ntdll.dll"); ASSERT(data != NULL); entry = (byte *) dr_get_proc_address(data->handle, wrapper); dr_free_module_data(data); if (entry == NULL) return -1; return drmgr_decode_sysnum_from_wrapper(entry); }
static bool is_in_known_module(app_pc pc, bool *found_section, IMAGE_SECTION_HEADER *section) { bool found = false; module_data_t *data = dr_lookup_module(pc); if (data != NULL) { found = true; *found_section = dr_lookup_module_section(data->handle, pc, section); } dr_free_module_data(data); return found; }
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; }
app_pc get_ntdll_base(void) { static app_pc ntdll_base; /* cached value */ if (ntdll_base == NULL) { module_data_t *data = dr_lookup_module_by_name("ntdll.dll"); ASSERT(data != NULL, "cannot find ntdll.dll"); ntdll_base = data->start; dr_free_module_data(data); ASSERT(ntdll_base != NULL, "internal error finding ntdll.dll base"); } return ntdll_base; }
app_pc get_heap_start(void) { static app_pc heap_start; /* cached value */ if (heap_start == NULL) { app_pc cur_brk = get_brk(true/*pre-us*/); dr_mem_info_t info; module_data_t *data; /* Locate the heap */ if (!dr_query_memory_ex(cur_brk - 1, &info)) { ASSERT(false, "cannot find heap region"); return NULL; } if (info.type == DR_MEMTYPE_FREE || info.type == DR_MEMTYPE_IMAGE || !TEST(DR_MEMPROT_WRITE, info.prot)) { /* Heap is empty */ heap_start = cur_brk; } else { ASSERT(!dr_memory_is_dr_internal(info.base_pc), "heap location error"); /* we no longer assert that these are equal b/c -replace_malloc * has extended the brk already */ ASSERT(info.base_pc + info.size >= cur_brk, "heap location error"); heap_start = info.base_pc; /* workaround for PR 618178 where /proc/maps is wrong on suse * and lists last 2 pages of executable as heap! */ /* On some old Linux kernel, the heap might be right after the bss * segment. DR's map iterator used by dr_query_memory_ex cannot * split bss out of heap. * We use dr_lookup_module to find the right bounds of bss so that * we can check whether the base is bss, existing heap, or merge of * the two. */ /* XXX: we still cannot handle the case that the application creates * memory right before the heap. */ data = dr_lookup_module(info.base_pc); if (data != NULL) { if (data->start < heap_start && data->end > heap_start) { heap_start = (byte *) ALIGN_FORWARD(data->end, PAGE_SIZE); LOG(1, "WARNING: workaround for invalid heap_start "PFX" => "PFX"\n", info.base_pc, heap_start); } dr_free_module_data(data); } } } return heap_start; }
/* Lookup the module containing addr and see if we have a table entry for it */ static table_entry_t * get_entry_for_address(app_pc addr) { module_data_t *data = dr_lookup_module(addr); table_entry_t *entry = NULL; if (data != NULL) { entry = table; while (entry != NULL && _stricmp(dr_module_preferred_name(data), entry->value.module_name) != 0) { entry = entry->next; } dr_free_module_data(data); } return entry; }
static int get_write_sysnum(void) { #ifdef LINUX return SYS_write; #else byte *entry; module_data_t *data = dr_lookup_module_by_name("ntdll.dll"); DR_ASSERT(data != NULL); entry = (byte *) dr_get_proc_address(data->handle, "NtWriteFile"); DR_ASSERT(entry != NULL); dr_free_module_data(data); return drmgr_decode_sysnum_from_wrapper(entry); #endif }
DR_EXPORT void dr_init(client_id_t id) { module_data_t *data; dr_fprintf(STDERR, "thank you for testing the client interface\n"); dr_register_bb_event(bb_event); data = dr_lookup_module_by_name("kernel32.dll"); if (data != NULL) { exit_proc_addr = (void *)dr_get_proc_address(data->handle, "ExitProcess"); if (exit_proc_addr == NULL) dr_fprintf(STDERR, "ERROR: unable to find kernel32!ExitProcess\n"); dr_free_module_data(data); } else { dr_fprintf(STDERR, "ERROR: unable to find ntdll.dll\n"); } }
static bool drmgr_cls_init(void) { /* For callback init we watch for KiUserCallbackDispatcher. * For callback exit we watch for NtCallbackReturn or int 0x2b. */ static int cls_initialized; /* 0=not tried; >0=success; <0=failure */ module_data_t *data; module_handle_t ntdll_lib; app_pc addr_cbret; drmgr_priority_t priority = {sizeof(priority), "drmgr_cls", NULL, NULL, 0}; if (cls_initialized > 0) return true; else if (cls_initialized < 0) return false; cls_initialized = -1; if (!drmgr_register_bb_instrumentation_event(drmgr_event_bb_analysis, drmgr_event_bb_insert, &priority)) return false; dr_register_filter_syscall_event(drmgr_event_filter_syscall); data = dr_lookup_module_by_name("ntdll.dll"); if (data == NULL) { /* fatal error: something is really wrong w/ underlying DR */ return false; } ntdll_lib = data->handle; dr_free_module_data(data); addr_KiCallback = (app_pc) dr_get_proc_address(ntdll_lib, "KiUserCallbackDispatcher"); if (addr_KiCallback == NULL) return false; /* should not happen */ /* the wrapper is not good enough for two reasons: one, we want to swap * contexts at the last possible moment, not prior to executing a few * instrs; second, we'll miss hand-rolled syscalls */ addr_cbret = (app_pc) dr_get_proc_address(ntdll_lib, "NtCallbackReturn"); if (addr_cbret == NULL) return false; /* should not happen */ sysnum_NtCallbackReturn = drmgr_decode_sysnum_from_wrapper(addr_cbret); if (sysnum_NtCallbackReturn == -1) return false; /* should not happen */ cls_initialized = 1; return true; }
static int get_write_sysnum(void) { /* XXX: we could use the "drsyscall" Extension from the Dr. Memory Framework * (DRMF) to obtain the number of any system call from the name. */ #ifdef UNIX return SYS_write; #else byte *entry; module_data_t *data = dr_lookup_module_by_name("ntdll.dll"); DR_ASSERT(data != NULL); entry = (byte *) dr_get_proc_address(data->handle, "NtWriteFile"); DR_ASSERT(entry != NULL); dr_free_module_data(data); return drmgr_decode_sysnum_from_wrapper(entry); #endif }
static void memtrace(void *drcontext) { per_thread_t *data; int num_refs; mem_ref_t *mem_ref; #ifdef READABLE_TRACE int i; #endif module_data_t * mdata; data = drmgr_get_tls_field(drcontext, tls_index); mem_ref = (mem_ref_t *)data->buf_base; num_refs = (int)((mem_ref_t *)data->buf_ptr - mem_ref); #ifdef READABLE_TRACE /*dr_fprintf(data->log, "Format: <instr address>,<(r)ead/(w)rite>,<data size>,<data address>\n");*/ for (i = 0; i < num_refs; i++) { mdata = dr_lookup_module(mem_ref->pc); if (mdata != NULL){ if (((uint)mem_ref->addr > data->stack_base) || ((uint)mem_ref->addr < data->stack_limit)){ dr_fprintf(data->outfile, "%x,%x,%d,%d,"PFX"\n", mdata->start, mem_ref->pc - mdata->start , mem_ref->write ? 1 : 0 , mem_ref->size, mem_ref->addr); } dr_free_module_data(mdata); } ++mem_ref; } #else dr_write_file(data->log, data->buf_base, (size_t)(data->buf_ptr - data->buf_base)); #endif memset(data->buf_base, 0, MEM_BUF_SIZE); data->num_refs += num_refs; data->buf_ptr = data->buf_base; }
/* 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"); }
DR_EXPORT void dr_init(client_id_t id) { /* Look up start_instrument() and stop_instrument() in the app. * These functions are markers that tell us when to start and stop * instrumenting. */ module_data_t *prog = dr_lookup_module_by_name("client.cbr4.exe"); ASSERT(prog != NULL); start_pc = (app_pc)dr_get_proc_address(prog->handle, "start_instrument"); stop_pc = (app_pc)dr_get_proc_address(prog->handle, "stop_instrument"); ASSERT(start_pc != NULL && stop_pc != NULL); dr_free_module_data(prog); table = new_table(); dr_register_bb_event(bb_event); dr_register_exit_event(dr_exit); }
static dr_signal_action_t signal_event_redirect(void *dcontext, dr_siginfo_t *info) { if (info->sig == SIGSEGV) { app_pc addr; module_data_t *data = dr_lookup_module_by_name("client.events"); dr_fprintf(STDERR, "signal event redirect\n"); if (data == NULL) { dr_fprintf(STDERR, "couldn't find client.events module\n"); return DR_SIGNAL_DELIVER; } addr = (app_pc)dr_get_proc_address(data->handle, "redirect"); dr_free_module_data(data); if (addr == NULL) { dr_fprintf(STDERR, "Couldn't find function redirect in client.events\n"); return DR_SIGNAL_DELIVER; } info->mcontext->pc = addr; return DR_SIGNAL_REDIRECT; } return DR_SIGNAL_DELIVER; }
DR_EXPORT void dr_client_main(client_id_t id, int argc, const char *argv[]) { module_data_t *app; generic_func_t repeatme_addr; drmgr_init(); if (drfuzz_init(id) != DRMF_SUCCESS) EXPECT(false, "drfuzz failed to init"); dr_register_exit_event(exit_event); /* fuzz repeatme */ app = dr_get_main_module(); if (app == NULL) EXPECT(false, "failed to get application module"); repeatme_addr = dr_get_proc_address(app->handle, "repeatme"); if (repeatme_addr == NULL) EXPECT(false, "failed to find function repeatme"); if (drfuzz_fuzz_target(repeatme_addr, 1, 0, DRWRAP_CALLCONV_DEFAULT, pre_fuzz_cb, post_fuzz_cb) != DRMF_SUCCESS) EXPECT(false, "drfuzz failed to fuzz function repeatme"); dr_free_module_data(app); }
DR_EXPORT void dr_client_main(client_id_t id, int argc, const char *argv[]) { dr_set_client_name("DynamoRIO Sample Client 'inscount'", "http://dynamorio.org/issues"); /* Options */ if (!droption_parser_t::parse_argv(DROPTION_SCOPE_CLIENT, argc, argv, NULL, NULL)) DR_ASSERT(false); drmgr_init(); /* Get main module address */ if (only_from_app.get_value()) { module_data_t *exe = dr_get_main_module(); if (exe != NULL) exe_start = exe->start; dr_free_module_data(exe); } /* register events */ dr_register_exit_event(event_exit); drmgr_register_bb_instrumentation_event(event_bb_analysis, event_app_instruction, NULL); /* make it easy to tell, by looking at log file, which client executed */ dr_log(NULL, DR_LOG_ALL, 1, "Client 'inscount' initializing\n"); #ifdef SHOW_RESULTS /* also give notification to stderr */ if (dr_is_notify_on()) { # ifdef WINDOWS /* ask for best-effort printing to cmd window. must be called at init. */ dr_enable_console_printing(); # endif dr_fprintf(STDERR, "Client inscount is running\n"); } #endif }
static void print_address(file_t f, app_pc addr, const char *prefix) { drsym_error_t symres; drsym_info_t sym; char name[MAX_SYM_RESULT]; char file[MAXIMUM_PATH]; module_data_t *data; data = dr_lookup_module(addr); if (data == NULL) { dr_fprintf(f, "%s "PFX" ? ??:0\n", prefix, addr); return; } sym.struct_size = sizeof(sym); sym.name = name; sym.name_size = MAX_SYM_RESULT; sym.file = file; sym.file_size = MAXIMUM_PATH; symres = drsym_lookup_address(data->full_path, addr - data->start, &sym, DRSYM_DEFAULT_FLAGS); if (symres == DRSYM_SUCCESS || symres == DRSYM_ERROR_LINE_NOT_AVAILABLE) { const char *modname = dr_module_preferred_name(data); if (modname == NULL) modname = "<noname>"; dr_fprintf(f, "%s "PFX" %s!%s+"PIFX, prefix, addr, modname, sym.name, addr - data->start - sym.start_offs); if (symres == DRSYM_ERROR_LINE_NOT_AVAILABLE) { dr_fprintf(f, " ??:0\n"); } else { dr_fprintf(f, " %s:%"UINT64_FORMAT_CODE"+"PIFX"\n", sym.file, sym.line, sym.line_offs); } } else dr_fprintf(f, "%s "PFX" ? ??:0\n", prefix, addr); dr_free_module_data(data); }
static dr_emit_flags_t event_bb_analysis(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating, void **user_data) { instr_t *instr; uint num_instrs; #ifdef VERBOSE dr_printf("in dynamorio_basic_block(tag=" PFX ")\n", tag); # ifdef VERBOSE_VERBOSE instrlist_disassemble(drcontext, tag, bb, STDOUT); # endif #endif /* Only count in app BBs */ if (only_from_app.get_value()) { module_data_t *mod = dr_lookup_module(dr_fragment_app_pc(tag)); if (mod != NULL) { bool from_exe = (mod->start == exe_start); dr_free_module_data(mod); if (!from_exe) { *user_data = NULL; return DR_EMIT_DEFAULT; } } } /* Count instructions. If an emulation client is running with this client, * we want to count all the original native instructions and the emulated * instruction but NOT the introduced native instructions used for emulation. */ bool is_emulation = false; for (instr = instrlist_first(bb), num_instrs = 0; instr != NULL; instr = instr_get_next(instr)) { if (drmgr_is_emulation_start(instr)) { /* Each emulated instruction is replaced by a series of native * instructions delimited by labels indicating when the emulation * sequence begins and ends. It is the responsibility of the * emulation client to place the start/stop labels correctly. */ num_instrs++; is_emulation = true; /* Data about the emulated instruction can be extracted from the * start label using the accessor function: * drmgr_get_emulated_instr_data() */ continue; } if (drmgr_is_emulation_end(instr)) { is_emulation = false; continue; } if (is_emulation) continue; if (!instr_is_app(instr)) continue; num_instrs++; } *user_data = (void *)(ptr_uint_t)num_instrs; #if defined(VERBOSE) && defined(VERBOSE_VERBOSE) dr_printf("Finished counting for dynamorio_basic_block(tag=" PFX ")\n", tag); instrlist_disassemble(drcontext, tag, bb, STDOUT); #endif return DR_EMIT_DEFAULT; }
static void event_exit(void) { int i; char msg[512]; int len; int j; uint64 xmod_xfer = 0; uint64 self_xfer = 0; for (i = 0; i < num_mods; i++) { dr_fprintf(logfile, "module %3d: %s\n", i, dr_module_preferred_name(mod_array[i].info) == NULL ? "<unknown>" : dr_module_preferred_name(mod_array[i].info)); dr_fprintf(logfile, "%20llu instruction executed\n", mod_cnt[i]); } if (mod_cnt[UNKNOW_MODULE_IDX] != 0) { dr_fprintf(logfile, "unknown modules:\n%20llu instruction executed\n", mod_cnt[UNKNOW_MODULE_IDX]); } for (i = 0; i < MAX_NUM_MODULES; i++) { for (j = 0; j < num_mods; j++) { if (xfer_cnt[i][j] != 0) { dr_fprintf(logfile, "mod %3d => mod %3d: %8u\n", i, j, xfer_cnt[i][j]); if (i == j) self_xfer += xfer_cnt[i][j]; else xmod_xfer += xfer_cnt[i][j]; } } } len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "Instrumentation results:\n" "\t%10llu instructions executed\n" "\t%10llu (%2.3f%%) cross module indirect branches\n" "\t%10llu (%2.3f%%) intra-module indirect branches\n", ins_count, xmod_xfer, 100*(float)xmod_xfer/ins_count, self_xfer, 100*(float)self_xfer/ins_count); DR_ASSERT(len > 0); NULL_TERMINATE_BUFFER(msg); #ifdef SHOW_RESULTS DISPLAY_STRING(msg); #endif /* SHOW_RESULTS */ dr_fprintf(logfile, "%s\n", msg); dr_mutex_lock(mod_lock); for (i = 0; i < num_mods; i++) { DR_ASSERT(mod_array[i].info != NULL); dr_free_module_data(mod_array[i].info); } dr_mutex_unlock(mod_lock); dr_mutex_destroy(mod_lock); log_file_close(logfile); drx_exit(); if (!drmgr_unregister_bb_instrumentation_event(event_analyze_bb) || !drmgr_unregister_module_load_event(event_module_load) || !drmgr_unregister_module_unload_event(event_module_unload) || drreg_exit() != DRREG_SUCCESS) DR_ASSERT(false); drmgr_exit(); }
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 void module_table_entry_free(void *entry) { dr_free_module_data(((module_entry_t *)entry)->data); dr_global_free(entry, sizeof(module_entry_t)); }
DR_EXPORT drmf_status_t drsymcache_init(client_id_t client_id, const char *symcache_dir_in, size_t modsize_cache_threshold) { #ifdef WINDOWS module_data_t *mod; #endif drmf_status_t res; drmgr_priority_t pri_mod_load_cache = {sizeof(pri_mod_load_cache), DRMGR_PRIORITY_NAME_DRSYMCACHE, NULL, NULL, DRMGR_PRIORITY_MODLOAD_DRSYMCACHE_READ}; drmgr_priority_t pri_mod_unload_cache = {sizeof(pri_mod_unload_cache), DRMGR_PRIORITY_NAME_DRSYMCACHE, NULL, NULL, DRMGR_PRIORITY_MODUNLOAD_DRSYMCACHE}; drmgr_priority_t pri_mod_save_cache = {sizeof(pri_mod_save_cache), DRMGR_PRIORITY_NAME_DRSYMCACHE_SAVE, NULL, NULL, DRMGR_PRIORITY_MODLOAD_DRSYMCACHE_SAVE}; /* handle multiple sets of init/exit calls */ int count = dr_atomic_add32_return_sum(&symcache_init_count, 1); if (count > 1) return DRMF_WARNING_ALREADY_INITIALIZED; res = drmf_check_version(client_id); if (res != DRMF_SUCCESS) return res; drmgr_init(); drmgr_register_module_load_event_ex(symcache_module_load, &pri_mod_load_cache); drmgr_register_module_unload_event_ex(symcache_module_unload, &pri_mod_unload_cache); drmgr_register_module_load_event_ex(symcache_module_load_save, &pri_mod_save_cache); initialized = true; op_modsize_cache_threshold = modsize_cache_threshold; hashtable_init_ex(&symcache_table, SYMCACHE_MASTER_TABLE_HASH_BITS, IF_WINDOWS_ELSE(HASH_STRING_NOCASE, HASH_STRING), true/*strdup*/, false/*!synch*/, symcache_free_entry, NULL, NULL); symcache_lock = dr_mutex_create(); dr_snprintf(symcache_dir, BUFFER_SIZE_ELEMENTS(symcache_dir), "%s", symcache_dir_in); NULL_TERMINATE_BUFFER(symcache_dir); if (!dr_directory_exists(symcache_dir)) { if (!dr_create_dir(symcache_dir)) { /* check again in case of a race (i#616) */ if (!dr_directory_exists(symcache_dir)) { NOTIFY_ERROR("Unable to create symcache dir %s"NL, symcache_dir); ASSERT(false, "unable to create symcache dir"); dr_abort(); } } } #ifdef WINDOWS /* It's common for tools to query ntdll in their init routines so we add it * early here */ mod = dr_lookup_module_by_name("ntdll.dll"); if (mod != NULL) { symcache_module_load(dr_get_current_drcontext(), mod, true); dr_free_module_data(mod); } #endif return DRMF_SUCCESS; }