void loader_thread_exit(dcontext_t *dcontext) { privmod_t *mod; /* assuming context swap have happened when entered DR */ if (privload_has_thread_entry() && /* Only call if we're cleaning up the currently executing thread, as * that's what the entry routine is going to do! Calling on other * threads results in problems like double frees (i#969). Exiting * another thread should only happen on process exit or forced thread * termination. The former can technically continue (app could call * NtTerminateProcess(0) but then keep going) but we have never seen * that; and the latter doesn't do full native cleanups anyway. Thus * we're not worried about leaks from not calling DLL_THREAD_EXIT. * (We can't check get_thread_private_dcontext() b/c it's already cleared.) */ dcontext->owning_thread == get_thread_id()) { acquire_recursive_lock(&privload_lock); /* Walk forward and call independent libs last */ for (mod = modlist; mod != NULL; mod = mod->next) { if (!mod->externally_loaded) privload_call_entry(mod, DLL_THREAD_EXIT); } release_recursive_lock(&privload_lock); } /* os specific thread exit for loader, holding no lock */ os_loader_thread_exit(dcontext); }
void os_loader_thread_init_prologue(dcontext_t *dcontext) { if (!privmod_initialized) { /* Because TLS is not setup at loader_init, we cannot call * loaded libraries' init functions there, so have to postpone * the invocation until here. */ acquire_recursive_lock(&privload_lock); privmod_t *mod = privload_first_module(); privload_call_modules_entry(mod, DLL_PROCESS_INIT); release_recursive_lock(&privload_lock); privmod_initialized = true; } }
void loader_init(void) { uint i; privmod_t *mod; acquire_recursive_lock(&privload_lock); VMVECTOR_ALLOC_VECTOR(modlist_areas, GLOBAL_DCONTEXT, VECTOR_SHARED | VECTOR_NEVER_MERGE /* protected by privload_lock */ | VECTOR_NO_LOCK, modlist_areas); /* os specific loader initialization prologue before finalize the load */ os_loader_init_prologue(); /* Process client libs we loaded early but did not finalize */ for (i = 0; i < privmod_static_idx; i++) { /* Transfer to real list so we can do normal processing */ char name_copy[MAXIMUM_PATH]; mod = privload_insert(NULL, privmod_static[i].base, privmod_static[i].size, privmod_static[i].name, privmod_static[i].path); LOG(GLOBAL, LOG_LOADER, 1, "%s: processing imports for %s\n", __FUNCTION__, mod->name); /* save a copy for error msg, b/c mod will be unloaded (i#643) */ snprintf(name_copy, BUFFER_SIZE_ELEMENTS(name_copy), "%s", mod->name); NULL_TERMINATE_BUFFER(name_copy); if (!privload_load_finalize(mod)) { mod = NULL; /* it's been unloaded! */ #ifdef CLIENT_INTERFACE SYSLOG(SYSLOG_ERROR, CLIENT_LIBRARY_UNLOADABLE, 5, get_application_name(), get_application_pid(), name_copy, "\n\tUnable to locate imports of client library"); #endif os_terminate(NULL, TERMINATE_PROCESS); ASSERT_NOT_REACHED(); } } /* os specific loader initialization epilogue after finalize the load */ os_loader_init_epilogue(); /* FIXME i#338: call loader_thread_init here once get * loader_init called after dynamo_thread_init but in a way that * works with Windows */ release_recursive_lock(&privload_lock); }
void loader_exit(void) { /* We must unload for detach so can't leave them loaded */ acquire_recursive_lock(&privload_lock); /* The list is kept in reverse-dependent order so we can unload from the * front without breaking dependencies. */ while (modlist != NULL) privload_unload(modlist); /* os related loader finalization */ os_loader_exit(); vmvector_delete_vector(GLOBAL_DCONTEXT, modlist_areas); release_recursive_lock(&privload_lock); DELETE_RECURSIVE_LOCK(privload_lock); }
void loader_thread_exit(dcontext_t *dcontext) { privmod_t *mod; /* assuming context swap have happened when entered DR */ if (privload_has_thread_entry()) { acquire_recursive_lock(&privload_lock); /* Walk forward and call independent libs last */ for (mod = modlist; mod != NULL; mod = mod->next) { if (!mod->externally_loaded) privload_call_entry(mod, DLL_THREAD_EXIT); } release_recursive_lock(&privload_lock); } /* os specific thread exit for loader, holding no lock */ os_loader_thread_exit(dcontext); }
void loader_thread_init(dcontext_t *dcontext) { privmod_t *mod; if (modlist == NULL) { #ifdef WINDOWS /* FIXME i#338: once restore order this will become nop */ /* os specific thread initilization prologue for loader with no lock */ os_loader_thread_init_prologue(dcontext); /* os specific thread initilization epilogue for loader with no lock */ os_loader_thread_init_epilogue(dcontext); #endif /* WINDOWS */ } else { /* os specific thread initilization prologue for loader with no lock */ os_loader_thread_init_prologue(dcontext); if (privload_has_thread_entry()) { /* We rely on lock isolation to prevent deadlock while we're here * holding privload_lock and the priv lib * DllMain may acquire the same lock that another thread acquired * in its app code before requesting a synchall (flush, exit). * FIXME i#875: we do not have ntdll!RtlpFlsLock isolated. * Living w/ it for now. It should be unlikely for the app to * hold RtlpFlsLock and then acquire privload_lock: privload_lock * is used for import redirection but those don't apply within * ntdll. */ ASSERT_OWN_NO_LOCKS(); acquire_recursive_lock(&privload_lock); /* Walk forward and call independent libs last. * We do notify priv libs of client threads. */ for (mod = modlist; mod != NULL; mod = mod->next) { if (!mod->externally_loaded) privload_call_entry(mod, DLL_THREAD_INIT); } release_recursive_lock(&privload_lock); } /* os specific thread initilization epilogue for loader with no lock */ os_loader_thread_init_epilogue(dcontext); } }
/* os specific loader initialization epilogue after finalizing the load. */ void os_loader_init_epilogue(void) { #ifdef INTERNAL /* Print the add-symbol-file commands so they can be copy-pasted into gdb. * We have to do it in a single syslog so they can be copy pasted. Since * info syslogs are only in internal builds, we only do this work in an * internal build. To debug an external build, we rely on the gdb script to * find text_addr in opd. * FIXME i#531: Support attaching from the gdb script. */ privmod_t *mod; size_t sofar = 0; size_t bufsz = 4096; /* Should be enough, but too much for stack. */ char *buf; /* FIXME: Skip this work if we're not going to print or log. */ ASSERT(dynamo_heap_initialized); ASSERT(!printed_gdb_commands); buf = HEAP_ARRAY_ALLOC(GLOBAL_DCONTEXT, char, bufsz, ACCT_OTHER, PROTECTED); acquire_recursive_lock(&privload_lock); for (mod = privload_first_module(); mod != NULL; mod = privload_next_module(mod)) { os_privmod_data_t *opd = (os_privmod_data_t *) mod->os_privmod_data; /* GDB already finds externally loaded modules (e.g. DR). */ if (mod->externally_loaded) continue; print_to_buffer(buf, bufsz, &sofar, "add-symbol-file '%s' %p\n", mod->path, opd->text_addr); } printed_gdb_commands = true; release_recursive_lock(&privload_lock); if (sofar > 0) { SYSLOG_INTERNAL_INFO("Paste into GDB to debug DynamoRIO clients:\n" /* Need to turn off confirm for paste to work. */ "set confirm off\n" "%s", buf); } HEAP_ARRAY_FREE(GLOBAL_DCONTEXT, buf, char, bufsz, ACCT_OTHER, PROTECTED); #endif /* INTERNAL */ }