void inscount_init(client_id_t id, const char * name, const char * arguments) { file_t in_file; char logfilename[MAX_STRING_LENGTH]; drmgr_init(); global_count = 0; DR_ASSERT(parse_commandline_args(arguments) == true); head = md_initialize(); if(client_arg->filter_mode != FILTER_NONE){ in_file = dr_open_file(client_arg->filter_filename,DR_FILE_READ); DR_ASSERT(in_file != INVALID_FILE); md_read_from_file(head,in_file,false); dr_close_file(in_file); } if (log_mode){ populate_conv_filename(logfilename, logdir, name, NULL); logfile = dr_open_file(logfilename, DR_FILE_WRITE_OVERWRITE); } strncpy(ins_pass_name, name, MAX_STRING_LENGTH); }
/* callbacks for the entire process */ void funcwrap_init(client_id_t id, const char * name, const char * arguments) { file_t in_file; char logfilename[MAX_STRING_LENGTH]; drmgr_init(); drwrap_init(); tls_index = drmgr_register_tls_field(); DR_ASSERT(parse_commandline_args(arguments) == true); head = md_initialize(); if (!dr_file_exists(client_arg->filter_filename)){ file_registered = false; } /* we expect the filter file to be of the form for function filtering */ else{ file_registered = true; in_file = dr_open_file(client_arg->filter_filename, DR_FILE_READ); DR_ASSERT(in_file != INVALID_FILE); md_read_from_file(head, in_file, false); dr_close_file(in_file); } if (log_mode){ populate_conv_filename(logfilename, logdir, name, NULL); logfile = dr_open_file(logfilename, DR_FILE_WRITE_OVERWRITE); } strncpy(ins_pass_name, name, MAX_STRING_LENGTH); }
/* callbacks for the entire process */ void memdump_init(client_id_t id, const char * name, const char * arguments) { char logfilename[MAX_STRING_LENGTH]; file_t in_file; drmgr_init(); drutil_init(); drwrap_init(); tls_index = drmgr_register_tls_field(); DR_ASSERT(parse_commandline_args(arguments) == true); filter_head = md_initialize(); done_head = md_initialize(); app_pc_head = md_initialize(); in_file = dr_open_file(client_arg->filter_filename, DR_FILE_READ); md_read_from_file(filter_head, in_file, false); dr_close_file(in_file); in_file = dr_open_file(client_arg->app_pc_filename, DR_FILE_READ); md_read_from_file(app_pc_head, in_file, false); dr_close_file(in_file); if (log_mode){ populate_conv_filename(logfilename, logdir, name, NULL); logfile = dr_open_file(logfilename, DR_FILE_WRITE_OVERWRITE); } strncpy(ins_pass_name, name, MAX_STRING_LENGTH); mutex = dr_mutex_create(); }
void writeLog(void* drcontext){ char logname[MAXIMUM_PATH]; char *dirsep; int len; len = dr_snprintf(logname, sizeof(logname)/sizeof(logname[0]), "%s", dr_get_client_path(client_id)); DR_ASSERT(len > 0); for (dirsep = logname + len; *dirsep != '/'; dirsep--) DR_ASSERT(dirsep > logname); len = dr_snprintf(dirsep + 1, (sizeof(logname) - (dirsep - logname))/sizeof(logname[0]), "floatingpoint.%d.log", dr_get_thread_id(drcontext)); DR_ASSERT(len > 0); NULL_TERMINATE(logname); logF = dr_open_file(logname, DR_FILE_WRITE_OVERWRITE | DR_FILE_ALLOW_LARGE); DR_ASSERT(logF != INVALID_FILE); dr_log(drcontext, LOG_ALL, 1, "floating point: log for thread %d is fp.%03d\n", dr_get_thread_id(drcontext), dr_get_thread_id(drcontext)); #ifdef SHOW_RESULTS if (dr_is_notify_on()) { // dr_fprintf(STDERR, "<floating point instruction operands for thread %d in %s>\n", // dr_get_thread_id(drcontext), logname); } #endif thread_id_for_log = dr_get_thread_id(drcontext); }
static file_t open_sigil2_fifo(const char *path, int flags) { /* Wait for Sigil2 to create pipes * Timeout is empirical */ uint max_tests = 10; for(uint i=0; i<max_tests+1; ++i) { if(dr_file_exists(path)) break; if(i == max_tests) { dr_printf("%s\n", path); DR_ASSERT_MSG(false, "DrSigil timed out waiting for sigil2 fifos"); } struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 200000000L; nanosleep(&ts, NULL); } file_t f = dr_open_file(path, flags); if(f == INVALID_FILE) DR_ABORT_MSG("error opening empty fifo"); return f; }
DR_EXPORT void dr_init(client_id_t id) { dr_fprintf(STDERR, "info: starting dtrace, &dr_init=%p..\n", &dr_init); trace_file = dr_open_file(TRACE_FILE_NAME, DR_FILE_ALLOW_LARGE | DR_FILE_WRITE_OVERWRITE); if(trace_file == INVALID_FILE) { dr_fprintf(STDERR, "fatal: dr_open_file() failed\n"); dr_exit_process(1); } trace_file_lock = dr_mutex_create(); trace_buffer = tb_create(-1); trace_buffer_lock = dr_mutex_create(); hashtable_init_ex(&tags, 16, HASH_INTPTR, false, false, &tag_info_free_raw, NULL, NULL); tags_lock = dr_mutex_create(); dr_register_exit_event(&dr_exit); dr_register_thread_init_event(&handle_thread_init); dr_register_thread_exit_event(&handle_thread_exit); dr_register_bb_event(&handle_bb); dr_register_trace_event(&handle_trace); dr_register_delete_event(&handle_delete); dr_register_signal_event(&handle_signal); dr_register_restore_state_event(&handle_restore_state); }
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); }
void instrace_init(client_id_t id, const char * name, const char * arguments) { file_t in_file; file_t out_file; int i; char logfilename[MAX_STRING_LENGTH]; drmgr_init(); drutil_init(); client_id = id; DR_ASSERT(parse_commandline_args(arguments)==true); head = md_initialize(); instrace_head = md_initialize(); if(client_arg->filter_mode != FILTER_NONE){ in_file = dr_open_file(client_arg->filter_filename,DR_FILE_READ); DR_ASSERT(in_file != INVALID_FILE); md_read_from_file(head,in_file,false); dr_close_file(in_file); } mutex = dr_mutex_create(); tls_index = drmgr_register_tls_field(); DR_ASSERT(tls_index != -1); code_cache_init(); if (log_mode){ populate_conv_filename(logfilename, logdir, name, NULL); logfile = dr_open_file(logfilename, DR_FILE_WRITE_OVERWRITE); } strncpy(ins_pass_name, name, MAX_STRING_LENGTH); for(i=OP_FIRST;i<=OP_LAST; i++){ opcodes_visited[i] = false; } }
/* Library offset has to be computed before the probe library is loaded * into memory. Reading it from the map file is one of the easiest ways to * do it. */ unsigned int get_symbol_offset_from_map(const char *map_file, const char *symbol) { const char *pref_addr_str = "Preferred load address is "; unsigned int pref_base, sym_addr, offset = 0xdeadc0de; ssize_t file_sz; file_t fd = INVALID_FILE; char *buf, *temp; fd = dr_open_file(map_file, DR_FILE_READ); if (fd == INVALID_FILE) goto _get_module_offset_exit; /* This seems to be the easiest way to get the size of the file. */ if (!dr_file_seek(fd, 0, DR_SEEK_END)) goto _get_module_offset_exit; file_sz = (ssize_t) dr_file_tell(fd); if (file_sz <= 0) goto _get_module_offset_exit; if (!dr_file_seek(fd, 0, DR_SEEK_SET)) goto _get_module_offset_exit; /* Read the whole file. */ buf = dr_global_alloc(file_sz + 1); if (buf == NULL) goto _get_module_offset_exit; dr_read_file(fd, buf, file_sz); buf[file_sz] = '\0'; /* Locate preferred base & symbol address. */ temp = strstr(buf, pref_addr_str); if (temp != NULL) { pref_base = strtoul(temp + strlen(pref_addr_str), NULL, 16); temp = strstr(buf, symbol); if (temp != NULL) sym_addr = strtoul(temp + strlen(symbol), NULL, 16); offset = sym_addr - pref_base; } dr_global_free(buf, file_sz + 1); _get_module_offset_exit: if (fd != INVALID_FILE) dr_close_file(fd); return offset; }
static void read_table() { file_t file; bool read_entry = true; file = dr_open_file(table_def_file_name, DR_FILE_READ); if (file == INVALID_FILE) { DISPLAY_FUNC(NAME" error opening config file \"%s\"\n", table_def_file_name); return; } VVDISPLAY_FUNC(NAME" reading config file: \"%s\"\n", table_def_file_name); do { table_entry_t *entry = (table_entry_t *)dr_global_alloc(sizeof(table_entry_t)); if (dr_read_file(file, &entry->value, sizeof(table_value_t)) != sizeof(table_value_t)) { /* end of file */ read_entry = false; dr_global_free(entry, sizeof(table_entry_t)); } else { int i; /* insert NULL termination for module name (including space padding) */ for (i = sizeof(entry->value.module_name) - 1; i >= 0 && entry->value.module_name[i] == ' '; i--) { entry->value.module_name[i] = '\0'; } /* just in case */ entry->value.module_name[sizeof(entry->value.module_name)-1] = '\0'; /* add to the table */ entry->next = table; table = entry; VVDISPLAY_FUNC(NAME" read entry for module=\"%s\" to_stack=%s to_heap=%s " "transfer_to_here=%s\n", entry->value.module_name, (entry->value.allow_to_stack == 'y' || entry->value.allow_to_stack == 'Y') ? "yes" : "no", (entry->value.allow_to_heap == 'y' || entry->value.allow_to_heap == 'Y') ? "yes" : "no", (entry->value.allow_to_here == 'y' || entry->value.allow_to_here == 'Y') ? "yes" : "no"); } } while (read_entry); VVDISPLAY_FUNC(NAME" done reading config file."); }
int main(int argc, char *argv[]) { file_t f; void *drcontext = dr_standalone_init(); if (argc != 2) { dr_fprintf(STDERR, "Usage: %s <objfile>\n", argv[0]); return 1; } f = dr_open_file(argv[1], DR_FILE_READ | DR_FILE_ALLOW_LARGE); if (f == INVALID_FILE) { dr_fprintf(STDERR, "Error opening %s\n", argv[1]); return 1; } read_data(f, drcontext); dr_close_file(f); return 0; }
file_t umbra_open_proc_log(process_id_t pid) { char name[128]; int len; file_t logfile; /* XXX: Windows need a absolute path */ name[0] = '\0'; len = dr_snprintf(name, sizeof(name)/sizeof(name[0]), "umbra.%s.%d.proc.log", dr_get_application_name(), pid); DR_ASSERT(len > 0); name[sizeof(name)/sizeof(name[0])-1] = '\0'; logfile = dr_open_file(name, DR_FILE_READ | DR_FILE_WRITE_APPEND); DR_ASSERT(logfile != INVALID_FILE); return logfile; }
static void post_func_cb(void * wrapcxt, void ** user_data){ //do the dump for the written app_pcs int i = 0; file_t dump_file; char * dump_filename; DEBUG_PRINT("post function call for dumping\n"); /* if for same memdump it is overwritten */ for (i = 0; i < write_region_size; i++){ dump_filename = get_mem_dump_filename(write_regions[i].base_pc, write_regions[i].size, true, written_count); dump_file = dr_open_file(dump_filename, DR_FILE_WRITE_OVERWRITE); do_mem_dump(dump_file, write_regions[i].base_pc, write_regions[i].size); dr_global_free(dump_filename, sizeof(char) * MAX_STRING_LENGTH); dr_close_file(dump_file); } written_count++; }
/* * Wrap the log_set_file() function in testsc.c, and respond to it by * opening or closing log files. */ static void wrap_logsetfile(void *wrapctx, void **user_data) { if (outfile) { dr_close_file(outfile); outfile = INVALID_FILE; } const char *outfilename = drwrap_get_arg(wrapctx, 0); if (outfilename) { outfile = dr_open_file(outfilename, DR_FILE_WRITE_OVERWRITE); DR_ASSERT(outfile != INVALID_FILE); } /* * Reset the allocation list to empty, whenever we open or close a * log file. */ while (alloc_ends->next != alloc_ends) free_allocation(alloc_ends->next); next_alloc_index = 0; }
file_t umbra_open_thread_log(thread_id_t tid) { #ifdef LINUX_KERNEL return our_stdout; #else char name[128]; int len; file_t logfile; /* XXX: Windows need a absolute path */ name[0] = '\0'; len = dr_snprintf(name, sizeof(name)/sizeof(name[0]), "umbra.%s.%d.thread.log", dr_get_application_name(), tid); DR_ASSERT(len > 0); name[sizeof(name)/sizeof(name[0])-1] = '\0'; logfile = dr_open_file(name, DR_FILE_READ | DR_FILE_WRITE_APPEND); DR_ASSERT(logfile != INVALID_FILE); return logfile; #endif }
DR_EXPORT void dr_init( client_id_t id ) { dr_printf( "In dr_init()\n" ); // Initialize extensions. drsym_error_t rc = drsym_init( 0 ); if( DRSYM_SUCCESS != rc ) { dr_printf( "drsym_init() failed: %i\n", rc ); exit( 1 ); } bool wrapInit = drwrap_init(); if( !wrapInit ) { dr_printf( "drwrap_init() failed\n" ); exit( 1 ); } // Set up output. char fileName[256]; unsigned int pid = (unsigned int)dr_get_process_id(); dr_snprintf( fileName, sizeof( fileName ), "objcount-%u.out", pid ); fileName[sizeof( fileName ) - 1] = 0; outFile = dr_open_file( fileName, DR_FILE_WRITE_OVERWRITE ); outMutex = dr_mutex_create(); // Set up hashtable. hashtable_init_ex( &wraps, // table 16, // num_bits HASH_INTPTR, // hashtype false, // str_dup false, // synch &free_wrap, // free_payload_func NULL, // hash_key_func NULL ); // cmp_key_func // Register for events. dr_register_module_load_event( onLoad ); dr_register_exit_event( onExit ); }
/* callbacks for threads */ void funcwrap_thread_init(void *drcontext){ per_thread_t * data; char logfilename[MAX_STRING_LENGTH]; char thread_id[MAX_STRING_LENGTH]; DEBUG_PRINT("%s - initializing thread %d\n", ins_pass_name, dr_get_thread_id(drcontext)); data = dr_thread_alloc(drcontext, sizeof(per_thread_t)); if (log_mode){ dr_snprintf(thread_id, MAX_STRING_LENGTH, "%d", dr_get_thread_id(drcontext)); populate_conv_filename(logfilename, logdir, ins_pass_name, thread_id); data->logfile = dr_open_file(logfilename, DR_FILE_WRITE_OVERWRITE); } data->filter_func = false; data->nesting = 0; drmgr_set_tls_field(drcontext, tls_index, data); DEBUG_PRINT("%s - initializing thread done %d\n", ins_pass_name, dr_get_thread_id(drcontext)); }
void writeCallgrind(int thread_id){ char logname[MAXIMUM_PATH]; char *dirsep; int len; char * tmp = process_path; len = dr_snprintf(logname, sizeof(logname)/sizeof(logname[0]), "%s", tmp); DR_ASSERT(len > 0); for (dirsep = logname + len; *dirsep != '/'; dirsep--) DR_ASSERT(dirsep > logname); len = dr_snprintf(dirsep + 1, (sizeof(logname) - (dirsep - logname))/sizeof(logname[0]), "callgrind.%d.out", thread_id); DR_ASSERT(len > 0); NULL_TERMINATE(logname); logOut = dr_open_file(logname, DR_FILE_WRITE_OVERWRITE | DR_FILE_ALLOW_LARGE); DR_ASSERT(logOut != INVALID_FILE); // dr_log(drcontext, LOG_ALL, 1, // "floating point: log for thread %d is fp.%03d\n",thread_id, thread_id); #ifdef SHOW_RESULTS if (dr_is_notify_on()) { // dr_fprintf(STDERR, "<floating point instruction operands for thread %d in %s>\n", // dr_get_thread_id(drcontext), logname); } #endif dr_fprintf(logOut, "version: 1\n"); dr_fprintf(logOut, "creator: callgrind-3.6.1-Debian\n"); dr_fprintf(logOut, "positions: instr line\n"); dr_fprintf(logOut, "events: Average Max\n\n\n"); }
add_new_bb = bb_table_add(tables[entry->mod_id], entry) || add_new_bb; } free(tables); return add_new_bb; } static file_t open_input_file(const char *fname, char **map_out OUT, size_t *map_size OUT, uint64 *file_sz OUT) { uint64 file_size; char *map; file_t f; ASSERT(map_out != NULL && map_size != NULL, "map_out must not be NULL"); f = dr_open_file(fname, DR_FILE_READ | DR_FILE_ALLOW_LARGE); if (f == INVALID_FILE) { WARN(2, "Failed to open file %s\n", fname); return INVALID_FILE; } if (!dr_file_size(f, &file_size)) { WARN(2, "Failed to get input file size for %s\n", fname); dr_close_file(f); return INVALID_FILE; } if (file_size <= MIN_LOG_FILE_SIZE) { WARN(2, "File size is 0 for %s\n", fname); dr_close_file(f); return INVALID_FILE; } *map_size = (size_t)file_size;
void instrace_thread_init(void *drcontext) { char outfilename[MAX_STRING_LENGTH]; char logfilename[MAX_STRING_LENGTH]; char thread_id[MAX_STRING_LENGTH]; char extra_info[MAX_STRING_LENGTH]; char *dirsep; int len; per_thread_t *data; char * mode; uint * stack_base; uint * deallocation_stack; DEBUG_PRINT("%s - initializing thread %d\n", ins_pass_name, dr_get_thread_id(drcontext)); /* allocate thread private data */ data = dr_thread_alloc(drcontext, sizeof(per_thread_t)); drmgr_set_tls_field(drcontext, tls_index, data); data->buf_base = dr_thread_alloc(drcontext, INSTR_BUF_SIZE); data->buf_ptr = data->buf_base; /* set buf_end to be negative of address of buffer end for the lea later */ data->buf_end = -(ptr_int_t)(data->buf_base + INSTR_BUF_SIZE); data->num_refs = 0; /* We're going to dump our data to a per-thread file. * On Windows we need an absolute path so we place it in * the same directory as our library. We could also pass * in a path and retrieve with dr_get_options(). */ dr_snprintf(thread_id, MAX_STRING_LENGTH, "%d", dr_get_thread_id(drcontext)); if (log_mode){ populate_conv_filename(logfilename, logdir, ins_pass_name, thread_id); data->logfile = dr_open_file(logfilename, DR_FILE_WRITE_OVERWRITE | DR_FILE_ALLOW_LARGE); } /* instrace types */ if (client_arg->instrace_mode == OPERAND_TRACE){ mode = "opnd"; } else if (client_arg->instrace_mode == OPCODE_TRACE){ mode = "opcode"; } else if (client_arg->instrace_mode == DISASSEMBLY_TRACE){ mode = "disasm"; } else if (client_arg->instrace_mode == INS_DISASM_TRACE){ mode = "asm_instr"; } else{ mode = "instr"; } dr_snprintf(extra_info, MAX_STRING_LENGTH, "%s_%s_%s", client_arg->extra_info, mode, thread_id); populate_conv_filename(outfilename, client_arg->output_folder, ins_pass_name, extra_info); data->outfile = dr_open_file(outfilename, DR_FILE_WRITE_OVERWRITE | DR_FILE_ALLOW_LARGE); DR_ASSERT(data->outfile != INVALID_FILE); DEBUG_PRINT("%s - thread id : %d, new thread logging at - %s\n",ins_pass_name, dr_get_thread_id(drcontext),logfilename); data->static_array = (instr_t **)dr_thread_alloc(drcontext,sizeof(instr_t *)*client_arg->static_info_size); data->static_array_size = client_arg->static_info_size; data->static_ptr = 0; data->output_array = (output_t *)dr_thread_alloc(drcontext,OUTPUT_BUF_SIZE); deallocation_stack = &data->deallocation_stack; stack_base = &data->stack_base; __asm{ mov EAX, FS : [0x04] mov EBX, stack_base mov [EBX], EAX mov EAX, FS : [0xE0C] mov EBX, deallocation_stack mov [EBX], EAX } DEBUG_PRINT("%s - thread %d stack information - stack_base %x stack_reserve %x\n", ins_pass_name, dr_get_thread_id(drcontext), data->stack_base, data->deallocation_stack); DEBUG_PRINT("%s - initializing thread done %d\n", ins_pass_name, dr_get_thread_id(drcontext)); }
static bool symcache_read_symfile(const module_data_t *mod, const char *modname, mod_cache_t *modcache) { hashtable_t *symtable = &modcache->table; bool res = false; const char *line, *next_line; char symbol[MAX_SYMLEN]; size_t offs; uint64 map_size; size_t actual_size; bool ok; void *map = NULL; char symfile[MAXIMUM_PATH]; file_t f; symcache_get_filename(modname, symfile, BUFFER_SIZE_ELEMENTS(symfile)); f = dr_open_file(symfile, DR_FILE_READ); if (f == INVALID_FILE) return res; LOG(2, "processing symbol cache file for %s\n", modname); /* we avoid having to do our own buffering by just mapping the whole file */ ok = dr_file_size(f, &map_size); if (ok) { actual_size = (size_t) map_size; ASSERT(actual_size == map_size, "file size too large"); map = dr_map_file(f, &actual_size, 0, NULL, DR_MEMPROT_READ, 0); } if (!ok || map == NULL || actual_size < map_size) { NOTIFY_ERROR("Error mapping symcache file for %s"NL, modname); goto symcache_read_symfile_done; } if (strncmp((char *)map, SYMCACHE_FILE_HEADER, strlen(SYMCACHE_FILE_HEADER)) != 0) { WARN("WARNING: symbol cache file is corrupted\n"); goto symcache_read_symfile_done; } if (sscanf((char *)map + strlen(SYMCACHE_FILE_HEADER) + 1, "%d", &offs) != 1 || /* neither forward nor backward compatible */ offs != SYMCACHE_VERSION) { WARN("WARNING: symbol cache file has wrong version\n"); goto symcache_read_symfile_done; } line = strchr((char *) map, '\n'); if (line != NULL) line++; if (line != NULL) { /* Module consistency checks */ uint cache_file_size; uint64 module_file_size; #ifdef WINDOWS version_number_t file_version; version_number_t product_version; uint checksum; uint timestamp; size_t module_internal_size; if (sscanf(line, " %u,"UINT64_FORMAT_STRING","UINT64_FORMAT_STRING"," UINT64_FORMAT_STRING",%u,%u,%lu", &cache_file_size, &module_file_size, &file_version.version, &product_version.version, &checksum, ×tamp, &module_internal_size) != 7) { WARN("WARNING: %s symbol cache file has bad consistency header\n", modname); goto symcache_read_symfile_done; } if (module_file_size != modcache->module_file_size || file_version.version != modcache->file_version.version || product_version.version != modcache->product_version.version || checksum != modcache->checksum || timestamp != modcache->timestamp || module_internal_size != modcache->module_internal_size) { LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname); LOG(2, "\t"UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", " UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", " UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", " "%u vs %u, %u vs %u, %lu vs %lu\n", module_file_size, modcache->module_file_size, file_version.version, modcache->file_version.version, product_version.version, modcache->product_version.version, checksum, modcache->checksum, timestamp, modcache->timestamp, module_internal_size, modcache->module_internal_size); goto symcache_read_symfile_done; } #else if (sscanf(line, "%u,"UINT64_FORMAT_STRING, &cache_file_size, &module_file_size) != 2) { WARN("WARNING: %s symbol cache file has bad consistency header\n", modname); goto symcache_read_symfile_done; } if (module_file_size != modcache->module_file_size) { LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname); goto symcache_read_symfile_done; } #endif /* We could go further w/ CRC or even MD5 but not worth it for dev tool */ if (cache_file_size != (uint)map_size) { WARN("WARNING: %s symbol cache file is corrupted\n", modname); goto symcache_read_symfile_done; } } line = strchr(line, '\n'); if (line != NULL) line++; symbol[0] = '\0'; for (; line != NULL && line < ((char *)map) + map_size; line = next_line) { const char *newline = strchr(line, '\n'); if (newline == NULL) { next_line = ((char *)map) + map_size + 1; /* handle EOF w/o trailing \n */ } else { next_line = newline + 1; } if (sscanf(line, "%"MAX_SYMLEN_MINUS_1_STR"[^,],0x%x", symbol, &offs) == 2) { symcache_symbol_add(modname, symtable, symbol, offs); } else if (symbol[0] != '\0' && sscanf(line, ",0x%x", &offs) == 1) { /* duplicate entries are allowed to not list the symbol, to save * space in the file (mainly for post-call caching i#669) */ symcache_symbol_add(modname, symtable, symbol, offs); } else { WARN("WARNING: malformed symbol cache line \"%.*s\"\n", next_line - line - 1, line); /* We abort in case there were two dueling writes to the file * and it somehow got past the self-consistency check, * putting a header in the middle of the file, and we can't * trust subsequent lines since they may belong to a different * version of the module */ break; /* res should still be true */ } } res = true; symcache_read_symfile_done: if (map != NULL) dr_unmap_file(map, actual_size); if (f != INVALID_FILE) dr_close_file(f); return res; }
DR_EXPORT void dr_init(client_id_t id) { char buf[MAXIMUM_PATH]; int64 pos; int i; uint prot; byte *base_pc; size_t size; size_t bytes_read, bytes_written; byte *edge, *mbuf; bool ok; byte *f_map; /* The Makefile will pass a full absolute path (for Windows and Linux) as the client * option to a dummy file in the which we use to exercise the file api routines. * TODO - these tests should be a lot more thorough, but the basic functionality * is there (should add write tests, file_exists, directory etc. tests). */ file = dr_open_file(dr_get_options(id), DR_FILE_READ); if (file == INVALID_FILE) dr_fprintf(STDERR, "Error opening file\n"); memset(buf, 0, sizeof(buf)); dr_read_file(file, buf, 10); pos = dr_file_tell(file); if (pos < 0) dr_fprintf(STDERR, "tell error\n"); dr_fprintf(STDERR, "%s\n", buf); if (!dr_file_seek(file, 0, DR_SEEK_SET)) dr_fprintf(STDERR, "seek error\n"); memset(buf, 0, sizeof(buf)); dr_read_file(file, buf, 5); dr_fprintf(STDERR, "%s\n", buf); for (i = 0; i < 100; i++) buf[i] = 0; if (!dr_file_seek(file, pos - 5, DR_SEEK_CUR)) dr_fprintf(STDERR, "seek error\n"); memset(buf, 0, sizeof(buf)); dr_read_file(file, buf, 7); dr_fprintf(STDERR, "%s\n", buf); if (!dr_file_seek(file, -6, DR_SEEK_END)) dr_fprintf(STDERR, "seek error\n"); memset(buf, 0, sizeof(buf)); /* read "x\nEOF\n" from the data file */ dr_read_file(file, buf, 6); /* check for DOS line ending */ if (buf[4] == '\r') { /* Account for two line endings: the snippet is "x\r\nEOF\r\n". * No conversion required--ctest will discard the '\r' when comparing results. */ if (!dr_file_seek(file, -8, DR_SEEK_END)) dr_fprintf(STDERR, "seek error\n"); memset(buf, 0, sizeof(buf)); dr_read_file(file, buf, 8); } dr_fprintf(STDERR, "%s\n", buf); #define EXTRA_SIZE 0x60 size = PAGE_SIZE + EXTRA_SIZE; f_map = dr_map_file(file, &size, 0, NULL, DR_MEMPROT_READ, DR_MAP_PRIVATE); if (f_map == NULL || size < (PAGE_SIZE + EXTRA_SIZE)) dr_fprintf(STDERR, "map error\n"); /* test unaligned unmap */ if (!dr_unmap_file(f_map + PAGE_SIZE, EXTRA_SIZE)) dr_fprintf(STDERR, "unmap error\n"); /* leave file open and check in exit event that it's still open after * app tries to close it */ dr_register_exit_event(event_exit); /* Test dr_rename_file. */ test_dr_rename_delete(); /* Test the memory query routines */ dummy_func(); if (!dr_memory_is_readable((byte *)dummy_func, 1) || !dr_memory_is_readable(read_only_buf+1000, 4000) || !dr_memory_is_readable(writable_buf+1000, 4000)) { dr_fprintf(STDERR, "ERROR : dr_memory_is_readable() incorrect results\n"); } if (!dr_query_memory((byte *)dummy_func, &base_pc, &size, &prot)) dr_fprintf(STDERR, "ERROR : can't find dummy_func mem region\n"); dr_fprintf(STDERR, "dummy_func is %s%s%s\n", TEST(DR_MEMPROT_READ, prot) ? "r" : "", TEST(DR_MEMPROT_WRITE, prot) ? "w" : "", TEST(DR_MEMPROT_EXEC, prot) ? "x" : ""); if (base_pc > (byte *)dummy_func || base_pc + size < (byte *)dummy_func) dr_fprintf(STDERR, "dummy_func region mismatch"); memset(writable_buf, 0, sizeof(writable_buf)); /* strip off write copy */ if (!dr_query_memory(writable_buf+100, &base_pc, &size, &prot)) dr_fprintf(STDERR, "ERROR : can't find dummy_func mem region\n"); dr_fprintf(STDERR, "writable_buf is %s%s%s\n", TEST(DR_MEMPROT_READ, prot) ? "r" : "", TEST(DR_MEMPROT_WRITE, prot) ? "w" : "", #ifdef UNIX /* Linux sometimes (probably depends on version and hardware NX * support) lists all readable regions as also exectuable in the * maps file. We just skip checking here for Linux to make * matching the template file easier. */ "" #else TEST(DR_MEMPROT_EXEC, prot) ? "x" : "" #endif ); if (base_pc > writable_buf || base_pc + size < writable_buf) dr_fprintf(STDERR, "writable_buf region mismatch\n"); if (base_pc + size < writable_buf + sizeof(writable_buf)) dr_fprintf(STDERR, "writable_buf size mismatch "PFX" "PFX" "PFX" "PFX"\n", base_pc, size, writable_buf, sizeof(writable_buf)); if (!dr_query_memory(read_only_buf+100, &base_pc, &size, &prot)) dr_fprintf(STDERR, "ERROR : can't find dummy_func mem region\n"); dr_fprintf(STDERR, "read_only_buf is %s%s\n", TEST(DR_MEMPROT_READ, prot) ? "r" : "", TEST(DR_MEMPROT_WRITE, prot) ? "w" : ""); if (base_pc > read_only_buf || base_pc + size < read_only_buf) dr_fprintf(STDERR, "read_only_buf region mismatch"); if (base_pc + size < read_only_buf + sizeof(read_only_buf)) dr_fprintf(STDERR, "read_only_buf size mismatch"); /* test the safe_read functions */ /* TODO - extend test to cover racy writes and reads (won't work on Linux yet). */ memset(safe_buf, 0xcd, sizeof(safe_buf)); if (!dr_safe_read(read_only_buf + 4000, 1000, safe_buf, &bytes_read) || bytes_read != 1000 || !memchk(safe_buf, 0, 1000) || *(safe_buf+1000) != 0xcd) { dr_fprintf(STDERR, "ERROR in plain dr_safe_read()\n"); } memset(safe_buf, 0xcd, sizeof(safe_buf)); /* read_only_buf will be in .rodata on Linux, and can be followed by string * constants with the same page protections. In order to be sure that we're * copying zeroes, we map our own memory. */ mbuf = dr_nonheap_alloc(PAGE_SIZE*3, DR_MEMPROT_READ|DR_MEMPROT_WRITE); memset(mbuf, 0, PAGE_SIZE*3); dr_memory_protect(mbuf + PAGE_SIZE*2, PAGE_SIZE, DR_MEMPROT_NONE); edge = find_prot_edge(mbuf, DR_MEMPROT_READ); bytes_read = 0xcdcdcdcd; if (dr_safe_read(edge - (PAGE_SIZE + 10), PAGE_SIZE+20, safe_buf, &bytes_read) || bytes_read == 0xcdcdcdcd || bytes_read > PAGE_SIZE+10 || !memchk(safe_buf, 0, bytes_read)) { dr_fprintf(STDERR, "ERROR in overlap dr_safe_read()\n"); } dr_nonheap_free(mbuf, PAGE_SIZE*3); dr_fprintf(STDERR, "dr_safe_read() check\n"); /* test DR_TRY_EXCEPT */ DR_TRY_EXCEPT(dr_get_current_drcontext(), { ok = false; *((int *)4) = 37; }, { /* EXCEPT */
void memtrace_thread_init(void *drcontext) { char logfilename[MAX_STRING_LENGTH]; char outfilename[MAX_STRING_LENGTH]; char thread_id[MAX_STRING_LENGTH]; char extra_info[MAX_STRING_LENGTH]; char *dirsep; int len; per_thread_t *data; uint * stack_base; uint * deallocation_stack; int i = 0; DEBUG_PRINT("%s - initializing thread %d\n", ins_pass_name, dr_get_thread_id(drcontext)); /* allocate thread private data */ data = dr_thread_alloc(drcontext, sizeof(per_thread_t)); drmgr_set_tls_field(drcontext, tls_index, data); data->buf_base = dr_thread_alloc(drcontext, MEM_BUF_SIZE); data->buf_ptr = data->buf_base; /* set buf_end to be negative of address of buffer end for the lea later */ data->buf_end = -(ptr_int_t)(data->buf_base + MEM_BUF_SIZE); data->num_refs = 0; /* We're going to dump our data to a per-thread file. * On Windows we need an absolute path so we place it in * the same directory as our library. We could also pass * in a path and retrieve with dr_get_options(). */ dr_snprintf(thread_id, MAX_STRING_LENGTH, "%d", dr_get_thread_id(drcontext)); if (log_mode){ populate_conv_filename(logfilename, logdir, ins_pass_name, thread_id); data->logfile = dr_open_file(logfilename, DR_FILE_WRITE_OVERWRITE | DR_FILE_ALLOW_LARGE); } dr_snprintf(extra_info, MAX_STRING_LENGTH, "%s_%s", client_arg->extra_info, thread_id); populate_conv_filename(outfilename, client_arg->output_folder, ins_pass_name, extra_info); data->outfile = dr_open_file(outfilename, DR_FILE_WRITE_OVERWRITE | DR_FILE_ALLOW_LARGE); DR_ASSERT(data->outfile != INVALID_FILE); /* this is done for 32 bit applications */ deallocation_stack = &data->stack_limit; stack_base = &data->stack_base; __asm{ mov EAX, FS : [0x04] mov EBX, stack_base mov[EBX], EAX mov EAX, FS : [0xE0C] mov EBX, deallocation_stack mov[EBX], EAX } DEBUG_PRINT("%s - stack boundaries - %x,%x\n", ins_pass_name, data->stack_base, data->stack_limit); DEBUG_PRINT("%s - initializing thread done %d\n", ins_pass_name, dr_get_thread_id(drcontext)); }
/* Sets modcache->has_debug_info. * No lock is needed as we assume the caller hasn't exposed modcache outside this * thread yet. */ static bool symcache_read_symfile(const module_data_t *mod, const char *modname, mod_cache_t *modcache) { hashtable_t *symtable = &modcache->table; bool res = false; const char *line, *next_line; char symbol[MAX_SYMLEN]; size_t offs; uint64 map_size; size_t actual_size; bool ok; void *map = NULL; char symfile[MAXIMUM_PATH]; file_t f; symcache_get_filename(modname, symfile, BUFFER_SIZE_ELEMENTS(symfile)); f = dr_open_file(symfile, DR_FILE_READ); if (f == INVALID_FILE) goto symcache_read_symfile_done; LOG(2, "processing symbol cache file for %s\n", modname); /* we avoid having to do our own buffering by just mapping the whole file */ ok = dr_file_size(f, &map_size); if (ok) { actual_size = (size_t) map_size; ASSERT(actual_size == map_size, "file size too large"); map = dr_map_file(f, &actual_size, 0, NULL, DR_MEMPROT_READ, 0); } if (!ok || map == NULL || actual_size < map_size) { NOTIFY_ERROR("Error mapping symcache file for %s"NL, modname); goto symcache_read_symfile_done; } if (strncmp((char *)map, SYMCACHE_FILE_HEADER, strlen(SYMCACHE_FILE_HEADER)) != 0) { WARN("WARNING: symbol cache file is corrupted\n"); goto symcache_read_symfile_done; } /* i#1057: We use dr_sscanf() because sscanf() from ntdll will call strlen() * and read off the end of the mapped file if it doesn't hit a null. */ if (dr_sscanf((char *)map + strlen(SYMCACHE_FILE_HEADER) + 1, "%d", (uint *)&offs) != 1 || /* neither forward nor backward compatible */ offs != SYMCACHE_VERSION) { WARN("WARNING: symbol cache file has wrong version\n"); goto symcache_read_symfile_done; } line = strchr((char *) map, '\n'); if (line != NULL) line++; if (line != NULL) { /* Module consistency checks */ uint cache_file_size; uint64 module_file_size; uint timestamp; #ifdef WINDOWS version_number_t file_version; version_number_t product_version; uint checksum; size_t module_internal_size; if (dr_sscanf(line, "%u,"UINT64_FORMAT_STRING","UINT64_FORMAT_STRING"," UINT64_FORMAT_STRING",%u,%u,%lu", &cache_file_size, &module_file_size, &file_version.version, &product_version.version, &checksum, ×tamp, &module_internal_size) != 7) { WARN("WARNING: %s symbol cache file has bad consistency header\n", modname); goto symcache_read_symfile_done; } if (module_file_size != modcache->module_file_size || file_version.version != modcache->file_version.version || product_version.version != modcache->product_version.version || checksum != modcache->checksum || timestamp != modcache->timestamp || module_internal_size != modcache->module_internal_size) { LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname); LOG(2, "\t"UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", " UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", " UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", " "%u vs %u, %u vs %u, %lu vs %lu\n", module_file_size, modcache->module_file_size, file_version.version, modcache->file_version.version, product_version.version, modcache->product_version.version, checksum, modcache->checksum, timestamp, modcache->timestamp, module_internal_size, modcache->module_internal_size); goto symcache_read_symfile_done; } #elif defined(LINUX) if (dr_sscanf(line, "%u,"UINT64_FORMAT_STRING",%u", &cache_file_size, &module_file_size, ×tamp) != 3) { WARN("WARNING: %s symbol cache file has bad consistency header\n", modname); goto symcache_read_symfile_done; } if (module_file_size != modcache->module_file_size || timestamp != modcache->timestamp) { LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname); goto symcache_read_symfile_done; } #elif defined(MACOS) uint current_version; uint compatibility_version; byte uuid[16]; /* XXX: if dr_sscanf supported %n maybe we could split these into * separate scans on the same string and share code w/ Linux. */ if (dr_sscanf(line, "%u,"UINT64_FORMAT_STRING",%u,%u,%u,%x,%x,%x,%x", &cache_file_size, &module_file_size, ×tamp, ¤t_version, &compatibility_version, (uint*)(&uuid[0]), (uint*)(&uuid[4]), (uint*)(&uuid[8]), (uint*)(&uuid[12])) != 9) { WARN("WARNING: %s symbol cache file has bad consistency header B\n", modname); goto symcache_read_symfile_done; } if (current_version != modcache->current_version || compatibility_version != modcache->compatibility_version || memcmp(uuid, modcache->uuid, sizeof(uuid)) != 0) { LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname); goto symcache_read_symfile_done; } #endif /* We could go further w/ CRC or even MD5 but not worth it for dev tool */ if (cache_file_size != (uint)map_size) { WARN("WARNING: %s symbol cache file is corrupted: map=%d vs file=%d\n", modname, (uint)map_size, cache_file_size); goto symcache_read_symfile_done; } } line = strchr(line, '\n'); if (line != NULL) line++; if (line != NULL) { uint has_debug_info; if (dr_sscanf(line, "%u", &has_debug_info) != 1) { WARN("WARNING: %s symbol cache file has bad consistency header\n", modname); goto symcache_read_symfile_done; } if (has_debug_info) { /* We assume that the current availability of debug info doesn't matter */ modcache->has_debug_info = true; } else { /* We delay the costly check for symbols until we've read the symcache * b/c if its entry indicates symbols we don't need to look */ if (module_has_symbols(mod)) { LOG(1, "module now has debug info: %s symbol cache is stale\n", modname); goto symcache_read_symfile_done; } } } line = strchr(line, '\n'); if (line != NULL) line++; symbol[0] = '\0'; for (; line != NULL && line < ((char *)map) + map_size; line = next_line) { const char *comma = strchr(line, ','); const char *newline = strchr(line, '\n'); size_t symlen = (comma != NULL ? comma - line : 0); if (newline == NULL) { next_line = ((char *)map) + map_size + 1; /* handle EOF w/o trailing \n */ } else { next_line = newline + 1; } if (symlen > 0 && symlen < MAX_SYMLEN) { strncpy(symbol, line, symlen); symbol[symlen] = '\0'; } if (comma != NULL && symlen < MAX_SYMLEN && symbol[0] != '\0' && dr_sscanf(comma, ",0x%x", (uint *)&offs) == 1) { #ifdef WINDOWS /* Guard against corrupted files that cause DrMem to crash (i#1465) */ if (offs >= modcache->module_internal_size) { /* This one we want to know about */ NOTIFY("SYMCACHE ERROR: %s file has too-large entry "PIFX" for %s"NL, modname, offs, symbol); goto symcache_read_symfile_done; } #endif symcache_symbol_add(modname, symtable, symbol, offs); } else { WARN("WARNING: malformed symbol cache line \"%.*s\"\n", next_line - line - 1, line); /* We abort in case there were two dueling writes to the file * and it somehow got past the self-consistency check, * putting a header in the middle of the file, and we can't * trust subsequent lines since they may belong to a different * version of the module */ break; /* res should still be true */ } } res = true; symcache_read_symfile_done: if (map != NULL) dr_unmap_file(map, actual_size); if (f != INVALID_FILE) dr_close_file(f); if (!res) modcache->has_debug_info = module_has_symbols(mod); return res; }
/* caller must hold symcache_lock */ static void symcache_write_symfile(const char *modname, mod_cache_t *modcache) { uint i; file_t f; hashtable_t *symtable = &modcache->table; char buf[SYMCACHE_BUFFER_SIZE]; size_t sofar = 0; ssize_t len; size_t bsz = BUFFER_SIZE_ELEMENTS(buf); size_t filesz_loc; char symfile[MAXIMUM_PATH]; char symfile_tmp[MAXIMUM_PATH]; int64 file_size; ASSERT(dr_mutex_self_owns(symcache_lock), "missing symcache lock"); /* if from file, we assume it's a waste of time to re-write file: * the version matched after all, unless we appended to it. */ if (modcache->from_file && !modcache->appended) return; if (symtable->entries == 0) return; /* nothing to write */ /* Open the temp symcache that we will rename. */ symcache_get_filename(modname, symfile, BUFFER_SIZE_ELEMENTS(symfile)); f = INVALID_FILE; i = 0; while (f == INVALID_FILE && i < SYMCACHE_MAX_TMP_TRIES) { dr_snprintf(symfile_tmp, BUFFER_SIZE_ELEMENTS(symfile_tmp), "%s.%04d.tmp", symfile, i); NULL_TERMINATE_BUFFER(symfile_tmp); f = dr_open_file(symfile_tmp, DR_FILE_WRITE_REQUIRE_NEW); i++; } if (f == INVALID_FILE) { NOTIFY("WARNING: Unable to create symcache temp file %s"NL, symfile_tmp); return; } BUFFERED_WRITE(f, buf, bsz, sofar, len, "%s %d\n", SYMCACHE_FILE_HEADER, SYMCACHE_VERSION); /* Leave room for file size for self-consistency check */ filesz_loc = sofar; /* XXX: Assumes that the buffer hasn't been flushed. */ BUFFERED_WRITE(f, buf, bsz, sofar, len, "%"STRINGIFY(SYMCACHE_SIZE_DIGITS)"u,", 0); #ifdef WINDOWS BUFFERED_WRITE(f, buf, bsz, sofar, len, UINT64_FORMAT_STRING","UINT64_FORMAT_STRING"," UINT64_FORMAT_STRING",%u,%u,%lu\n", modcache->module_file_size, modcache->file_version.version, modcache->product_version.version, modcache->checksum, modcache->timestamp, modcache->module_internal_size); #else BUFFERED_WRITE(f, buf, bsz, sofar, len, UINT64_FORMAT_STRING",%u", modcache->module_file_size, modcache->timestamp); # ifdef MACOS BUFFERED_WRITE(f, buf, bsz, sofar, len, ",%u,%u,", modcache->current_version, modcache->compatibility_version); /* For easy sscanf we print as 4 ints */ for (i = 0; i < 4; i++) BUFFERED_WRITE(f, buf, bsz, sofar, len, "%08x,", *(int*)(&modcache->uuid[i*4])); # endif BUFFERED_WRITE(f, buf, bsz, sofar, len, "\n"); #endif BUFFERED_WRITE(f, buf, bsz, sofar, len, "%u\n", modcache->has_debug_info); for (i = 0; i < HASHTABLE_SIZE(symtable->table_bits); i++) { hash_entry_t *he; for (he = symtable->table[i]; he != NULL; he = he->next) { offset_list_t *olist = (offset_list_t *) he->payload; offset_entry_t *e; if (olist == NULL) continue; /* skip symbol in dup entries to save space */ BUFFERED_WRITE(f, buf, bsz, sofar, len, "%s", he->key); e = olist->list; while (e != NULL) { BUFFERED_WRITE(f, buf, bsz, sofar, len, ",0x%x\n", e->offs); e = e->next; } } } /* now update size */ FLUSH_BUFFER(f, buf, sofar); if ((file_size = dr_file_tell(f)) < 0 || dr_snprintf(buf, BUFFER_SIZE_ELEMENTS(buf), "%"STRINGIFY(SYMCACHE_SIZE_DIGITS)"u", (uint)file_size) < 0 || !dr_file_seek(f, filesz_loc, DR_SEEK_SET) || dr_write_file(f, buf, SYMCACHE_SIZE_DIGITS) != SYMCACHE_SIZE_DIGITS) { /* If any steps fail, warn and give up. */ NOTIFY("WARNING: Unable to write symcache file size."NL); dr_close_file(f); dr_delete_file(symfile_tmp); return; } else { LOG(3, "Wrote symcache %s file size %u to pos "SZFMT"\n", modname, (uint)file_size, filesz_loc); ASSERT(strlen(buf) <= SYMCACHE_SIZE_DIGITS, "not enough space for file size"); } dr_close_file(f); if (!dr_rename_file(symfile_tmp, symfile, /*replace*/true)) { NOTIFY_ERROR("WARNING: Failed to rename the symcache file."NL); dr_delete_file(symfile_tmp); } }
void init_IPC(int idx, const char *path, bool standalone) { DR_ASSERT(idx < MAX_IPC_CHANNELS); int path_len, pad_len, shmem_len, fullfifo_len, emptyfifo_len; ipc_channel_t *channel = &IPC[idx]; channel->standalone = standalone; /* Initialize channel state */ ticket_node_t *node = dr_global_alloc(sizeof(ticket_node_t)); if (node == NULL) DR_ABORT_MSG("Failed to allocate ticket node\n"); node->next = NULL; node->dr_event = NULL; node->waiting = false; node->thread_id = 0; channel->ticket_queue.head = node; channel->ticket_queue.tail = node; channel->ticket_queue.locked = false; channel->queue_lock = dr_mutex_create(); channel->shared_mem = NULL; channel->full_fifo = -1; channel->empty_fifo = -1; channel->shmem_buf_idx = 0; for(uint i=0; i<sizeof(channel->empty_buf_idx)/sizeof(channel->empty_buf_idx[0]); ++i) channel->empty_buf_idx[i] = true; channel->last_active_tid = 0; channel->initialized = false; if (standalone) { /* mimic shared memory writes */ channel->shared_mem = dr_raw_mem_alloc(sizeof(Sigil2DBISharedData), DR_MEMPROT_READ | DR_MEMPROT_WRITE, NULL); if (channel->shared_mem == NULL) DR_ABORT_MSG("Failed to allocate pseudo shared memory buffer\n"); for (int i=0; i<SIGIL2_IPC_BUFFERS; ++i) channel->shared_mem->eventBuffers[i].used = 0; } else { /* Connect to Sigil2 */ path_len = strlen(path); pad_len = 4; /* extra space for '/', 2x'-', '\0' */ shmem_len = (path_len + pad_len + sizeof(SIGIL2_IPC_SHMEM_BASENAME) + sizeof(STRINGIFY(MAX_IPC_CHANNELS))); fullfifo_len = (path_len + pad_len + sizeof(SIGIL2_IPC_FULLFIFO_BASENAME) + sizeof(STRINGIFY(MAX_IPC_CHANNELS))); emptyfifo_len = (path_len + pad_len + sizeof(SIGIL2_IPC_EMPTYFIFO_BASENAME) + sizeof(STRINGIFY(MAX_IPC_CHANNELS))); /* set up names of IPC files */ char shmem_name[shmem_len]; sprintf(shmem_name, "%s/%s-%d", path, SIGIL2_IPC_SHMEM_BASENAME, idx); char fullfifo_name[fullfifo_len]; sprintf(fullfifo_name, "%s/%s-%d", path, SIGIL2_IPC_FULLFIFO_BASENAME, idx); char emptyfifo_name[emptyfifo_len]; sprintf(emptyfifo_name, "%s/%s-%d", path, SIGIL2_IPC_EMPTYFIFO_BASENAME, idx); /* initialize read/write pipes */ channel->empty_fifo = open_sigil2_fifo(emptyfifo_name, DR_FILE_READ); channel->full_fifo = open_sigil2_fifo(fullfifo_name, DR_FILE_WRITE_ONLY); /* no need to timeout on file because shared memory MUST be initialized * by Sigil2 before the fifos are created */ file_t map_file = dr_open_file(shmem_name, DR_FILE_READ|DR_FILE_WRITE_APPEND); if(map_file == INVALID_FILE) DR_ABORT_MSG("error opening shared memory file"); size_t mapped_size = sizeof(Sigil2DBISharedData); channel->shared_mem = dr_map_file(map_file, &mapped_size, 0, 0, /* assume this is not honored */ DR_MEMPROT_READ|DR_MEMPROT_WRITE, 0); if(mapped_size != sizeof(Sigil2DBISharedData) || channel->shared_mem == NULL) DR_ABORT_MSG("error mapping shared memory"); dr_close_file(map_file); } channel->initialized = true; }
void symcache_module_load(void *drcontext, const module_data_t *mod, bool loaded) { /* look for cache file for this module. * fill in hashtable: key is string, value is list of offsets */ mod_cache_t *modcache; const char *modname = dr_module_preferred_name(mod); file_t f; if (modname == NULL) return; /* don't support caching */ /* if smaller than threshold, not worth caching */ if (mod->end - mod->start < op_modsize_cache_threshold) { LOG(1, "%s: module %s too small to cache\n", __FUNCTION__, modname); return; } ASSERT(initialized, "symcache was not initialized"); /* support initializing prior to module events => called twice */ dr_mutex_lock(symcache_lock); modcache = (mod_cache_t *) hashtable_lookup(&symcache_table, (void *)mod->full_path); dr_mutex_unlock(symcache_lock); if (modcache != NULL) return; modcache = (mod_cache_t *) global_alloc(sizeof(*modcache), HEAPSTAT_HASHTABLE); memset(modcache, 0, sizeof(*modcache)); hashtable_init_ex(&modcache->table, SYMCACHE_MODULE_TABLE_HASH_BITS, HASH_STRING, true/*strdup*/, true/*synch*/, symcache_free_list, NULL, NULL); /* store consistency fields */ f = dr_open_file(mod->full_path, DR_FILE_READ); if (f != INVALID_FILE) { bool ok = dr_file_size(f, &modcache->module_file_size); if (!ok) WARN("WARNING: unable to determine size of %s\n", mod->full_path); dr_close_file(f); } else WARN("WARNING: unable to open %s\n", mod->full_path); #ifdef WINDOWS modcache->file_version = mod->file_version; modcache->product_version = mod->product_version; modcache->checksum = mod->checksum; modcache->timestamp = mod->timestamp; modcache->module_internal_size = mod->module_internal_size; #endif modcache->modname = drmem_strdup(modname, HEAPSTAT_HASHTABLE); modcache->from_file = symcache_read_symfile(mod, modname, modcache); dr_mutex_lock(symcache_lock); if (!hashtable_add(&symcache_table, (void *)mod->full_path, (void *)modcache)) { /* this should be really rare to have dup paths (xref i#729) -- and * actually we now have a lookup up above so we should only get here * on a race while we let go of the lock */ WARN("WARNING: duplicate module paths: only caching symbols from first\n"); hashtable_delete(&modcache->table); global_free(modcache, sizeof(*modcache), HEAPSTAT_HASHTABLE); } dr_mutex_unlock(symcache_lock); }