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); }
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; }
drcovlib_status_t drcovlib_init(drcovlib_options_t *ops) { int count = dr_atomic_add32_return_sum(&drcovlib_init_count, 1); if (count > 1) return DRCOVLIB_SUCCESS; if (ops->struct_size != sizeof(options)) return DRCOVLIB_ERROR_INVALID_PARAMETER; if ((ops->flags & (~(DRCOVLIB_DUMP_AS_TEXT|DRCOVLIB_THREAD_PRIVATE))) != 0) return DRCOVLIB_ERROR_INVALID_PARAMETER; if (TEST(DRCOVLIB_THREAD_PRIVATE, ops->flags)) { if (!dr_using_all_private_caches()) return DRCOVLIB_ERROR_INVALID_SETUP; drcov_per_thread = true; } options = *ops; if (options.logdir != NULL) dr_snprintf(logdir, BUFFER_SIZE_ELEMENTS(logdir), "%s", ops->logdir); else /* default */ dr_snprintf(logdir, BUFFER_SIZE_ELEMENTS(logdir), "."); NULL_TERMINATE_BUFFER(logdir); options.logdir = logdir; if (options.native_until_thread > 0) go_native = true; drmgr_init(); drx_init(); /* We follow a simple model of the caller requesting the coverage dump, * either via calling the exit routine, using its own soft_kills nudge, or * an explicit dump call for unusual cases. This means that drx's * soft_kills remains inside the outer later, i.e., the drcov client. This * is the easiest approach for coordinating soft_kills among many libraries. * Thus, we do *not* register for an exit event here. */ drmgr_register_thread_init_event(event_thread_init); drmgr_register_thread_exit_event(event_thread_exit); drmgr_register_bb_instrumentation_event(event_basic_block_analysis, NULL, NULL); dr_register_filter_syscall_event(event_filter_syscall); drmgr_register_pre_syscall_event(event_pre_syscall); #ifdef UNIX dr_register_fork_init_event(event_fork); #endif tls_idx = drmgr_register_tls_field(); if (tls_idx == -1) return DRCOVLIB_ERROR; return event_init(); }
static void wrap_pre_SSL_write(void *wrapcxt, OUT void **user_data) { /* int SSL_write(SSL *ssl, const void *buf, int num); * * ssize_t gnutls_record_send(gnutls_session_t session, * const void * data, size_t sizeofdata); */ void *ssl = (void *)drwrap_get_arg(wrapcxt, 0); unsigned char *buf = (unsigned char *)drwrap_get_arg(wrapcxt, 1); size_t sz = (size_t)drwrap_get_arg(wrapcxt, 2); /* By generating unique filenames (per SSL context), we are able to * simplify logging of SSL traffic (no file locking is required). */ char filename[MAXIMUM_PATH] = { 0 }; dr_snprintf(filename, BUFFER_SIZE_ELEMENTS(filename), "trace-%x.write", ssl); NULL_TERMINATE_BUFFER(filename); FILE *fp = fopen(filename, "ab+"); /* Error handling of logging operations isn't critical - in fact, we don't * even know what to do in such error conditions, so we simply return! */ if (!fp) { dr_fprintf(STDERR, "Couldn’t open the output file %s\n", filename); return; } /* We assume that SSL_write always succeeds and writes the whole buffer. */ fwrite(buf, 1, sz, fp); fclose(fp); }
static void options_init(client_id_t id) { const char *opstr = dr_get_options(id); const char *s; char token[OPTION_MAX_LENGTH]; /* default values */ dr_snprintf(options.logdir, BUFFER_SIZE_ELEMENTS(options.logdir), "."); for (s = dr_get_token(opstr, token, BUFFER_SIZE_ELEMENTS(token)); s != NULL; s = dr_get_token(s, token, BUFFER_SIZE_ELEMENTS(token))) { if (strcmp(token, "-logdir") == 0) { s = dr_get_token(s, options.logdir, BUFFER_SIZE_ELEMENTS(options.logdir)); USAGE_CHECK(s != NULL, "missing logdir path"); } else if (strcmp(token, "-verbose") == 0) { s = dr_get_token(s, token, BUFFER_SIZE_ELEMENTS(token)); USAGE_CHECK(s != NULL, "missing -verbose number"); if (s != NULL) { int res = dr_sscanf(token, "%u", &verbose); USAGE_CHECK(res == 1, "invalid -verbose number"); } } else if (strcmp(token, "-symcache_path") == 0) { s = dr_get_token(s, options.sympath, BUFFER_SIZE_ELEMENTS(options.sympath)); USAGE_CHECK(s != NULL, "missing symcache dir path"); ALERT(2, "<drstrace symbol source is %s>\n", options.sympath); } else { ALERT(0, "UNRECOGNIZED OPTION: \"%s\"\n", token); USAGE_CHECK(false, "invalid option"); } } }
static void exit_event(void) { #ifdef SHOW_RESULTS char msg[512]; int len; len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "Instrumentation results:\n" "Processed %d instructions\n" ,fp_count); DR_ASSERT(len > 0); NULL_TERMINATE(msg); DISPLAY_STRING(msg); #endif /* SHOW_RESULTS */ dr_mutex_destroy(count_mutex); #ifdef SHOW_SYMBOLS if (drsym_exit() != DRSYM_SUCCESS) { dr_log(NULL, LOG_ALL, 1, "WARNING: error cleaning up symbol library\n"); } #endif printht(); __wrap_free(testarr); }
void symcache_init(const char *symcache_dir_in, size_t modsize_cache_threshold) { 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(); } } } }
static void event_exit(void) { file_t f; /* Display the results! */ char msg[512]; int len; len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "Instrumentation results:\n" " saw %" STAT_FORMAT_CODE " flops\n", stats->num_flops); DR_ASSERT(len > 0); msg[sizeof(msg)/sizeof(msg[0])-1] = '\0'; #ifdef SHOW_RESULTS DISPLAY_STRING(msg); #endif /* SHOW_RESULTS */ /* On Windows we need an absolute path so we place it in * the same directory as our library. */ f = log_file_open(my_id, NULL, NULL /* client lib path */, "stats", 0); DR_ASSERT(f != INVALID_FILE); dr_fprintf(f, "%s\n", msg); dr_close_file(f); shared_memory_exit(); drx_exit(); if (!drmgr_unregister_bb_instrumentation_event(event_analyze_bb)) DR_ASSERT(false); drmgr_exit(); }
static void event_exit() { #ifdef SHOW_RESULTS char msg[512]; int len; len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "Instrumentation results:\n" " saw %llu memory references\n", num_refs); DR_ASSERT(len > 0); NULL_TERMINATE_BUFFER(msg); DISPLAY_STRING(msg); #endif /* SHOW_RESULTS */ code_cache_exit(); if (!drmgr_unregister_tls_field(tls_index) || !drmgr_unregister_thread_init_event(event_thread_init) || !drmgr_unregister_thread_exit_event(event_thread_exit) || !drmgr_unregister_bb_insertion_event(event_bb_insert) || drreg_exit() != DRREG_SUCCESS) DR_ASSERT(false); dr_mutex_destroy(mutex); drmgr_exit(); }
static void event_exit(void) { #ifdef SHOW_RESULTS char msg[512]; int len; uint64 total_count = app_count + lib_count; /* We only instrument indirect calls/jmps, and assume that * there would be a return paired with indirect calls/jmps. */ uint64 total_xfer = (app2lib + lib2app); len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "Instrumentation results:\n" "\t%10llu instructions executed\n" "\t%10llu (%2.3f%%) in app\n" "\t%10llu (%2.3f%%) in lib,\n" "\t%10llu (%2.3f%%) call/jmp between app and lib\n" "\t%10u app call/jmp to lib\n" "\t%10u lib call/jmp to app\n", total_count, app_count, 100*(float)app_count/total_count, lib_count, 100*(float)lib_count/total_count, total_xfer, 100*(float)total_xfer/total_count, app2lib, lib2app); DR_ASSERT(len > 0); NULL_TERMINATE(msg); DISPLAY_STRING(msg); #endif /* SHOW_RESULTS */ }
static void process_symbols(void *dcontext, char *dllname, LOADED_IMAGE *img) { /* We have to specify the module via "modname!symname". * We must use the same modname as in full_path. */ # define MAX_SYM_WITH_MOD_LEN 256 char sym_with_mod[MAX_SYM_WITH_MOD_LEN]; size_t modoffs; drsym_error_t symres; char *fname = NULL, *c; search_data_t sd; if (drsym_init(NULL) != DRSYM_SUCCESS) { print("WARNING: unable to initialize symbol engine\n"); return; } if (dllname == NULL) return; for (c = dllname; *c != '\0'; c++) { if (*c == '/' || *c == '\\') fname = c + 1; } assert(fname != NULL && "unable to get fname for module"); if (fname == NULL) return; /* now get rid of extension */ for (; c > fname && *c != '.'; c--) ; /* nothing */ assert(c - fname < BUFFER_SIZE_ELEMENTS(sym_with_mod) && "sizes way off"); modoffs = dr_snprintf(sym_with_mod, c - fname, "%s", fname); assert(modoffs > 0 && "error printing modname!symname"); modoffs = dr_snprintf(sym_with_mod + modoffs, BUFFER_SIZE_ELEMENTS(sym_with_mod) - modoffs, "!%s", SYM_PATTERN); assert(modoffs > 0 && "error printing modname!symname"); sd.dcontext = dcontext; sd.img = img; verbose_print("Searching \"%s\" for \"%s\"\n", dllname, sym_with_mod); symres = drsym_search_symbols(dllname, sym_with_mod, true, search_syms_cb, &sd); if (symres != DRSYM_SUCCESS) print("Error %d searching \"%s\" for \"%s\"\n", dllname, sym_with_mod); drsym_exit(); }
static void event_exit(void) { #ifdef SHOW_RESULTS char msg[256]; int len; if (enable) { len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "converted %d out of %d inc/dec to add/sub\n", num_converted, num_examined); } else { len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "decided to keep all original inc/dec\n"); } DR_ASSERT(len > 0); msg[sizeof(msg)/sizeof(msg[0])-1] = '\0'; DISPLAY_STRING(msg); #endif /* SHOW_RESULTS */ }
/* XXX i#1440: share w/ Linux */ static bool handle_strarray_access(sysarg_iter_info_t *ii, const sysinfo_arg_t *arg_info, app_pc start, uint size) { char id[16]; dr_snprintf(id, BUFFER_SIZE_ELEMENTS(id), "%s%d", "parameter #", arg_info->param); NULL_TERMINATE_BUFFER(id); check_strarray(ii, (char **)start, arg_info->param, id); return true; /* check_strarray checks whole array */ }
static char * get_mem_dump_filename(app_pc base_pc, uint size, uint write, uint other_info){ char other_details[MAX_STRING_LENGTH]; char * filename = dr_global_alloc(sizeof(char) * MAX_STRING_LENGTH); dr_snprintf(other_details, MAX_STRING_LENGTH, "%x_%d_%d_%d", base_pc, size, write, other_info); populate_conv_filename(filename, client_arg->output_folder, ins_pass_name, other_details); return filename; }
/* Requires that hex_buf be at least as long as 2*memref->size + 1. */ static char * write_hexdump(char *hex_buf, byte *write_base, mem_ref_t *mem_ref) { int i; char *hexstring = hex_buf, *needle = hex_buf; for (i = mem_ref->size - 1; i >= 0; --i) { needle += dr_snprintf(needle, 2 * mem_ref->size + 1 - (needle - hex_buf), "%02x", write_base[i]); } return hexstring; }
static void event_exit(void) { char msg[512]; int len; len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "Instrumentation results: %llu instructions executed\n", global_count); DR_ASSERT(len > 0); NULL_TERMINATE(msg); DISPLAY_STRING(msg); }
void drmemory_abort(void) { if (op_pause_at_assert) { char buf[64]; /* very useful to have the pid */ dr_snprintf(buf, BUFFER_SIZE_ELEMENTS(buf), "Dr. Memory is paused at an assert in pid=%d", dr_get_process_id()); wait_for_user(buf); } dr_abort(); }
/* assuming caller holds the lock */ static int module_table_entry_print(module_entry_t *entry, char *buf, size_t size) { const char *name; module_data_t *data; const char *full_path = "<unknown>"; int len, total_len = 0; data = entry->data; name = dr_module_preferred_name(data); if (data->full_path != NULL && data->full_path[0] != '\0') full_path = data->full_path; len = dr_snprintf(buf, size, "%3u, " PFX ", " PFX ", " PFX "", entry->id, data->start, data->end, data->entry_point); if (len == -1) return -1; buf += len; total_len += len; size -= len; #ifdef WINDOWS len = dr_snprintf(buf, size, ", 0x%08x, 0x%08x", data->checksum, data->timestamp); if (len == -1) return -1; buf += len; total_len += len; size -= len; #endif len = dr_snprintf(buf, size, ", %s\n", full_path); if (len == -1) return -1; buf += len; total_len += len; size -= len; return total_len; }
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"); }
static void show_results(void) { #ifdef SHOW_RESULTS char msg[512]; int len; /* Note that using %f with dr_printf or dr_fprintf on Windows will print * garbage as they use ntdll._vsnprintf, so we must use dr_snprintf. */ len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "<Number of system calls seen: %d>", num_syscalls); DR_ASSERT(len > 0); msg[sizeof(msg)/sizeof(msg[0])-1] = '\0'; DISPLAY_STRING(msg); #endif /* SHOW_RESULTS */ }
static void event_exit(void) { #ifdef SHOW_RESULTS char msg[256]; int len; len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "<Largest malloc request: %d>\n<OOM simulations: %d>\n", max_malloc, malloc_oom); DR_ASSERT(len > 0); NULL_TERMINATE(msg); DISPLAY_STRING(msg); #endif /* SHOW_RESULTS */ dr_mutex_destroy(max_lock); drwrap_exit(); }
/* We should only have a very small number of chunks (O(log(n)) per file, * so it is ok to use recursive call for printing. */ static char * line_chunk_print(line_chunk_t *chunk, char *start) { uint i, line_num; int res; for (i = 0, line_num = chunk->first_num; i < chunk->num_lines; i++, line_num++) { if (chunk->line_info[i] != SOURCE_LINE_STATUS_NONE) { res = dr_snprintf(start, MAX_CHAR_PER_LINE, "DA:%u,%u\n", line_num, chunk->line_info[i]); ASSERT(res < MAX_CHAR_PER_LINE && res != -1, "Error on printing\n"); start += res; } } return start; }
static void exit_event(void) { #ifdef SHOW_RESULTS char msg[512]; int len; len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "Instrumentation results:\n" " saw %d div instructions\n" " of which %d were powers of 2\n", div_count, div_p2_count); DR_ASSERT(len > 0); NULL_TERMINATE(msg); DISPLAY_STRING(msg); #endif /* SHOW_RESULTS */ dr_mutex_destroy(count_mutex); }
static void display_results(per_thread_t *data, char *thread_note) { #ifdef SHOW_RESULTS char msg[512]; int len; len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "%sInstrumentation results:\n" " saw %d direct calls\n" " saw %d indirect calls\n" " saw %d returns\n", thread_note, data->num_direct_calls, data->num_indirect_calls, data->num_returns); DR_ASSERT(len > 0); NULL_TERMINATE(msg); DISPLAY_STRING(msg); #endif /* SHOW_RESULTS */ }
static void event_thread_exit(void *drcontext) { per_thread_t *data = (per_thread_t *) dr_get_tls_field(drcontext); char msg[512]; int len; len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "Thread %d exited - ", dr_get_thread_id(drcontext)); DR_ASSERT(len > 0); NULL_TERMINATE(msg); /* display thread private counts data */ display_results(data, msg); /* clean up memory */ dr_thread_free(drcontext, data, sizeof(per_thread_t)); }
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 event_exit(void) { #ifdef SHOW_RESULTS char msg[512]; int len; len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "Instrumentation results:\n" "%10d basic block executions\n" "%10d basic blocks needed flag saving\n" "%10d basic blocks did not\n", global_count, bbs_eflags_saved, bbs_no_eflags_saved); DR_ASSERT(len > 0); NULL_TERMINATE(msg); DISPLAY_STRING(msg); #endif /* SHOW_RESULTS */ drreg_exit(); drmgr_exit(); }
static void event_exit(void) { #ifdef SHOW_RESULTS /* Display the results! */ char msg[512]; int len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "Inlining results:\n" " Number of traces: %d\n" " Number of complete inlines: %d\n", num_traces, num_complete_inlines); DR_ASSERT(len > 0); msg[sizeof(msg)/sizeof(msg[0])-1] = '\0'; DISPLAY_STRING(msg); #endif hashtable_delete(&head_table); if (!drmgr_unregister_bb_instrumentation_event(event_analyze_bb)) DR_ASSERT(false); drmgr_exit(); }
static void event_exit(void) { #ifdef SHOW_RESULTS char msg[512]; int len; /* Note that using %f with dr_printf or dr_fprintf on Windows will print * garbage as they use ntdll._vsnprintf, so we must use dr_snprintf. */ len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]), "Number of basic blocks seen: %d\n" " Maximum size: %d instructions\n" " Average size: %5.1f instructions\n", num_bb, max_size, ave_size); DR_ASSERT(len > 0); msg[sizeof(msg)/sizeof(msg[0])-1] = '\0'; DISPLAY_STRING(msg); #endif /* SHOW_RESULTS */ dr_mutex_destroy(stats_mutex); }
/* test unregistering from inside an event */ static dr_emit_flags_t one_time_bb_event(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating) { int i; # define STRESS_REGISTER_ITERS 64 # define NAME_SZ 32 char *names[STRESS_REGISTER_ITERS]; drmgr_priority_t pri = { sizeof(pri), }; one_time_exec++; if (!drmgr_unregister_bb_app2app_event(one_time_bb_event)) CHECK(false, "drmgr unregistration failed"); /* stress-test adding and removing */ for (i = 0; i < STRESS_REGISTER_ITERS; i++) { /* force sorted insertion on each add */ pri.priority = STRESS_REGISTER_ITERS - i; names[i] = dr_thread_alloc(drcontext, NAME_SZ); dr_snprintf(names[i], NAME_SZ, "%d", pri.priority); pri.name = names[i]; if (!drmgr_register_bb_app2app_event(one_time_bb_event, &pri)) CHECK(false, "drmgr app2app registration failed"); } /* XXX: drmgr lets us add multiple instances of the same callback * so long as they have different priority names (or use default * priority) -- but on removal it only asks for callback and * removes the first it finds. Thus we cannot free any memory * tied up in a priority until we remove *all* of them. * Normally priorities use string literals, so seems ok. */ for (i = 0; i < STRESS_REGISTER_ITERS; i++) { if (!drmgr_unregister_bb_app2app_event(one_time_bb_event)) CHECK(false, "drmgr app2app unregistration failed"); } for (i = 0; i < STRESS_REGISTER_ITERS; i++) { dr_thread_free(drcontext, names[i], NAME_SZ); } return DR_EMIT_DEFAULT; }