diff --git a/core/synch.c b/core/synch.c index ecb43244399..779cdbc1b12 100644 --- a/core/synch.c +++ b/core/synch.c @@ -2301,55 +2301,41 @@ detach_externally_on_linux() thread_id_t my_id; DEBUG_DECLARE(bool ok;) DEBUG_DECLARE(int exit_res;) - /* synch-all flags: */ uint flags = 0; - /* For Unix, such privilege problems are rarer but we would still prefer to * continue if we hit a problem. */ flags |= THREAD_SYNCH_SUSPEND_FAILURE_IGNORE; - /* i#297: we only synch client threads after process exit event. */ flags |= THREAD_SYNCH_SKIP_CLIENT_THREAD; - ENTERING_DR(); - /* dynamo_detaching_flag is not really a lock, and since no one ever waits * on it we can't deadlock on it either. */ if (!atomic_compare_exchange(&dynamo_detaching_flag, LOCK_FREE_STATE, LOCK_SET_STATE)) return; - instrument_pre_detach_event(); - /* Unprotect .data for exit cleanup. * XXX: more secure to not do this until we've synched, but then need * alternative prot for started_detach and init_apc_go_native* */ SELF_UNPROTECT_DATASEC(DATASEC_RARELY_PROT); - ASSERT(!started_detach); started_detach = true; - ASSERT(dynamo_initialized); ASSERT(!dynamo_exited); - my_id = d_r_get_thread_id(); my_dcontext = get_thread_private_dcontext(); ASSERT(my_dcontext != NULL); - LOG(GLOBAL, LOG_ALL, 1, "Detach: thread %d starting detach process\n", my_id); SYSLOG(SYSLOG_INFORMATION, INFO_DETACHING, 2, get_application_name(), get_application_pid()); - /* synch with flush */ if (my_dcontext != NULL) enter_threadexit(my_dcontext); - /* i#2270: we ignore alarm signals during detach to reduce races. */ signal_remove_alarm_handlers(my_dcontext); - /* suspend all DR-controlled threads at safe locations */ if (!synch_with_all_threads(THREAD_SYNCH_SUSPENDED_VALID_MCONTEXT, &threads, &num_threads, @@ -2362,18 +2348,15 @@ detach_externally_on_linux() REPORT_FATAL_ERROR_AND_EXIT(FAILED_TO_SYNCHRONIZE_THREADS, 2, get_application_name(), get_application_pid()); } - /* Now we own the thread_initexit_lock. We'll release the locks grabbed in * synch_with_all_threads below after cleaning up all the threads in case we * need to grab it during process exit cleanup. */ ASSERT(mutex_testlock(&all_threads_synch_lock) && mutex_testlock(&thread_initexit_lock)); - ASSERT(!doing_detach); doing_detach = true; detacher_tid = d_r_get_thread_id(); - #ifdef HOT_PATCHING_INTERFACE /* In hotp_only mode, we must remove patches when detaching; we don't want * to leave in all our hooks and detach; that will definitely crash the app. @@ -2381,28 +2364,24 @@ detach_externally_on_linux() if (DYNAMO_OPTION(hotp_only)) hotp_only_detach_helper(); #endif - if (!DYNAMO_OPTION(thin_client)) revert_memory_regions(); unhook_vsyscall(); LOG(GLOBAL, LOG_ALL, 1, "Detach : unpatched ntdll.dll and fixed memory permissions\n"); - /* perform exit tasks that require full thread data structs */ dynamo_process_exit_with_thread_info(); - LOG(GLOBAL, LOG_ALL, 1, "Detach: starting to translate contexts\n"); for (i = 0; i < num_threads; i++) { priv_mcontext_t mc; if (threads[i]->dcontext == my_dcontext) { my_idx = i; my_tr = threads[i]; - DEBUG_DECLARE(ok =) thread_get_nudged_mcontext(threads[i], &my_mcontext); - DEBUG_DECLARE(ok =) - translate_mcontext(threads[i], &my_mcontext, true /*restore mem*/, NULL /*f*/); + translate_mcontext(threads[i], &my_mcontext, true /*restore mem*/, + NULL /*f*/); ASSERT(!is_dynamo_address(my_mcontext.pc) && !in_fcache(my_mcontext.pc)); ASSERT(!in_fcache(my_mcontext.pc)); ASSERT(!is_dynamo_address(my_mcontext.pc)); @@ -2417,18 +2396,15 @@ detach_externally_on_linux() threads[i]->id); } else { LOG(GLOBAL, LOG_ALL, 2, "Detach: translating " TIDFMT "\n", threads[i]->id); - DEBUG_DECLARE(ok =) thread_get_mcontext(threads[i], &mc); ASSERT(ok); - /* For a thread at a syscall, we use SA_RESTART for our suspend signal, * so the kernel will adjust the restart point back to the syscall for us * where expected. This is an artifical signal we're introducing, so an * app that assumes no signals and assumes its non-auto-restart syscalls * don't need loops could be broken. */ - LOG(GLOBAL, LOG_ALL, 3, /* Having the code bytes can help diagnose post-detach where the code * cache is gone. @@ -2437,14 +2413,12 @@ detach_externally_on_linux() "for thread " TIDFMT "\n", mc.pc, *mc.pc, *(mc.pc + 1), *(mc.pc + 2), *(mc.pc + 3), *(mc.pc + 4), mc.xsp, threads[i]->id); - DEBUG_DECLARE(ok =) translate_mcontext(threads[i], &mc, true /*restore mem*/, NULL /*f*/); ASSERT(ok); - if (!threads[i]->under_dynamo_control) { dr_printf("Detach : thread " TIDFMT " already running natively\n", - threads[i]->id); + threads[i]->id); LOG(GLOBAL, LOG_ALL, 1, "Detach : thread " TIDFMT " already running natively\n", threads[i]->id); @@ -2454,7 +2428,6 @@ detach_externally_on_linux() put_back_native_retaddrs(threads[i]->dcontext); } } - LOG(GLOBAL, LOG_ALL, 1, "Detach: pc=" PFX " for thread " TIDFMT "\n", mc.pc, threads[i]->id); ASSERT(!is_dynamo_address(mc.pc) && !in_fcache(mc.pc)); @@ -2463,11 +2436,9 @@ detach_externally_on_linux() * structures for the handler, it could result in a codemod exception * that wouldn't happen natively! */ - DEBUG_DECLARE(ok =) thread_set_mcontext(threads[i], &mc); ASSERT(ok); - } /* Resumes the thread, which will do kernel-visible cleanup of * signal state. Resume happens within the synch_all region where @@ -2475,19 +2446,15 @@ detach_externally_on_linux() * data later. */ os_signal_thread_detach(threads[i]->dcontext); - LOG(GLOBAL, LOG_ALL, 1, "Detach: thread " TIDFMT " is being resumed as native\n", threads[i]->id); - os_thread_resume(threads[i]); } - LOG(GLOBAL, LOG_ALL, 1, "Detach: waiting for threads to fully detach\n"); for (i = 0; i < num_threads; i++) { if (i != my_idx && !IS_CLIENT_THREAD(threads[i]->dcontext)) os_wait_thread_detached(threads[i]->dcontext); } - /* Clean up each thread now that everyone has gone native. Needs to be * done with the thread_initexit_lock held, which is true within a synched * region. @@ -2499,36 +2466,26 @@ detach_externally_on_linux() dynamo_other_thread_exit(threads[i] _IF_WINDOWS(!cleanup_tpc[i])); } } - if (my_idx != -1) { /* pre-client thread cleanup (PR 536058) */ dynamo_thread_exit_pre_client(my_dcontext, my_tr->id); } - LOG(GLOBAL, LOG_ALL, 1, "Detach: Letting secondary threads go native\n"); end_synch_with_all_threads(threads, num_threads, false /*don't resume */); threads = NULL; - LOG(GLOBAL, LOG_ALL, 1, "Detach: Entering final cleanup and unload\n"); SYSLOG_INTERNAL_INFO("Detaching from process, entering final cleanup"); - DEBUG_DECLARE(exit_res =) dynamo_shared_exit(my_tr _IF_WINDOWS(detach_stacked_callbacks)); - ASSERT(exit_res == SUCCESS); detach_finalize_cleanup(); - stack_free(d_r_initstack, DYNAMORIO_STACK_SIZE); - dynamo_exit_post_detach(); - doing_detach = false; started_detach = false; - SELF_PROTECT_DATASEC(DATASEC_RARELY_PROT); dynamo_detaching_flag = LOCK_FREE_STATE; EXITING_DR(); options_detach(); - thread_set_self_mcontext(&my_mcontext); } diff --git a/core/unix/signal.c b/core/unix/signal.c index e5f86ccf2e4..ef3639bb474 100644 --- a/core/unix/signal.c +++ b/core/unix/signal.c @@ -8483,7 +8483,7 @@ handle_suspend_signal(dcontext_t *dcontext, kernel_siginfo_t *siginfo, if (is_sigqueue_supported() && SUSPEND_SIGNAL == NUDGESIG_SIGNUM) { nudge_arg_t *arg = (nudge_arg_t *)siginfo; - if (!TEST(NUDGE_IS_SUSPEND, arg->flags)){ + if (!TEST(NUDGE_IS_SUSPEND, arg->flags)) { sig_full_initialize(&sc_full, ucxt); ostd->nudged_sigcxt = &sc_full; return handle_nudge_signal(dcontext, siginfo, ucxt); diff --git a/suite/tests/client-interface/detach_test.dll.c b/suite/tests/client-interface/detach_test.dll.c index fceaa08f8a4..71ace838031 100644 --- a/suite/tests/client-interface/detach_test.dll.c +++ b/suite/tests/client-interface/detach_test.dll.c @@ -47,7 +47,7 @@ dr_exit(void) #ifdef WINDOWS dr_fprintf(STDERR, "done\n"); #else - /* The app prints 'done' for us. */ + /* The app prints 'done' for us. */ #endif } diff --git a/tools/drdeploy.c b/tools/drdeploy.c index 35f8df6fd97..f4fbbeaeb89 100644 --- a/tools/drdeploy.c +++ b/tools/drdeploy.c @@ -1216,9 +1216,9 @@ _tmain(int argc, TCHAR *targv[]) bool exit0 = false; #endif #if defined(DRCONFIG) -#if defined(WINDOWS) || defined(LINUX) +# if defined(WINDOWS) || defined(LINUX) process_id_t detach_pid = 0; -# endif +# endif #endif char *drlib_path = NULL; #if defined(DRCONFIG) || defined(DRRUN) @@ -1515,7 +1515,7 @@ _tmain(int argc, TCHAR *targv[]) nudge_arg = _strtoui64(argv[++i], NULL, 16); } # endif -#if defined(WINDOWS) || defined(LINUX) +# if defined(WINDOWS) || defined(LINUX) else if (strcmp(argv[i], "-detach") == 0) { if (i + 1 >= argc) usage(false, "detach requires a process id"); @@ -1845,13 +1845,14 @@ _tmain(int argc, TCHAR *targv[]) die(); } # ifndef WINDOWS -# ifdef LINUX +# ifdef LINUX else if (detach_pid != 0) { siginfo_t info; uint action_mask = 0x04; client_id_t client_id = 0; uint64 client_arg = 0; - bool success = create_nudge_signal_payload(&info, action_mask, 0, client_id, client_arg); + bool success = + create_nudge_signal_payload(&info, action_mask, 0, client_id, client_arg); assert(success); /* failure means kernel's sigqueueinfo has changed */ /* send the nudge */ @@ -1859,7 +1860,7 @@ _tmain(int argc, TCHAR *targv[]) if (i < 0) fprintf(stderr, "nudge FAILED with error %d\n", i); } -# endif +# endif else { usage(false, "no action specified"); } @@ -1899,8 +1900,7 @@ _tmain(int argc, TCHAR *targv[]) list_process(NULL, global, dr_platform, iter); dr_registered_process_iterator_stop(iter); } - } - else if (detach_pid != 0) { + } else if (detach_pid != 0) { dr_config_status_t res = detach(detach_pid, TRUE, detach_timeout); if (res != DR_SUCCESS) error("unable to detach: check pid and system ptrace permissions");