struct trace_buffer_t* tb_create(thread_id_t thread_id) { size_t size; struct trace_buffer_t* tb; size = MMAP_SIZE; // XXX: will -1 work on Windows? tb = dr_map_file(-1, &size, 0, 0, DR_MEMPROT_READ | DR_MEMPROT_WRITE, 0); if(!tb) { dr_fprintf(STDERR, "fatal: dr_map_file() failed\n"); dr_exit_process(1); } if((uintptr_t)tb % PAGE_SIZE != 0 || size != MMAP_SIZE) { dr_fprintf(STDERR, "fatal: dr_map_file() returned unusable area\n"); dr_exit_process(1); } if(!dr_memory_protect((void*)tb + MMAP_SIZE - PAGE_SIZE, PAGE_SIZE, DR_MEMPROT_NONE)) { dr_fprintf(STDERR, "fatal: dr_memory_protect() failed\n"); dr_exit_process(1); } tb_init(tb, TRACE_BUFFER_SIZE, trace_file, trace_file_lock, thread_id); #ifdef TRACE_DEBUG dr_fprintf(STDERR, "debug: created tb=%p\n", tb); #endif return tb; }
/* 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; }
/* file I/O */ void md_read_from_file (module_t * head, file_t file, bool extra_info){ uint64 map_size; size_t actual_size; bool ok; void * map = NULL; char * line; /*loop variables*/ int i; int j; /* linked list structure specific variables */ int no_modules; int no_instructions; unsigned int addr; char module_name[MAX_STRING_LENGTH]; /* for filling up the linked list data structure */ module_t * elem; ok = dr_file_size(file,&map_size); if(ok){ actual_size = (size_t)map_size; DR_ASSERT(actual_size == map_size); map = dr_map_file(file, &actual_size, 0, NULL, DR_MEMPROT_READ, 0); } dr_sscanf((char *)map,"%d\n",&no_modules); //dr_printf("%d\n",no_modules); //debug line = (char *)map; for(i=0;i<no_modules;i++){ line = strchr(line,'\n'); line++; //start of the next line //dr_sscanf(line,"%[^\t\n]\n",module_name); dr_get_token(line,module_name,MAX_STRING_LENGTH); //getFinalName(module_name); //dr_printf("%s\n",module_name); //debug line = strchr(line,'\n'); line++; //start of the next line dr_sscanf(line,"%d\n",&no_instructions); //dr_printf("%d\n",no_instructions); //debug //create a new element elem = new_elem(module_name,no_instructions+2); head->next = elem; head = elem; for(j=0;j<no_instructions;j++){ line = strchr(line,'\n'); line++; //start of the next line dr_sscanf(line,"%u\n",&addr); //dr_printf(line,"%x\n",addr); //debug add_bb_to_list(head->bbs,addr, extra_info, head->size_bbs); } } }
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; }
drcovlib_status_t drmodtrack_offline_read(file_t file, const char **map, OUT void **handle, OUT uint *num_mods) { module_read_info_t *info = NULL; uint i; uint64 file_size; size_t map_size = 0; const char *buf, *map_start; uint version; if (handle == NULL || num_mods == NULL) return DRCOVLIB_ERROR_INVALID_PARAMETER; if (file == INVALID_FILE) { if (map == NULL) return DRCOVLIB_ERROR_INVALID_PARAMETER; map_start = *map; } else { if (!dr_file_size(file, &file_size)) return DRCOVLIB_ERROR_INVALID_PARAMETER; map_size = (size_t)file_size; map_start = (char *) dr_map_file(file, &map_size, 0, NULL, DR_MEMPROT_READ, 0); if (map_start == NULL || map_size < file_size) return DRCOVLIB_ERROR_INVALID_PARAMETER; /* assume bad perms or sthg */ } if (map_start == NULL) return DRCOVLIB_ERROR_INVALID_PARAMETER; buf = map_start; /* Module table header, handling the pre-versioning legacy format. */ if (dr_sscanf(buf, "Module Table: %u\n", num_mods) == 1) version = 1; else if (dr_sscanf(buf, "Module Table: version %u, count %u\n", &version, num_mods) != 2 || version != MODULE_FILE_VERSION) goto read_error; buf = move_to_next_line(buf); if (version > 1) { // Skip header line buf = move_to_next_line(buf); } info = (module_read_info_t *)dr_global_alloc(sizeof(*info)); if (file != INVALID_FILE) { info->map = map_start; info->map_size = map_size; } else info->map = NULL; info->num_mods = *num_mods; info->mod = (module_read_entry_t *)dr_global_alloc(*num_mods * sizeof(*info->mod)); /* module lists */ for (i = 0; i < *num_mods; i++) { uint mod_id; if (version == 1) { if (dr_sscanf(buf, " %u, %" INT64_FORMAT"u, %[^\n\r]", &mod_id, &info->mod[i].size, info->mod[i].path) != 3 || mod_id != i) goto read_error; } else { app_pc end, entry; #ifdef WINDOWS uint checksum, timestamp; if (dr_sscanf(buf, " %u, "PIFX", "PIFX", "PIFX", 0x%x, 0x%x, %[^\n\r]", &mod_id, &info->mod[i].base, &end, &entry, &checksum, ×tamp, info->mod[i].path) != 7 || mod_id != i) goto read_error; #else if (dr_sscanf(buf, " %u, "PIFX", "PIFX", "PIFX", %[^\n\r]", &mod_id, &info->mod[i].base, &end, &entry, info->mod[i].path) != 5 || mod_id != i) goto read_error; #endif info->mod[i].size = end - info->mod[i].base; } buf = move_to_next_line(buf); } if (file == INVALID_FILE) *map = buf; *handle = (void *)info; return DRCOVLIB_SUCCESS; read_error: if (info != NULL) { dr_global_free(info->mod, *num_mods * sizeof(*info->mod)); dr_global_free(info, sizeof(*info)); } if (file != INVALID_FILE) dr_unmap_file((char *)map_start, map_size); return DRCOVLIB_ERROR; }
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 */