void module_table_print(module_table_t *table, file_t log, bool print_all_info) { uint i; module_entry_t *entry; if (log == INVALID_FILE) { /* It is possible that failure on log file creation is caused by the * running process not having enough privilege, so this is not a * release-build fatal error */ ASSERT(false, "invalid log file"); return; } drvector_lock(&table->vector); dr_fprintf(log, "Module Table: %u\n", table->vector.entries); if (print_all_info) { dr_fprintf(log, "Module Table: id, base, end, entry, unload, name, path"); #ifdef WINDOWS dr_fprintf(log, ", checksum, timestamp"); #endif dr_fprintf(log, "\n"); } for (i = 0; i < table->vector.entries; i++) { entry = drvector_get_entry(&table->vector, i); module_table_entry_print(entry, log, print_all_info); } drvector_unlock(&table->vector); }
drcovlib_status_t drmodtrack_dump_buf(char *buf, size_t size) { uint i; module_entry_t *entry; int len; if (buf == NULL || size == 0) return DRCOVLIB_ERROR_INVALID_PARAMETER; size--; /* for the terminating null character */ drvector_lock(&module_table.vector); len = dr_snprintf(buf, size, "Module Table: version %u, count %u\n", MODULE_FILE_VERSION, module_table.vector.entries); if (len == -1) { drvector_unlock(&module_table.vector); return DRCOVLIB_ERROR_BUF_TOO_SMALL; } buf += len; size -= len; len = dr_snprintf(buf, size, "Columns: id, base, end, entry"); if (len == -1) { drvector_unlock(&module_table.vector); return DRCOVLIB_ERROR_BUF_TOO_SMALL; } #ifdef WINDOWS buf += len; size -= len; len = dr_snprintf(buf, size, ", checksum, timestamp"); if (len == -1) { drvector_unlock(&module_table.vector); return DRCOVLIB_ERROR_BUF_TOO_SMALL; } #endif buf += len; size -= len; len = dr_snprintf(buf, size, ", path\n"); if (len == -1) { drvector_unlock(&module_table.vector); return DRCOVLIB_ERROR_BUF_TOO_SMALL; } buf += len; size -= len; for (i = 0; i < module_table.vector.entries; i++) { entry = drvector_get_entry(&module_table.vector, i); len = module_table_entry_print(entry, buf, size); if (len == -1) { drvector_unlock(&module_table.vector); return DRCOVLIB_ERROR_BUF_TOO_SMALL; } buf += len; size -= len; } buf[0] = '\0'; drvector_unlock(&module_table.vector); return DRCOVLIB_SUCCESS; }
static void event_module_load(void *drcontext, const module_data_t *data, bool loaded) { module_entry_t *entry = NULL; module_data_t *mod; int i; /* Some apps repeatedly unload and reload the same module, * so we will try to re-use the old one. */ ASSERT(data != NULL, "data must not be NULL"); drvector_lock(&module_table.vector); /* Assuming most recently loaded entries are most likely to be unloaded, * we iterate the module table in a backward way for better performance. */ for (i = module_table.vector.entries-1; i >= 0; i--) { entry = drvector_get_entry(&module_table.vector, i); mod = entry->data; if (entry->unload && /* If the same module is re-loaded at the same address, * we will try to use the existing entry. */ mod->start == data->start && mod->end == data->end && mod->entry_point == data->entry_point && #ifdef WINDOWS mod->checksum == data->checksum && mod->timestamp == data->timestamp && #endif /* If a module w/ no name (there are some) is loaded, we will * keep making new entries. */ dr_module_preferred_name(data) != NULL && dr_module_preferred_name(mod) != NULL && strcmp(dr_module_preferred_name(data), dr_module_preferred_name(mod)) == 0) { entry->unload = false; break; } entry = NULL; } if (entry == NULL) { entry = dr_global_alloc(sizeof(*entry)); entry->id = module_table.vector.entries; entry->unload = false; entry->data = dr_copy_module_data(data); drvector_append(&module_table.vector, entry); } drvector_unlock(&module_table.vector); global_module_cache_add(module_table.cache, entry); }
drcovlib_status_t drmodtrack_lookup(void *drcontext, app_pc pc, OUT uint *mod_index, OUT app_pc *mod_base) { per_thread_t *data = (per_thread_t *)drmgr_get_tls_field(drcontext, tls_idx); module_entry_t *entry; int i; /* We assume we never change an entry's data field, even on unload, * and thus it is ok to check its value without a lock. */ /* lookup thread module cache */ for (i = 0; i < NUM_THREAD_MODULE_CACHE; i++) { entry = data->cache[i]; if (pc_is_in_module(entry, pc)) { if (i > 0) { thread_module_cache_adjust(data->cache, entry, i, NUM_THREAD_MODULE_CACHE); } lookup_helper_set_fields(entry, mod_index, mod_base); return DRCOVLIB_SUCCESS; } } /* lookup global module cache */ /* we use a direct map cache, so it is ok to access it without lock */ for (i = 0; i < NUM_GLOBAL_MODULE_CACHE; i++) { entry = module_table.cache[i]; if (pc_is_in_module(entry, pc)) { lookup_helper_set_fields(entry, mod_index, mod_base); return DRCOVLIB_SUCCESS; } } /* lookup module table */ entry = NULL; drvector_lock(&module_table.vector); for (i = module_table.vector.entries - 1; i >= 0; i--) { entry = drvector_get_entry(&module_table.vector, i); ASSERT(entry != NULL, "fail to get module entry"); if (pc_is_in_module(entry, pc)) { global_module_cache_add(module_table.cache, entry); thread_module_cache_add(data->cache, NUM_THREAD_MODULE_CACHE, entry); break; } entry = NULL; } if (entry != NULL) lookup_helper_set_fields(entry, mod_index, mod_base); drvector_unlock(&module_table.vector); return entry == NULL ? DRCOVLIB_ERROR_NOT_FOUND : DRCOVLIB_SUCCESS; }
module_entry_t * module_table_lookup(module_entry_t **cache, int cache_size, module_table_t *table, app_pc pc) { module_entry_t *entry; int i; /* We assume we never change an entry's data field, even on unload, * and thus it is ok to check its value without a lock. */ /* lookup thread module cache */ if (cache != NULL) { for (i = 0; i < cache_size; i++) { entry = cache[i]; if (pc_is_in_module(entry, pc)) { if (i > 0) thread_module_cache_adjust(cache, entry, i, cache_size); return entry; } } } /* lookup global module cache */ /* we use a direct map cache, so it is ok to access it without lock */ for (i = 0; i < NUM_GLOBAL_MODULE_CACHE; i++) { entry = table->cache[i]; if (pc_is_in_module(entry, pc)) return entry; } /* lookup module table */ entry = NULL; drvector_lock(&table->vector); for (i = table->vector.entries - 1; i >= 0; i--) { entry = drvector_get_entry(&table->vector, i); ASSERT(entry != NULL, "fail to get module entry"); if (pc_is_in_module(entry, pc)) { global_module_cache_add(table->cache, entry); if (cache != NULL) thread_module_cache_add(cache, cache_size, entry); break; } entry = NULL; } drvector_unlock(&table->vector); return entry; }
static void event_module_unload(void *drcontext, const module_data_t *data) { module_entry_t *entry = NULL; int i; drvector_lock(&module_table.vector); for (i = module_table.vector.entries - 1; i >= 0; i--) { entry = drvector_get_entry(&module_table.vector, i); ASSERT(entry != NULL, "fail to get module entry"); if (pc_is_in_module(entry, data->start)) break; entry = NULL; } if (entry != NULL) entry->unload = true; else ASSERT(false, "fail to find the module to be unloaded"); drvector_unlock(&module_table.vector); }