From e1b9e533b92cea2f9783d0c730ac880f925a85bb Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 10:56:44 +0800 Subject: [PATCH 01/40] feat: enable detachment on Linux --- core/nudge.c | 21 ++++ core/optionsx.h | 2 +- core/os_shared.h | 4 + core/synch.c | 243 +++++++++++++++++++++++++++++++++++++++++ core/synch.h | 3 + core/unix/os.c | 15 +++ core/unix/os_private.h | 3 + core/unix/signal.c | 10 +- 8 files changed, 298 insertions(+), 3 deletions(-) diff --git a/core/nudge.c b/core/nudge.c index 4df3a4aa549..d96c9274d9d 100644 --- a/core/nudge.c +++ b/core/nudge.c @@ -42,6 +42,10 @@ #else #endif /* WINDOWS */ +#ifdef LINUX +# include "synch.h" +#endif + #ifdef HOT_PATCHING_INTERFACE # include "hotpatch.h" /* for hotp_nudge_update() */ #endif @@ -438,6 +442,23 @@ handle_nudge(dcontext_t *dcontext, nudge_arg_t *arg) detach_helper(DETACH_NORMAL_TYPE); } #endif +#ifdef LINUX + /* The detach handler is last since in the common case it doesn't return. */ + if (TEST(NUDGE_GENERIC(detach), nudge_action_mask)) { + nudge_action_mask &= ~NUDGE_GENERIC(detach); + heap_error_code_t error_code_reserve, error_code_commit; + void *d_r_detachstack = + os_heap_reserve(NULL, DYNAMORIO_STACK_SIZE, &error_code_reserve, false); + if (!os_heap_commit(d_r_detachstack, DYNAMORIO_STACK_SIZE, + MEMPROT_READ | MEMPROT_WRITE, &error_code_commit)) { + ASSERT_NOT_REACHED(); + } + call_switch_stack(dcontext, + (byte *)((ptr_uint_t)d_r_detachstack + DYNAMORIO_STACK_SIZE), + (void (*)(void *))detach_externally_on_linux, NULL, true); + ASSERT_NOT_REACHED(); + } +#endif } #ifdef UNIX diff --git a/core/optionsx.h b/core/optionsx.h index 52f98c1f868..23ed2bd6286 100644 --- a/core/optionsx.h +++ b/core/optionsx.h @@ -780,7 +780,7 @@ OPTION_DEFAULT(uint, max_pending_signals, 8, * mechanism that will set only the GPR's and will assume the target stack * is valid and its beyond-TOS slot can be clobbered. X86-only. */ -OPTION_DEFAULT_INTERNAL(bool, use_sigreturn_setcontext, true, +OPTION_DEFAULT_INTERNAL(bool, use_sigreturn_setcontext, false, "use sigreturn to set a thread's context") /* i#853: Use our all_memory_areas address space cache when possible. This diff --git a/core/os_shared.h b/core/os_shared.h index b2ef7d568c4..8e54cfaf070 100644 --- a/core/os_shared.h +++ b/core/os_shared.h @@ -204,6 +204,10 @@ is_thread_currently_native(thread_record_t *tr); */ bool thread_get_mcontext(thread_record_t *tr, priv_mcontext_t *mc); + +bool +thread_get_nudged_mcontext(thread_record_t *tr, priv_mcontext_t *mc); + bool thread_set_mcontext(thread_record_t *tr, priv_mcontext_t *mc); diff --git a/core/synch.c b/core/synch.c index 4c96c2b0e88..58fa5048e89 100644 --- a/core/synch.c +++ b/core/synch.c @@ -2289,3 +2289,246 @@ detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats) EXITING_DR(); options_detach(); } + +void +detach_externally_on_linux() +{ + dcontext_t *my_dcontext; + priv_mcontext_t my_mcontext; + thread_record_t **threads; + thread_record_t *my_tr = NULL; + int i, num_threads, my_idx = -1; + 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, + /* Case 6821: allow other synch-all-thread uses + * that beat us to not wait on us. We still have + * a problem if we go first since we must xfer + * other threads. + */ + THREAD_SYNCH_NO_LOCKS_NO_XFER, flags)) { + 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. + */ + 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*/); + 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)); + continue; + } else if (IS_CLIENT_THREAD(threads[i]->dcontext)) { + /* i#297 we will kill client-owned threads later after app exit events + * in dynamo_shared_exit(). + */ + continue; + } else if (detach_do_not_translate(threads[i])) { + LOG(GLOBAL, LOG_ALL, 2, "Detach: not translating " TIDFMT "\n", + 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. + */ + "Detach: pre-xl8 pc=%p (%02x %02x %02x %02x %02x), xsp=%p " + "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); + LOG(GLOBAL, LOG_ALL, 1, + "Detach : thread " TIDFMT " already running natively\n", + threads[i]->id); + /* we do need to restore the app ret addr, for native_exec */ + if (!DYNAMO_OPTION(thin_client) && DYNAMO_OPTION(native_exec) && + !vmvector_empty(native_exec_areas)) { + 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)); + /* XXX case 7457: if the thread is suspended after it received a fault + * but before the kernel copied the faulting context to the user mode + * 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 + * the thread_initexit_lock is held so that we can clean up thread + * 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. + */ + for (i = 0; i < num_threads; i++) { + if (i != my_idx && !IS_CLIENT_THREAD(threads[i]->dcontext)) { + LOG(GLOBAL, LOG_ALL, 1, "Detach: cleaning up thread " TIDFMT " %s\n", + threads[i]->id, IF_WINDOWS_ELSE(cleanup_tpc[i] ? "and its TPC" : "", "")); + 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); +} \ No newline at end of file diff --git a/core/synch.h b/core/synch.h index 90e1382c8f4..297d84f1398 100644 --- a/core/synch.h +++ b/core/synch.h @@ -263,6 +263,9 @@ send_all_other_threads_native(void); void detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats); +void +detach_externally_on_linux(); + /*** exported for detach only ***/ bool diff --git a/core/unix/os.c b/core/unix/os.c index 6949390b5f3..ad10e3383aa 100644 --- a/core/unix/os.c +++ b/core/unix/os.c @@ -3979,6 +3979,21 @@ thread_get_mcontext(thread_record_t *tr, priv_mcontext_t *mc) return true; } +bool +thread_get_nudged_mcontext(thread_record_t *tr, priv_mcontext_t *mc) +{ + /* PR 212090: only works when target is suspended by us, and + * we then take the signal context + */ + os_thread_data_t *ostd = (os_thread_data_t *)tr->dcontext->os_field; + ASSERT(ostd != NULL); + ASSERT(ostd->nudged_sigcxt != NULL); + sigcontext_to_mcontext(mc, ostd->nudged_sigcxt, DR_MC_ALL); + IF_ARM(dr_set_isa_mode(tr->dcontext, get_sigcontext_isa_mode(ostd->nudged_sigcxt), + NULL)); + return true; +} + bool thread_set_mcontext(thread_record_t *tr, priv_mcontext_t *mc) { diff --git a/core/unix/os_private.h b/core/unix/os_private.h index 1cfef5572a5..187ff7345e1 100644 --- a/core/unix/os_private.h +++ b/core/unix/os_private.h @@ -165,6 +165,9 @@ typedef struct _os_thread_data_t { KSYNCH_TYPE resumed; sig_full_cxt_t *suspended_sigcxt; + /* For detachment on Linux*/ + sig_full_cxt_t *nudged_sigcxt; + /* PR 297902: for thread termination */ bool terminate; /* Any function that sets this flag must also notify possibly waiting diff --git a/core/unix/signal.c b/core/unix/signal.c index 90767800081..e5f86ccf2e4 100644 --- a/core/unix/signal.c +++ b/core/unix/signal.c @@ -7917,10 +7917,13 @@ signal_to_itimer_type(int sig) static bool alarm_signal_has_DR_only_itimer(dcontext_t *dcontext, int signal) { - thread_sig_info_t *info = (thread_sig_info_t *)dcontext->signal_field; int which = signal_to_itimer_type(signal); if (which == -1) return false; + if (dcontext == GLOBAL_DCONTEXT) { + return false; + } + thread_sig_info_t *info = (thread_sig_info_t *)dcontext->signal_field; if (info->shared_itimer) acquire_recursive_lock(&(*info->itimer)[which].lock); bool DR_only = @@ -8480,8 +8483,11 @@ 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); + } } /* We distinguish from an app signal further below from the rare case of an From e96b744ed18df343f4c6f320c10c100817c04538 Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 11:04:51 +0800 Subject: [PATCH 02/40] feat: use the drconfig frontend for detachment --- tools/drdeploy.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/tools/drdeploy.c b/tools/drdeploy.c index 05175816564..35f8df6fd97 100644 --- a/tools/drdeploy.c +++ b/tools/drdeploy.c @@ -59,11 +59,16 @@ #include #include #include +#include #include "globals_shared.h" #include "dr_config.h" /* MUST be before share.h (it sets HOT_PATCHING_INTERFACE) */ #include "dr_inject.h" #include "dr_frontend.h" +extern bool +create_nudge_signal_payload(siginfo_t *info DR_PARAM_OUT, uint action_mask, + client_id_t client_id, uint flags, uint64 client_arg); + typedef enum _action_t { action_none, action_nudge, @@ -1211,9 +1216,9 @@ _tmain(int argc, TCHAR *targv[]) bool exit0 = false; #endif #if defined(DRCONFIG) -# ifdef WINDOWS +#if defined(WINDOWS) || defined(LINUX) process_id_t detach_pid = 0; -# endif +# endif #endif char *drlib_path = NULL; #if defined(DRCONFIG) || defined(DRRUN) @@ -1508,7 +1513,10 @@ _tmain(int argc, TCHAR *targv[]) nudge_all = true; nudge_id = strtoul(argv[++i], NULL, 16); nudge_arg = _strtoui64(argv[++i], NULL, 16); - } else if (strcmp(argv[i], "-detach") == 0) { + } +# endif +#if defined(WINDOWS) || defined(LINUX) + else if (strcmp(argv[i], "-detach") == 0) { if (i + 1 >= argc) usage(false, "detach requires a process id"); const char *pid_str = argv[++i]; @@ -1837,11 +1845,25 @@ _tmain(int argc, TCHAR *targv[]) die(); } # ifndef WINDOWS +# 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); + assert(success); /* failure means kernel's sigqueueinfo has changed */ + + /* send the nudge */ + i = syscall(SYS_rt_sigqueueinfo, detach_pid, NUDGESIG_SIGNUM, &info); + if (i < 0) + fprintf(stderr, "nudge FAILED with error %d\n", i); + } +# endif else { usage(false, "no action specified"); } # else /* WINDOWS */ - /* FIXME i#840: Nudge NYI on Linux. */ else if (action == action_nudge) { int count = 1; dr_config_status_t res = DR_SUCCESS; @@ -1878,7 +1900,6 @@ _tmain(int argc, TCHAR *targv[]) dr_registered_process_iterator_stop(iter); } } - /* FIXME i#95: Process detach NYI for UNIX. */ else if (detach_pid != 0) { dr_config_status_t res = detach(detach_pid, TRUE, detach_timeout); if (res != DR_SUCCESS) From 34ce6b33d01572187c6d021feb3b5f9440dd8e7e Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 11:14:13 +0800 Subject: [PATCH 03/40] test: add and modify test case for detachment on Linux and Windows --- suite/tests/CMakeLists.txt | 7 ++++--- .../client-interface/attach_test.template | 4 ---- .../tests/client-interface/detach_test.dll.c | 8 ++++++- .../client-interface/detach_test.template | 3 +-- suite/tests/runall.cmake | 21 +++++++------------ suite/tests/win32/attachee.c | 2 +- 6 files changed, 21 insertions(+), 24 deletions(-) diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 1304b50eb9e..323cf485a25 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -1411,6 +1411,9 @@ function(torun test key source native standalone_dr dr_ops exe_ops added_out pas # is failing). set(exe_ops "${exe_ops};-v;-attach") endif () + if ("${runall}" MATCHES "") + set(exe_ops "${exe_ops};-v;") + endif () if ("${runall}" MATCHES "") set(exe_ops "${exe_ops};-block") endif () @@ -2574,9 +2577,7 @@ endif (ANNOTATIONS AND NOT ARM) if (NOT ANDROID) # TODO i#38: Port test to Android. tobuild_ci(client.attach_test client-interface/attach_test.runall "" "" "") - if (WIN32) - tobuild_ci(client.detach_test client-interface/detach_test.runall "" "" "") - endif (WIN32) + tobuild_ci(client.detach_test client-interface/detach_test.runall "" "" "") if (UNIX) # Test attaching during a blocking syscall. torunonly_ci(client.attach_blocking linux.infloop client.attach_test.dll diff --git a/suite/tests/client-interface/attach_test.template b/suite/tests/client-interface/attach_test.template index b6e88d2236b..a732e0060a2 100644 --- a/suite/tests/client-interface/attach_test.template +++ b/suite/tests/client-interface/attach_test.template @@ -1,8 +1,4 @@ -#ifdef WINDOWS -starting attachee -#else starting -#endif thank you for testing attach thread init #ifdef WINDOWS diff --git a/suite/tests/client-interface/detach_test.dll.c b/suite/tests/client-interface/detach_test.dll.c index daac52d602b..fceaa08f8a4 100644 --- a/suite/tests/client-interface/detach_test.dll.c +++ b/suite/tests/client-interface/detach_test.dll.c @@ -39,11 +39,16 @@ static thread_id_t injection_tid; static bool first_thread = true; +static bool saw_attach_event = false; static void dr_exit(void) { +#ifdef WINDOWS dr_fprintf(STDERR, "done\n"); +#else + /* The app prints 'done' for us. */ +#endif } static void @@ -87,7 +92,8 @@ dr_exception_event(void *drcontext, dr_exception_t *excpt) static void event_post_attach(void) { - dr_fprintf(STDERR, "attach\n"); + // We do not print here as the ordering is non-deterministic vs thread init. + saw_attach_event = true; } static void diff --git a/suite/tests/client-interface/detach_test.template b/suite/tests/client-interface/detach_test.template index 1fe679addcb..1cb428dd057 100644 --- a/suite/tests/client-interface/detach_test.template +++ b/suite/tests/client-interface/detach_test.template @@ -1,6 +1,5 @@ -starting attachee +starting thank you for testing detach -attach thread init detach done diff --git a/suite/tests/runall.cmake b/suite/tests/runall.cmake index 7c7ad7823ea..532ca777cea 100644 --- a/suite/tests/runall.cmake +++ b/suite/tests/runall.cmake @@ -90,6 +90,12 @@ else (UNIX) set(nudge_cmd drconfig) endif (UNIX) +if (UNIX) + set(detach_cmd drconfig) +else () + set(detach_cmd drconfig.exe) +endif() + if (UNIX) set(MAX_ITERS 50000) else () @@ -268,17 +274,6 @@ if ("${orig_nudge}" MATCHES "-client") endif () endwhile() elseif ("${orig_nudge}" MATCHES "" OR "${orig_nudge}" MATCHES "") - # Wait until attached. - set(iters 0) - while (NOT "${output}" MATCHES "attach\n") - do_sleep(0.1) - file(READ "${out}" output) - math(EXPR iters "${iters}+1") - if (${iters} GREATER ${MAX_ITERS}) - kill_background_process(ON) - message(FATAL_ERROR "Timed out waiting for attach") - endif () - endwhile() # Wait until thread init. set(iters 0) while (NOT "${output}" MATCHES "thread init\n") @@ -298,7 +293,7 @@ else () endif () if ("${orig_nudge}" MATCHES "") - execute_process(COMMAND "${toolbindir}/drconfig.exe" "-detach" ${pid} + execute_process(COMMAND "${toolbindir}/${detach_cmd}" "-detach" ${pid} RESULT_VARIABLE detach_result ERROR_VARIABLE detach_err OUTPUT_VARIABLE detach_out) @@ -314,7 +309,7 @@ if ("${orig_nudge}" MATCHES "") math(EXPR iters "${iters}+1") if (${iters} GREATER ${MAX_ITERS}) kill_background_process(ON) - message(FATAL_ERROR "Timed out waiting for attach") + message(FATAL_ERROR "Timed out waiting for detach") endif () endwhile() endif() diff --git a/suite/tests/win32/attachee.c b/suite/tests/win32/attachee.c index daec058593c..4a8747fbdc0 100644 --- a/suite/tests/win32/attachee.c +++ b/suite/tests/win32/attachee.c @@ -65,7 +65,7 @@ main(int argc, const char *argv[]) "Infloop pid=%d", GetProcessId(GetCurrentProcess())); SetTimer(NULL, 0, 180 * 1000 /*3 mins*/, TimerProc); - print("starting attachee\n"); + print("starting\n"); MessageBoxA(NULL, "DynamoRIO test: will be auto-closed", title, MB_OK); if (!for_detach) { print("MessageBox closed\n"); From 8fe8c24bbb97131183fd20c1d32eb25a47a9f7d1 Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 11:22:37 +0800 Subject: [PATCH 04/40] docs: update the documentation to include detachment on Linux --- api/docs/deployment.dox | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/api/docs/deployment.dox b/api/docs/deployment.dox index bb779ea39ab..9cb8559c3c5 100644 --- a/api/docs/deployment.dox +++ b/api/docs/deployment.dox @@ -337,6 +337,12 @@ with this command: % echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope \endcode +Then, you can also detach DynamoRIO from the target process +without affecting the normal execution of the application. +\code +% bin32/drconfig -detach +\endcode + Run \c drrun with no options to get a list of the options and environment variable shortcuts it supports. To disable following across child execve calls, use the \ref op_children "-no_follow_children" runtime From d6d2acbc26271c21de7c65d66632e37c4f5cbb58 Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 13:22:08 +0800 Subject: [PATCH 05/40] fix: remove extra space --- suite/tests/runall.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/suite/tests/runall.cmake b/suite/tests/runall.cmake index 532ca777cea..08523de745f 100644 --- a/suite/tests/runall.cmake +++ b/suite/tests/runall.cmake @@ -313,7 +313,6 @@ if ("${orig_nudge}" MATCHES "") endif () endwhile() endif() - kill_background_process(OFF) if (NOT "${fail_msg}" STREQUAL "") From d3589ea9b3a31b0ab4882cd1a18f43d8737528a0 Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 13:35:05 +0800 Subject: [PATCH 06/40] fix: extra space --- core/synch.c | 2 +- suite/tests/runall.cmake | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/synch.c b/core/synch.c index 58fa5048e89..ecb43244399 100644 --- a/core/synch.c +++ b/core/synch.c @@ -2531,4 +2531,4 @@ detach_externally_on_linux() options_detach(); thread_set_self_mcontext(&my_mcontext); -} \ No newline at end of file +} diff --git a/suite/tests/runall.cmake b/suite/tests/runall.cmake index 08523de745f..532ca777cea 100644 --- a/suite/tests/runall.cmake +++ b/suite/tests/runall.cmake @@ -313,6 +313,7 @@ if ("${orig_nudge}" MATCHES "") endif () endwhile() endif() + kill_background_process(OFF) if (NOT "${fail_msg}" STREQUAL "") From 51d2b8624c4fd4197b1d8205d71ca7845cf86fc5 Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 13:37:52 +0800 Subject: [PATCH 07/40] fix: extra space --- suite/tests/runall.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suite/tests/runall.cmake b/suite/tests/runall.cmake index 532ca777cea..34c3300b337 100644 --- a/suite/tests/runall.cmake +++ b/suite/tests/runall.cmake @@ -312,7 +312,7 @@ if ("${orig_nudge}" MATCHES "") message(FATAL_ERROR "Timed out waiting for detach") endif () endwhile() -endif() +endif () kill_background_process(OFF) From 1956e11ccf444901dc38012b967c8ab86d637baf Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 16:39:42 +0800 Subject: [PATCH 08/40] fix: modify format --- core/synch.c | 49 ++----------------- core/unix/signal.c | 2 +- .../tests/client-interface/detach_test.dll.c | 2 +- tools/drdeploy.c | 16 +++--- 4 files changed, 13 insertions(+), 56 deletions(-) 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"); From 8221e5b460e21a2cb0ca63a29f98f7f28c52f90e Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 19:35:06 +0800 Subject: [PATCH 09/40] fix: test can't be finished --- suite/tests/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 323cf485a25..ead446dc6bf 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -2577,7 +2577,9 @@ endif (ANNOTATIONS AND NOT ARM) if (NOT ANDROID) # TODO i#38: Port test to Android. tobuild_ci(client.attach_test client-interface/attach_test.runall "" "" "") - tobuild_ci(client.detach_test client-interface/detach_test.runall "" "" "") + if (NOT APPLE AND NOT RISCV64) + tobuild_ci(client.detach_test client-interface/detach_test.runall "" "" "") + endif () if (UNIX) # Test attaching during a blocking syscall. torunonly_ci(client.attach_blocking linux.infloop client.attach_test.dll From 0f05ee1e5bd7aa4518191bf35971617f2ea888b8 Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 20:12:47 +0800 Subject: [PATCH 10/40] fix: add conditional macro ifdef LINUX --- core/os_shared.h | 2 ++ core/synch.c | 6 ++---- core/synch.h | 2 ++ core/unix/os.c | 2 ++ core/unix/os_private.h | 2 ++ core/unix/signal.c | 4 ++++ 6 files changed, 14 insertions(+), 4 deletions(-) diff --git a/core/os_shared.h b/core/os_shared.h index 8e54cfaf070..09aae11c53b 100644 --- a/core/os_shared.h +++ b/core/os_shared.h @@ -205,8 +205,10 @@ is_thread_currently_native(thread_record_t *tr); bool thread_get_mcontext(thread_record_t *tr, priv_mcontext_t *mc); +#ifdef LINUX bool thread_get_nudged_mcontext(thread_record_t *tr, priv_mcontext_t *mc); +#endif bool thread_set_mcontext(thread_record_t *tr, priv_mcontext_t *mc); diff --git a/core/synch.c b/core/synch.c index 779cdbc1b12..b9c354bbde0 100644 --- a/core/synch.c +++ b/core/synch.c @@ -2289,7 +2289,7 @@ detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats) EXITING_DR(); options_detach(); } - +#ifdef LINUX void detach_externally_on_linux() { @@ -2382,9 +2382,6 @@ detach_externally_on_linux() DEBUG_DECLARE(ok =) 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)); continue; } else if (IS_CLIENT_THREAD(threads[i]->dcontext)) { /* i#297 we will kill client-owned threads later after app exit events @@ -2489,3 +2486,4 @@ detach_externally_on_linux() options_detach(); thread_set_self_mcontext(&my_mcontext); } +#endif diff --git a/core/synch.h b/core/synch.h index 297d84f1398..9812a1494e0 100644 --- a/core/synch.h +++ b/core/synch.h @@ -263,8 +263,10 @@ send_all_other_threads_native(void); void detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats); +#ifdef LINUX void detach_externally_on_linux(); +#endif /*** exported for detach only ***/ diff --git a/core/unix/os.c b/core/unix/os.c index ad10e3383aa..f2d4cc72950 100644 --- a/core/unix/os.c +++ b/core/unix/os.c @@ -3979,6 +3979,7 @@ thread_get_mcontext(thread_record_t *tr, priv_mcontext_t *mc) return true; } +#ifdef LINUX bool thread_get_nudged_mcontext(thread_record_t *tr, priv_mcontext_t *mc) { @@ -3993,6 +3994,7 @@ thread_get_nudged_mcontext(thread_record_t *tr, priv_mcontext_t *mc) NULL)); return true; } +#endif bool thread_set_mcontext(thread_record_t *tr, priv_mcontext_t *mc) diff --git a/core/unix/os_private.h b/core/unix/os_private.h index 187ff7345e1..3d850b13f9f 100644 --- a/core/unix/os_private.h +++ b/core/unix/os_private.h @@ -165,8 +165,10 @@ typedef struct _os_thread_data_t { KSYNCH_TYPE resumed; sig_full_cxt_t *suspended_sigcxt; +#ifdef LINUX /* For detachment on Linux*/ sig_full_cxt_t *nudged_sigcxt; +#endif /* PR 297902: for thread termination */ bool terminate; diff --git a/core/unix/signal.c b/core/unix/signal.c index ef3639bb474..bd4b908e8fa 100644 --- a/core/unix/signal.c +++ b/core/unix/signal.c @@ -7920,9 +7920,11 @@ alarm_signal_has_DR_only_itimer(dcontext_t *dcontext, int signal) int which = signal_to_itimer_type(signal); if (which == -1) return false; +#ifdef LINUX if (dcontext == GLOBAL_DCONTEXT) { return false; } +#endif thread_sig_info_t *info = (thread_sig_info_t *)dcontext->signal_field; if (info->shared_itimer) acquire_recursive_lock(&(*info->itimer)[which].lock); @@ -8484,8 +8486,10 @@ 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)) { +#ifdef LINUX sig_full_initialize(&sc_full, ucxt); ostd->nudged_sigcxt = &sc_full; +#endif return handle_nudge_signal(dcontext, siginfo, ucxt); } } From cf4cde65eb643af17b09ff60ffe2296015aa9ec2 Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 20:16:50 +0800 Subject: [PATCH 11/40] fix: modify the format of conditional macro --- core/synch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/synch.c b/core/synch.c index b9c354bbde0..d8effb707b2 100644 --- a/core/synch.c +++ b/core/synch.c @@ -2357,13 +2357,13 @@ detach_externally_on_linux() ASSERT(!doing_detach); doing_detach = true; detacher_tid = d_r_get_thread_id(); -#ifdef HOT_PATCHING_INTERFACE +# 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. */ if (DYNAMO_OPTION(hotp_only)) hotp_only_detach_helper(); -#endif +# endif if (!DYNAMO_OPTION(thin_client)) revert_memory_regions(); unhook_vsyscall(); From 8a75c73643f2d0c6b5701754c5e0d03d4c0a6d1c Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 20:28:29 +0800 Subject: [PATCH 12/40] fix: add conditional macro ifdef LINUX --- tools/drdeploy.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/drdeploy.c b/tools/drdeploy.c index f4fbbeaeb89..2870f91fe0b 100644 --- a/tools/drdeploy.c +++ b/tools/drdeploy.c @@ -51,6 +51,10 @@ # include # include #endif +#ifdef LINUX +# include +#endif + #include #include @@ -59,7 +63,6 @@ #include #include #include -#include #include "globals_shared.h" #include "dr_config.h" /* MUST be before share.h (it sets HOT_PATCHING_INTERFACE) */ #include "dr_inject.h" From 7c0b21b681cb670875657d8d1043ef0fef027c98 Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 20:29:46 +0800 Subject: [PATCH 13/40] fix: add conditional macro ifdef LINUX --- tools/drdeploy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/drdeploy.c b/tools/drdeploy.c index 2870f91fe0b..301346be042 100644 --- a/tools/drdeploy.c +++ b/tools/drdeploy.c @@ -55,7 +55,6 @@ # include #endif - #include #include #include From cea79a5699d7b669795a4ae999c924de089a6d37 Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 20:30:04 +0800 Subject: [PATCH 14/40] fix: add conditional macro ifdef LINUX --- tools/drdeploy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/drdeploy.c b/tools/drdeploy.c index 301346be042..6f27d5c5256 100644 --- a/tools/drdeploy.c +++ b/tools/drdeploy.c @@ -51,6 +51,7 @@ # include # include #endif + #ifdef LINUX # include #endif From 30ddfe14bd2992b04adc33fdd606083bd9719773 Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 20:35:54 +0800 Subject: [PATCH 15/40] fix: add conditional macro ifdef LINUX --- tools/drdeploy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/drdeploy.c b/tools/drdeploy.c index 6f27d5c5256..fc050f21d36 100644 --- a/tools/drdeploy.c +++ b/tools/drdeploy.c @@ -68,9 +68,11 @@ #include "dr_inject.h" #include "dr_frontend.h" +#ifdef LINUX extern bool create_nudge_signal_payload(siginfo_t *info DR_PARAM_OUT, uint action_mask, client_id_t client_id, uint flags, uint64 client_arg); +#endif typedef enum _action_t { action_none, From 892b75b48d99f3be2d3cf5ac44b2806d348ba763 Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 21:27:59 +0800 Subject: [PATCH 16/40] fix: add conditional macro ifdef LINUX --- core/optionsx.h | 5 +++++ suite/tests/runall.cmake | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/core/optionsx.h b/core/optionsx.h index 23ed2bd6286..072da57d342 100644 --- a/core/optionsx.h +++ b/core/optionsx.h @@ -780,8 +780,13 @@ OPTION_DEFAULT(uint, max_pending_signals, 8, * mechanism that will set only the GPR's and will assume the target stack * is valid and its beyond-TOS slot can be clobbered. X86-only. */ +#ifdef LINUX OPTION_DEFAULT_INTERNAL(bool, use_sigreturn_setcontext, false, "use sigreturn to set a thread's context") +#else +OPTION_DEFAULT_INTERNAL(bool, use_sigreturn_setcontext, true, + "use sigreturn to set a thread's context") +#endif /* i#853: Use our all_memory_areas address space cache when possible. This * avoids expensive reads of /proc/pid/maps, but if the cache becomes stale, diff --git a/suite/tests/runall.cmake b/suite/tests/runall.cmake index 34c3300b337..a7ba17ae1ad 100644 --- a/suite/tests/runall.cmake +++ b/suite/tests/runall.cmake @@ -314,7 +314,7 @@ if ("${orig_nudge}" MATCHES "") endwhile() endif () -kill_background_process(OFF) +kill_background_process(ON) if (NOT "${fail_msg}" STREQUAL "") message(FATAL_ERROR "${fail_msg}") From 3a0005219db47501da933f21a21021851b459b08 Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 21:31:44 +0800 Subject: [PATCH 17/40] fix: add conditional macro ifdef LINUX --- core/optionsx.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/optionsx.h b/core/optionsx.h index 072da57d342..73daec841fd 100644 --- a/core/optionsx.h +++ b/core/optionsx.h @@ -780,13 +780,13 @@ OPTION_DEFAULT(uint, max_pending_signals, 8, * mechanism that will set only the GPR's and will assume the target stack * is valid and its beyond-TOS slot can be clobbered. X86-only. */ -#ifdef LINUX +# ifdef LINUX OPTION_DEFAULT_INTERNAL(bool, use_sigreturn_setcontext, false, "use sigreturn to set a thread's context") -#else +# else OPTION_DEFAULT_INTERNAL(bool, use_sigreturn_setcontext, true, "use sigreturn to set a thread's context") -#endif +# endif /* i#853: Use our all_memory_areas address space cache when possible. This * avoids expensive reads of /proc/pid/maps, but if the cache becomes stale, From c54f5b1ff6e36ac239e47651c77f0c59b8dd8c1e Mon Sep 17 00:00:00 2001 From: Wenlong Mu Date: Mon, 18 Dec 2023 22:01:55 +0800 Subject: [PATCH 18/40] test again --- suite/tests/runall.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suite/tests/runall.cmake b/suite/tests/runall.cmake index a7ba17ae1ad..34c3300b337 100644 --- a/suite/tests/runall.cmake +++ b/suite/tests/runall.cmake @@ -314,7 +314,7 @@ if ("${orig_nudge}" MATCHES "") endwhile() endif () -kill_background_process(ON) +kill_background_process(OFF) if (NOT "${fail_msg}" STREQUAL "") message(FATAL_ERROR "${fail_msg}") From 35faf438d38b2235976a76087b401ae90741bf5d Mon Sep 17 00:00:00 2001 From: wlmu Date: Tue, 19 Dec 2023 15:34:47 +0800 Subject: [PATCH 19/40] resume attach test --- suite/tests/CMakeLists.txt | 10 +++-- .../client-interface/attach_test.template | 4 ++ .../client-interface/detach_test.template | 4 ++ suite/tests/runall.cmake | 37 ++++++++++++++++++- suite/tests/win32/attachee.c | 2 +- 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 1dface5ff81..a592ec563cd 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -1411,12 +1411,14 @@ function(torun test key source native standalone_dr dr_ops exe_ops added_out pas # is failing). set(exe_ops "${exe_ops};-v;-attach") endif () - if ("${runall}" MATCHES "") - set(exe_ops "${exe_ops};-v;") - endif () if ("${runall}" MATCHES "") set(exe_ops "${exe_ops};-block") endif () + if (LINUX) + if ("${runall}" MATCHES "") + set(exe_ops "${exe_ops};-v;") + endif () + endif () else () if ("${runall}" MATCHES "" OR "${runall}" MATCHES "") # For detach we use attachee to attach firstly, and "-detach" option is used @@ -2577,7 +2579,7 @@ endif (ANNOTATIONS AND NOT ARM) if (NOT ANDROID) # TODO i#38: Port test to Android. tobuild_ci(client.attach_test client-interface/attach_test.runall "" "" "") - if (NOT APPLE AND NOT RISCV64) + if ((LINUX OR WIN32) AND NOT RISCV64) tobuild_ci(client.detach_test client-interface/detach_test.runall "" "" "") endif () if (UNIX) diff --git a/suite/tests/client-interface/attach_test.template b/suite/tests/client-interface/attach_test.template index a732e0060a2..b6e88d2236b 100644 --- a/suite/tests/client-interface/attach_test.template +++ b/suite/tests/client-interface/attach_test.template @@ -1,4 +1,8 @@ +#ifdef WINDOWS +starting attachee +#else starting +#endif thank you for testing attach thread init #ifdef WINDOWS diff --git a/suite/tests/client-interface/detach_test.template b/suite/tests/client-interface/detach_test.template index 1cb428dd057..fd8496ea131 100644 --- a/suite/tests/client-interface/detach_test.template +++ b/suite/tests/client-interface/detach_test.template @@ -1,4 +1,8 @@ +#ifdef WINDOWS +starting attachee +#else starting +#endif thank you for testing detach thread init detach diff --git a/suite/tests/runall.cmake b/suite/tests/runall.cmake index 34c3300b337..502e777f4c6 100644 --- a/suite/tests/runall.cmake +++ b/suite/tests/runall.cmake @@ -273,7 +273,18 @@ if ("${orig_nudge}" MATCHES "-client") message(FATAL_ERROR "Timed out waiting for more output") endif () endwhile() -elseif ("${orig_nudge}" MATCHES "" OR "${orig_nudge}" MATCHES "") +elseif ("${orig_nudge}" MATCHES "") + # Wait until attached. + set(iters 0) + while (NOT "${output}" MATCHES "attach\n") + do_sleep(0.1) + file(READ "${out}" output) + math(EXPR iters "${iters}+1") + if (${iters} GREATER ${MAX_ITERS}) + kill_background_process(ON) + message(FATAL_ERROR "Timed out waiting for attach") + endif () + endwhile() # Wait until thread init. set(iters 0) while (NOT "${output}" MATCHES "thread init\n") @@ -282,7 +293,29 @@ elseif ("${orig_nudge}" MATCHES "" OR "${orig_nudge}" MATCHES "" math(EXPR iters "${iters}+1") if (${iters} GREATER ${MAX_ITERS}) kill_background_process(ON) - message(FATAL_ERROR "Timed out waiting for attach") + message(FATAL_ERROR "Timed out waiting for thread init") + endif () + endwhile() +elseif ("${orig_nudge}" MATCHES "") + set(iters 0) + while (NOT "${output}" MATCHES "detach\n") + do_sleep(0.1) + file(READ "${out}" output) + math(EXPR iters "${iters}+1") + if (${iters} GREATER ${MAX_ITERS}) + kill_background_process(ON) + message(FATAL_ERROR "Timed out waiting for detach") + endif () + endwhile() + # Wait until thread init. + set(iters 0) + while (NOT "${output}" MATCHES "thread init\n") + do_sleep(0.1) + file(READ "${out}" output) + math(EXPR iters "${iters}+1") + if (${iters} GREATER ${MAX_ITERS}) + kill_background_process(ON) + message(FATAL_ERROR "Timed out waiting for thread init") endif () endwhile() else () diff --git a/suite/tests/win32/attachee.c b/suite/tests/win32/attachee.c index 4a8747fbdc0..daec058593c 100644 --- a/suite/tests/win32/attachee.c +++ b/suite/tests/win32/attachee.c @@ -65,7 +65,7 @@ main(int argc, const char *argv[]) "Infloop pid=%d", GetProcessId(GetCurrentProcess())); SetTimer(NULL, 0, 180 * 1000 /*3 mins*/, TimerProc); - print("starting\n"); + print("starting attachee\n"); MessageBoxA(NULL, "DynamoRIO test: will be auto-closed", title, MB_OK); if (!for_detach) { print("MessageBox closed\n"); From 70f137de0d67039a4f593312ce1669cdcfd879d4 Mon Sep 17 00:00:00 2001 From: wlmu Date: Wed, 20 Dec 2023 09:11:21 +0800 Subject: [PATCH 20/40] debug git test suite --- suite/tests/CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index a592ec563cd..747156cc4e4 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -1414,11 +1414,11 @@ function(torun test key source native standalone_dr dr_ops exe_ops added_out pas if ("${runall}" MATCHES "") set(exe_ops "${exe_ops};-block") endif () - if (LINUX) - if ("${runall}" MATCHES "") - set(exe_ops "${exe_ops};-v;") - endif () - endif () +# if (LINUX) +# if ("${runall}" MATCHES "") +# set(exe_ops "${exe_ops};-v;") +# endif () +# endif () else () if ("${runall}" MATCHES "" OR "${runall}" MATCHES "") # For detach we use attachee to attach firstly, and "-detach" option is used @@ -2579,7 +2579,7 @@ endif (ANNOTATIONS AND NOT ARM) if (NOT ANDROID) # TODO i#38: Port test to Android. tobuild_ci(client.attach_test client-interface/attach_test.runall "" "" "") - if ((LINUX OR WIN32) AND NOT RISCV64) + if (WIN32) # ((LINUX OR WIN32) AND NOT RISCV64) tobuild_ci(client.detach_test client-interface/detach_test.runall "" "" "") endif () if (UNIX) From 2d6fa3932eaa74b09195325fe48ac62e7987abbf Mon Sep 17 00:00:00 2001 From: wlmu Date: Wed, 20 Dec 2023 09:39:26 +0800 Subject: [PATCH 21/40] debug git test suite --- core/optionsx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/optionsx.h b/core/optionsx.h index 73daec841fd..593456ec0fc 100644 --- a/core/optionsx.h +++ b/core/optionsx.h @@ -781,7 +781,7 @@ OPTION_DEFAULT(uint, max_pending_signals, 8, * is valid and its beyond-TOS slot can be clobbered. X86-only. */ # ifdef LINUX -OPTION_DEFAULT_INTERNAL(bool, use_sigreturn_setcontext, false, +OPTION_DEFAULT_INTERNAL(bool, use_sigreturn_setcontext, true, "use sigreturn to set a thread's context") # else OPTION_DEFAULT_INTERNAL(bool, use_sigreturn_setcontext, true, From 12b244ffecbd888d3b06d2006f2c0f73ef8d3e44 Mon Sep 17 00:00:00 2001 From: wlmu Date: Wed, 20 Dec 2023 10:54:45 +0800 Subject: [PATCH 22/40] add is_detach_external --- core/os_shared.h | 4 ++-- core/synch.c | 6 +++--- core/unix/signal.c | 8 ++++---- core/win32/os.c | 8 ++++---- suite/tests/CMakeLists.txt | 12 ++++++------ 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/core/os_shared.h b/core/os_shared.h index 09aae11c53b..5b828e66259 100644 --- a/core/os_shared.h +++ b/core/os_shared.h @@ -215,10 +215,10 @@ thread_set_mcontext(thread_record_t *tr, priv_mcontext_t *mc); /* Takes an os-specific context. Does not return. */ void -thread_set_self_context(void *cxt); +thread_set_self_context(void *cxt, bool is_detach_external); /* Only sets the priv_mcontext_t state. Does not return. */ void -thread_set_self_mcontext(priv_mcontext_t *mc); +thread_set_self_mcontext(priv_mcontext_t *mc, bool is_detach_external); /* Assumes target thread is suspended */ bool diff --git a/core/synch.c b/core/synch.c index d8effb707b2..89ecdefde7a 100644 --- a/core/synch.c +++ b/core/synch.c @@ -761,9 +761,9 @@ check_wait_at_safe_spot(dcontext_t *dcontext, thread_synch_permission_t cur_stat * being at the synch point vs in the cache. */ if (set_mcontext) - thread_set_self_mcontext((priv_mcontext_t *)cxt); + thread_set_self_mcontext((priv_mcontext_t *)cxt, false); else - thread_set_self_context((void *)cxt); + thread_set_self_context((void *)cxt, false); ASSERT_NOT_REACHED(); } } @@ -2484,6 +2484,6 @@ detach_externally_on_linux() dynamo_detaching_flag = LOCK_FREE_STATE; EXITING_DR(); options_detach(); - thread_set_self_mcontext(&my_mcontext); + thread_set_self_mcontext(&my_mcontext, true); } #endif diff --git a/core/unix/signal.c b/core/unix/signal.c index bd4b908e8fa..04ba562ebcc 100644 --- a/core/unix/signal.c +++ b/core/unix/signal.c @@ -3166,10 +3166,10 @@ translate_sigcontext(dcontext_t *dcontext, kernel_ucontext_t *uc, bool avoid_fai /* Takes an os-specific context */ void -thread_set_self_context(void *cxt) +thread_set_self_context(void *cxt, bool is_detach_external) { #ifdef X86 - if (!INTERNAL_OPTION(use_sigreturn_setcontext)) { + if (!INTERNAL_OPTION(use_sigreturn_setcontext) || is_detach_external) { sigcontext_t *sc = (sigcontext_t *)cxt; dr_jmp_buf_t buf; buf.xbx = sc->SC_XBX; @@ -3311,7 +3311,7 @@ thread_set_segment_registers(sigcontext_t *sc) /* Takes a priv_mcontext_t */ void -thread_set_self_mcontext(priv_mcontext_t *mc) +thread_set_self_mcontext(priv_mcontext_t *mc, bool is_detach_external) { kernel_ucontext_t ucxt; sig_full_cxt_t sc_full; @@ -3325,7 +3325,7 @@ thread_set_self_mcontext(priv_mcontext_t *mc) IF_ARM( set_pc_mode_in_cpsr(sc_full.sc, dr_get_isa_mode(get_thread_private_dcontext()))); /* thread_set_self_context will fill in the real fp/simd state for x86 */ - thread_set_self_context((void *)sc_full.sc); + thread_set_self_context((void *)sc_full.sc, is_detach_external); ASSERT_NOT_REACHED(); } diff --git a/core/win32/os.c b/core/win32/os.c index b5dc3b3793f..2f294643ef2 100644 --- a/core/win32/os.c +++ b/core/win32/os.c @@ -2795,7 +2795,7 @@ thread_attach_setup(priv_mcontext_t *mc) * sets the context back). */ mc->pc = data->continuation_pc; - thread_set_self_mcontext(mc); + thread_set_self_mcontext(mc, false); ASSERT_NOT_REACHED(); } /* Preclude double takeover if we become suspended while in ntdll */ @@ -5201,7 +5201,7 @@ thread_set_context(thread_record_t *tr, CONTEXT *context) /* Takes an os-specific context */ void -thread_set_self_context(void *cxt) +thread_set_self_context(void *cxt, bool is_detach_external) { /* We use NtContinue to avoid privilege issues with NtSetContext */ nt_continue((CONTEXT *)cxt); @@ -5210,7 +5210,7 @@ thread_set_self_context(void *cxt) /* Takes a priv_mcontext_t */ void -thread_set_self_mcontext(priv_mcontext_t *mc) +thread_set_self_mcontext(priv_mcontext_t *mc, bool is_detach_external) { /* We can't use heap for our CONTEXT as we have no opportunity to free it. * We assume call paths can handle a large stack buffer as size something @@ -5232,7 +5232,7 @@ thread_set_self_mcontext(priv_mcontext_t *mc) cxt = nt_initialize_context(buf, bufsz, cxt_flags); /* need ss and cs for setting my own context */ mcontext_to_context(cxt, mc, true /* set_cur_seg */); - thread_set_self_context(cxt); + thread_set_self_context(cxt, false); ASSERT_NOT_REACHED(); } diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 6820150799a..3065e6adf8d 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -1414,11 +1414,11 @@ function(torun test key source native standalone_dr dr_ops exe_ops added_out pas if ("${runall}" MATCHES "") set(exe_ops "${exe_ops};-block") endif () -# if (LINUX) -# if ("${runall}" MATCHES "") -# set(exe_ops "${exe_ops};-v;") -# endif () -# endif () + if (LINUX) + if ("${runall}" MATCHES "") + set(exe_ops "${exe_ops};-v;") + endif () + endif () else () if ("${runall}" MATCHES "" OR "${runall}" MATCHES "") # For detach we use attachee to attach firstly, and "-detach" option is used @@ -2579,7 +2579,7 @@ endif (ANNOTATIONS AND NOT ARM) if (NOT ANDROID) # TODO i#38: Port test to Android. tobuild_ci(client.attach_test client-interface/attach_test.runall "" "" "") - if (WIN32) # ((LINUX OR WIN32) AND NOT RISCV64) + if ((LINUX OR WIN32) AND NOT RISCV64) # ((LINUX OR WIN32) AND NOT RISCV64) tobuild_ci(client.detach_test client-interface/detach_test.runall "" "" "") endif () if (UNIX) From f8fa6a4231921b1b00eb5704336c79e57a8c5572 Mon Sep 17 00:00:00 2001 From: wlmu Date: Wed, 20 Dec 2023 11:35:22 +0800 Subject: [PATCH 23/40] ignore on aarch64-native(like attach_test) --- suite/runsuite_wrapper.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/suite/runsuite_wrapper.pl b/suite/runsuite_wrapper.pl index a5169d3c258..74b94720ab9 100755 --- a/suite/runsuite_wrapper.pl +++ b/suite/runsuite_wrapper.pl @@ -340,6 +340,7 @@ 'code_api|linux.mangle_asynch' => 1, 'code_api,tracedump_text,tracedump_origins,syntax_intel|common.loglevel' => 1, # i#1807 'code_api|client.attach_test' => 1, # i#5740 + 'code_api|client.detach_test' => 1, # i#5740 'code_api|client.attach_blocking' => 1, # i#5740 'code_api|tool.drcacheoff.rseq' => 1, # i#5734 'code_api|tool.drcacheoff.windows-zlib' => 1, # i#5507 From 044242756b5e7cd70cba1bacd07b37ad239855bf Mon Sep 17 00:00:00 2001 From: wlmu Date: Wed, 20 Dec 2023 11:38:46 +0800 Subject: [PATCH 24/40] remove extra comment and macro --- core/optionsx.h | 5 ----- suite/tests/CMakeLists.txt | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/core/optionsx.h b/core/optionsx.h index 593456ec0fc..52f98c1f868 100644 --- a/core/optionsx.h +++ b/core/optionsx.h @@ -780,13 +780,8 @@ OPTION_DEFAULT(uint, max_pending_signals, 8, * mechanism that will set only the GPR's and will assume the target stack * is valid and its beyond-TOS slot can be clobbered. X86-only. */ -# ifdef LINUX OPTION_DEFAULT_INTERNAL(bool, use_sigreturn_setcontext, true, "use sigreturn to set a thread's context") -# else -OPTION_DEFAULT_INTERNAL(bool, use_sigreturn_setcontext, true, - "use sigreturn to set a thread's context") -# endif /* i#853: Use our all_memory_areas address space cache when possible. This * avoids expensive reads of /proc/pid/maps, but if the cache becomes stale, diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 3065e6adf8d..bc31dbdfe15 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -2579,7 +2579,7 @@ endif (ANNOTATIONS AND NOT ARM) if (NOT ANDROID) # TODO i#38: Port test to Android. tobuild_ci(client.attach_test client-interface/attach_test.runall "" "" "") - if ((LINUX OR WIN32) AND NOT RISCV64) # ((LINUX OR WIN32) AND NOT RISCV64) + if ((LINUX OR WIN32) AND NOT RISCV64) tobuild_ci(client.detach_test client-interface/detach_test.runall "" "" "") endif () if (UNIX) From 77a180dc85ab0fb9fe56f263766d2290008cd98f Mon Sep 17 00:00:00 2001 From: wlmu Date: Fri, 22 Dec 2023 10:04:39 +0800 Subject: [PATCH 25/40] fix: modify the frontend --- core/lib/globals_shared.h | 2 +- tools/drdeploy.c | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/core/lib/globals_shared.h b/core/lib/globals_shared.h index 06748b4d77b..4dbb74903a7 100644 --- a/core/lib/globals_shared.h +++ b/core/lib/globals_shared.h @@ -933,9 +933,9 @@ enum { #else NUDGE_NUDGER_FREE_STACK = 0x02, /* nudger will free the nudge thread's stack so the * nudge thread itself shouldn't */ +#endif NUDGE_FREE_ARG = 0x04, /* nudge arg is in a separate allocation and should * be freed by the nudge thread */ -#endif }; typedef struct { diff --git a/tools/drdeploy.c b/tools/drdeploy.c index fc050f21d36..eca1e865397 100644 --- a/tools/drdeploy.c +++ b/tools/drdeploy.c @@ -69,6 +69,9 @@ #include "dr_frontend.h" #ifdef LINUX +/* XXX: It would be cleaner to have a header for this and have nudgesig.c be in its + * own static library instead of compiled separately for the core and drdeploy. + */ extern bool create_nudge_signal_payload(siginfo_t *info DR_PARAM_OUT, uint action_mask, client_id_t client_id, uint flags, uint64 client_arg); @@ -1848,24 +1851,26 @@ _tmain(int argc, TCHAR *targv[]) } else if (action == action_unregister) { if (!unregister_proc(process, 0, global, dr_platform)) die(); - } -# ifndef WINDOWS -# ifdef LINUX - else if (detach_pid != 0) { + } else if (detach_pid != 0) { +# ifdef LINUX siginfo_t info; - uint action_mask = 0x04; + uint action_mask = NUDGE_FREE_ARG; client_id_t client_id = 0; uint64 client_arg = 0; 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 */ i = syscall(SYS_rt_sigqueueinfo, detach_pid, NUDGESIG_SIGNUM, &info); if (i < 0) fprintf(stderr, "nudge FAILED with error %d\n", i); +# elif defined(WINDOWS) + 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"); +# endif } -# endif +# ifndef WINDOWS else { usage(false, "no action specified"); } @@ -1905,10 +1910,6 @@ _tmain(int argc, TCHAR *targv[]) list_process(NULL, global, dr_platform, iter); dr_registered_process_iterator_stop(iter); } - } 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"); } # endif else if (!syswide_on && !syswide_off) { From 4be80a70e8c2bfcf7dd5418731504d0d3247b584 Mon Sep 17 00:00:00 2001 From: wlmu Date: Fri, 22 Dec 2023 10:10:22 +0800 Subject: [PATCH 26/40] fix: modify the frontend --- core/lib/globals_shared.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/lib/globals_shared.h b/core/lib/globals_shared.h index 4dbb74903a7..392b875b07d 100644 --- a/core/lib/globals_shared.h +++ b/core/lib/globals_shared.h @@ -934,8 +934,8 @@ enum { NUDGE_NUDGER_FREE_STACK = 0x02, /* nudger will free the nudge thread's stack so the * nudge thread itself shouldn't */ #endif - NUDGE_FREE_ARG = 0x04, /* nudge arg is in a separate allocation and should - * be freed by the nudge thread */ + NUDGE_FREE_ARG = 0x04, /* nudge arg is in a separate allocation and should + * be freed by the nudge thread */ }; typedef struct { From 824efb181002b4b51e16bbe8879adfdf5ad97131 Mon Sep 17 00:00:00 2001 From: wlmu Date: Fri, 22 Dec 2023 10:48:17 +0800 Subject: [PATCH 27/40] fix: modify the code on detach --- core/nudge.c | 15 ++++++++------- core/synch.c | 2 +- core/synch.h | 2 +- core/unix/os.c | 4 +--- core/unix/os_private.h | 2 +- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/core/nudge.c b/core/nudge.c index d96c9274d9d..e8ab897d92b 100644 --- a/core/nudge.c +++ b/core/nudge.c @@ -434,29 +434,30 @@ handle_nudge(dcontext_t *dcontext, nudge_arg_t *arg) SYSLOG_INTERNAL_WARNING("nudge reset ignored since resets are disabled"); } } -#ifdef WINDOWS +#if defined(WINDOWS) || defined(LINUX) /* The detach handler is last since in the common case it doesn't return. */ if (TEST(NUDGE_GENERIC(detach), nudge_action_mask)) { +# ifdef WINDOWS dcontext->free_app_stack = false; nudge_action_mask &= ~NUDGE_GENERIC(detach); detach_helper(DETACH_NORMAL_TYPE); - } -#endif -#ifdef LINUX - /* The detach handler is last since in the common case it doesn't return. */ - if (TEST(NUDGE_GENERIC(detach), nudge_action_mask)) { +# else nudge_action_mask &= ~NUDGE_GENERIC(detach); + /* This is not using stack_alloc() because we can't have this being cleaned up + * via normal cleanup paths. */ heap_error_code_t error_code_reserve, error_code_commit; void *d_r_detachstack = os_heap_reserve(NULL, DYNAMORIO_STACK_SIZE, &error_code_reserve, false); + /* XXX: This memory is not freed. */ if (!os_heap_commit(d_r_detachstack, DYNAMORIO_STACK_SIZE, MEMPROT_READ | MEMPROT_WRITE, &error_code_commit)) { ASSERT_NOT_REACHED(); } call_switch_stack(dcontext, (byte *)((ptr_uint_t)d_r_detachstack + DYNAMORIO_STACK_SIZE), - (void (*)(void *))detach_externally_on_linux, NULL, true); + (void (*)(void *))detach_externally_on_new_stack, NULL, true); ASSERT_NOT_REACHED(); +# endif } #endif } diff --git a/core/synch.c b/core/synch.c index 89ecdefde7a..0f51745d87c 100644 --- a/core/synch.c +++ b/core/synch.c @@ -2291,7 +2291,7 @@ detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats) } #ifdef LINUX void -detach_externally_on_linux() +detach_externally_on_new_stack() { dcontext_t *my_dcontext; priv_mcontext_t my_mcontext; diff --git a/core/synch.h b/core/synch.h index 9812a1494e0..461d429a625 100644 --- a/core/synch.h +++ b/core/synch.h @@ -265,7 +265,7 @@ detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats); #ifdef LINUX void -detach_externally_on_linux(); +detach_externally_on_new_stack(); #endif /*** exported for detach only ***/ diff --git a/core/unix/os.c b/core/unix/os.c index f2d4cc72950..6d7f85dcf88 100644 --- a/core/unix/os.c +++ b/core/unix/os.c @@ -3983,9 +3983,7 @@ thread_get_mcontext(thread_record_t *tr, priv_mcontext_t *mc) bool thread_get_nudged_mcontext(thread_record_t *tr, priv_mcontext_t *mc) { - /* PR 212090: only works when target is suspended by us, and - * we then take the signal context - */ + /* This only works for a thread that just received a nduge signal. */ os_thread_data_t *ostd = (os_thread_data_t *)tr->dcontext->os_field; ASSERT(ostd != NULL); ASSERT(ostd->nudged_sigcxt != NULL); diff --git a/core/unix/os_private.h b/core/unix/os_private.h index 3d850b13f9f..861cab9dc20 100644 --- a/core/unix/os_private.h +++ b/core/unix/os_private.h @@ -166,7 +166,7 @@ typedef struct _os_thread_data_t { sig_full_cxt_t *suspended_sigcxt; #ifdef LINUX - /* For detachment on Linux*/ + /* For detachment on Linux. */ sig_full_cxt_t *nudged_sigcxt; #endif From e18c7284b97bde8b0e2e1747c65c0dad11a1910c Mon Sep 17 00:00:00 2001 From: wlmu Date: Fri, 22 Dec 2023 10:58:44 +0800 Subject: [PATCH 28/40] fix: modify the frontend --- tools/drdeploy.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tools/drdeploy.c b/tools/drdeploy.c index eca1e865397..a6b5c49a480 100644 --- a/tools/drdeploy.c +++ b/tools/drdeploy.c @@ -1851,8 +1851,14 @@ _tmain(int argc, TCHAR *targv[]) } else if (action == action_unregister) { if (!unregister_proc(process, 0, global, dr_platform)) die(); - } else if (detach_pid != 0) { -# ifdef LINUX + } +# if defined(WINDOWS) || defined(LINUX) + else if (detach_pid != 0) { +# ifdef WINDOWS + 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"); +# else siginfo_t info; uint action_mask = NUDGE_FREE_ARG; client_id_t client_id = 0; @@ -1864,12 +1870,9 @@ _tmain(int argc, TCHAR *targv[]) i = syscall(SYS_rt_sigqueueinfo, detach_pid, NUDGESIG_SIGNUM, &info); if (i < 0) fprintf(stderr, "nudge FAILED with error %d\n", i); -# elif defined(WINDOWS) - 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"); -# endif +# endif } +# endif # ifndef WINDOWS else { usage(false, "no action specified"); From c7ff3caa7041960bee1a09131fc64f0fbb8cbc61 Mon Sep 17 00:00:00 2001 From: wlmu Date: Fri, 22 Dec 2023 13:23:57 +0800 Subject: [PATCH 29/40] fix: add helper functions --- core/synch.c | 198 +++++++++++++++++++-------------------------------- core/synch.h | 6 ++ 2 files changed, 80 insertions(+), 124 deletions(-) diff --git a/core/synch.c b/core/synch.c index 0f51745d87c..88f1f8be122 100644 --- a/core/synch.c +++ b/core/synch.c @@ -1965,6 +1965,76 @@ send_all_other_threads_native(void) return; } +void detach_set_mcontext_helper(thread_record_t *thread) +{ + priv_mcontext_t mc; + LOG(GLOBAL, LOG_ALL, 2, "Detach: translating " TIDFMT "\n", thread); + DEBUG_DECLARE(ok =) + thread_get_mcontext(thread, &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. + */ + "Detach: pre-xl8 pc=%p (%02x %02x %02x %02x %02x), xsp=%p " + "for thread " TIDFMT "\n", + mc.pc, *mc.pc, *(mc.pc + 1), *(mc.pc + 2), *(mc.pc + 3), *(mc.pc + 4), + mc.xsp, thread->id); + DEBUG_DECLARE(ok =) + translate_mcontext(thread, &mc, true /*restore mem*/, NULL /*f*/); + ASSERT(ok); + if (!thread->under_dynamo_control) { + LOG(GLOBAL, LOG_ALL, 1, + "Detach : thread " TIDFMT " already running natively\n", + thread->id); + /* we do need to restore the app ret addr, for native_exec */ + if (!DYNAMO_OPTION(thin_client) && DYNAMO_OPTION(native_exec) && + !vmvector_empty(native_exec_areas)) { + put_back_native_retaddrs(thread->dcontext); + } + } + detach_finalize_translation(thread, &mc); + 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)); + /* XXX case 7457: if the thread is suspended after it received a fault + * but before the kernel copied the faulting context to the user mode + * structures for the handler, it could result in a codemod exception + * that wouldn't happen natively! + */ + DEBUG_DECLARE(ok =) + thread_set_mcontext(thread, &mc); + ASSERT(ok); + /* i#249: restore app's PEB/TEB fields */ + IF_WINDOWS(restore_peb_pointer_for_thread(thread->dcontext)); +} + +void detach_cleanup_helper(thread_record_t *thread) +{ + DEBUG_DECLARE(int exit_res =) + dynamo_shared_exit(thread _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(); +} + void detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats) { @@ -1978,7 +2048,6 @@ detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats) bool *cleanup_tpc; #endif DEBUG_DECLARE(bool ok;) - DEBUG_DECLARE(int exit_res;) /* synch-all flags: */ uint flags = 0; @@ -2152,7 +2221,6 @@ detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats) 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]; @@ -2166,54 +2234,7 @@ detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats) LOG(GLOBAL, LOG_ALL, 2, "Detach: not translating " TIDFMT "\n", 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. - */ - "Detach: pre-xl8 pc=%p (%02x %02x %02x %02x %02x), xsp=%p " - "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) { - LOG(GLOBAL, LOG_ALL, 1, - "Detach : thread " TIDFMT " already running natively\n", - threads[i]->id); - /* we do need to restore the app ret addr, for native_exec */ - if (!DYNAMO_OPTION(thin_client) && DYNAMO_OPTION(native_exec) && - !vmvector_empty(native_exec_areas)) { - put_back_native_retaddrs(threads[i]->dcontext); - } - } - detach_finalize_translation(threads[i], &mc); - - 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)); - /* XXX case 7457: if the thread is suspended after it received a fault - * but before the kernel copied the faulting context to the user mode - * 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); - - /* i#249: restore app's PEB/TEB fields */ - IF_WINDOWS(restore_peb_pointer_for_thread(threads[i]->dcontext)); + detach_set_mcontext_helper(threads[i]); } /* Resumes the thread, which will do kernel-visible cleanup of * signal state. Resume happens within the synch_all region where @@ -2272,22 +2293,7 @@ detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats) SYSLOG_INTERNAL_INFO("Detaching from process, entering final cleanup"); if (drstats != NULL) stats_get_snapshot(drstats); - 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(); + detach_cleanup_helper(my_tr); } #ifdef LINUX void @@ -2300,7 +2306,6 @@ detach_externally_on_new_stack() int i, num_threads, my_idx = -1; 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 @@ -2373,7 +2378,6 @@ detach_externally_on_new_stack() 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]; @@ -2392,50 +2396,7 @@ detach_externally_on_new_stack() LOG(GLOBAL, LOG_ALL, 2, "Detach: not translating " TIDFMT "\n", 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. - */ - "Detach: pre-xl8 pc=%p (%02x %02x %02x %02x %02x), xsp=%p " - "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); - LOG(GLOBAL, LOG_ALL, 1, - "Detach : thread " TIDFMT " already running natively\n", - threads[i]->id); - /* we do need to restore the app ret addr, for native_exec */ - if (!DYNAMO_OPTION(thin_client) && DYNAMO_OPTION(native_exec) && - !vmvector_empty(native_exec_areas)) { - 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)); - /* XXX case 7457: if the thread is suspended after it received a fault - * but before the kernel copied the faulting context to the user mode - * 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); + detach_set_mcontext_helper(threads[i]); } /* Resumes the thread, which will do kernel-visible cleanup of * signal state. Resume happens within the synch_all region where @@ -2472,18 +2433,7 @@ detach_externally_on_new_stack() 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(); + detach_cleanup_helper(my_tr); thread_set_self_mcontext(&my_mcontext, true); } #endif diff --git a/core/synch.h b/core/synch.h index 461d429a625..ff470431783 100644 --- a/core/synch.h +++ b/core/synch.h @@ -260,6 +260,12 @@ translate_from_synchall_to_dispatch(thread_record_t *tr, void send_all_other_threads_native(void); +void +detach_cleanup_helper(thread_record_t *thread); + +void +detach_set_mcontext_helper(thread_record_t *thread); + void detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats); From 32306caff405b31c5cc447ec8b436963e0ca2df2 Mon Sep 17 00:00:00 2001 From: wlmu Date: Fri, 22 Dec 2023 13:31:02 +0800 Subject: [PATCH 30/40] fix: modify format --- core/synch.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/core/synch.c b/core/synch.c index 88f1f8be122..3897f4ed57d 100644 --- a/core/synch.c +++ b/core/synch.c @@ -1965,7 +1965,8 @@ send_all_other_threads_native(void) return; } -void detach_set_mcontext_helper(thread_record_t *thread) +void +detach_set_mcontext_helper(thread_record_t *thread) { priv_mcontext_t mc; LOG(GLOBAL, LOG_ALL, 2, "Detach: translating " TIDFMT "\n", thread); @@ -1984,14 +1985,13 @@ void detach_set_mcontext_helper(thread_record_t *thread) */ "Detach: pre-xl8 pc=%p (%02x %02x %02x %02x %02x), xsp=%p " "for thread " TIDFMT "\n", - mc.pc, *mc.pc, *(mc.pc + 1), *(mc.pc + 2), *(mc.pc + 3), *(mc.pc + 4), - mc.xsp, thread->id); + mc.pc, *mc.pc, *(mc.pc + 1), *(mc.pc + 2), *(mc.pc + 3), *(mc.pc + 4), mc.xsp, + thread->id); DEBUG_DECLARE(ok =) translate_mcontext(thread, &mc, true /*restore mem*/, NULL /*f*/); ASSERT(ok); if (!thread->under_dynamo_control) { - LOG(GLOBAL, LOG_ALL, 1, - "Detach : thread " TIDFMT " already running natively\n", + LOG(GLOBAL, LOG_ALL, 1, "Detach : thread " TIDFMT " already running natively\n", thread->id); /* we do need to restore the app ret addr, for native_exec */ if (!DYNAMO_OPTION(thin_client) && DYNAMO_OPTION(native_exec) && @@ -2015,7 +2015,8 @@ void detach_set_mcontext_helper(thread_record_t *thread) IF_WINDOWS(restore_peb_pointer_for_thread(thread->dcontext)); } -void detach_cleanup_helper(thread_record_t *thread) +void +detach_cleanup_helper(thread_record_t *thread) { DEBUG_DECLARE(int exit_res =) dynamo_shared_exit(thread _IF_WINDOWS(detach_stacked_callbacks)); @@ -2295,6 +2296,7 @@ detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats) stats_get_snapshot(drstats); detach_cleanup_helper(my_tr); } + #ifdef LINUX void detach_externally_on_new_stack() From 270a3e31fb391361511fe97e824b14787efa0906 Mon Sep 17 00:00:00 2001 From: wlmu Date: Fri, 22 Dec 2023 13:45:17 +0800 Subject: [PATCH 31/40] fix: add _IF_WINDOWS inside helper functions --- core/synch.c | 4 ++-- core/synch.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/synch.c b/core/synch.c index 3897f4ed57d..22b247b0a37 100644 --- a/core/synch.c +++ b/core/synch.c @@ -2016,7 +2016,7 @@ detach_set_mcontext_helper(thread_record_t *thread) } void -detach_cleanup_helper(thread_record_t *thread) +detach_cleanup_helper(thread_record_t *thread _IF_WINDOWS(bool detach_stacked_callbacks)) { DEBUG_DECLARE(int exit_res =) dynamo_shared_exit(thread _IF_WINDOWS(detach_stacked_callbacks)); @@ -2294,7 +2294,7 @@ detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats) SYSLOG_INTERNAL_INFO("Detaching from process, entering final cleanup"); if (drstats != NULL) stats_get_snapshot(drstats); - detach_cleanup_helper(my_tr); + detach_cleanup_helper(my_tr _IF_WINDOWS(detach_stacked_callbacks)); } #ifdef LINUX diff --git a/core/synch.h b/core/synch.h index ff470431783..29e7eee2916 100644 --- a/core/synch.h +++ b/core/synch.h @@ -261,7 +261,7 @@ void send_all_other_threads_native(void); void -detach_cleanup_helper(thread_record_t *thread); +detach_cleanup_helper(thread_record_t *thread _IF_WINDOWS(bool detach_stacked_callbacks)); void detach_set_mcontext_helper(thread_record_t *thread); From 33c74bea7fa3a1faa3347c6c68f8e134662e17ce Mon Sep 17 00:00:00 2001 From: wlmu Date: Fri, 22 Dec 2023 13:49:27 +0800 Subject: [PATCH 32/40] fix: modify format --- core/synch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/synch.c b/core/synch.c index 22b247b0a37..b530e840f1e 100644 --- a/core/synch.c +++ b/core/synch.c @@ -1970,7 +1970,7 @@ detach_set_mcontext_helper(thread_record_t *thread) { priv_mcontext_t mc; LOG(GLOBAL, LOG_ALL, 2, "Detach: translating " TIDFMT "\n", thread); - DEBUG_DECLARE(ok =) + DEBUG_DECLARE(bool ok =) thread_get_mcontext(thread, &mc); ASSERT(ok); /* For a thread at a syscall, we use SA_RESTART for our suspend signal, @@ -2001,7 +2001,7 @@ detach_set_mcontext_helper(thread_record_t *thread) } detach_finalize_translation(thread, &mc); LOG(GLOBAL, LOG_ALL, 1, "Detach: pc=" PFX " for thread " TIDFMT "\n", mc.pc, - threads[i]->id); + thread->id); ASSERT(!is_dynamo_address(mc.pc) && !in_fcache(mc.pc)); /* XXX case 7457: if the thread is suspended after it received a fault * but before the kernel copied the faulting context to the user mode From f97f6e2a656b66e28ff0403d3d3149567452f020 Mon Sep 17 00:00:00 2001 From: wlmu Date: Fri, 22 Dec 2023 13:51:56 +0800 Subject: [PATCH 33/40] fix: modify format --- core/synch.c | 1 - 1 file changed, 1 deletion(-) diff --git a/core/synch.c b/core/synch.c index b530e840f1e..532c744b886 100644 --- a/core/synch.c +++ b/core/synch.c @@ -2048,7 +2048,6 @@ detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats) bool detach_stacked_callbacks; bool *cleanup_tpc; #endif - DEBUG_DECLARE(bool ok;) /* synch-all flags: */ uint flags = 0; From dcd7280616b7db624764ae7698dcb4d49b81758a Mon Sep 17 00:00:00 2001 From: wlmu Date: Fri, 22 Dec 2023 15:09:40 +0800 Subject: [PATCH 34/40] fix: modify the test suite --- .../tests/client-interface/detach_test.dll.c | 2 ++ suite/tests/runall.cmake | 35 +------------------ 2 files changed, 3 insertions(+), 34 deletions(-) diff --git a/suite/tests/client-interface/detach_test.dll.c b/suite/tests/client-interface/detach_test.dll.c index 71ace838031..0740832f781 100644 --- a/suite/tests/client-interface/detach_test.dll.c +++ b/suite/tests/client-interface/detach_test.dll.c @@ -44,6 +44,8 @@ static bool saw_attach_event = false; static void dr_exit(void) { + if (!saw_attach_event) + dr_fprintf(STDERR, "Error: never saw attach event!\n"); #ifdef WINDOWS dr_fprintf(STDERR, "done\n"); #else diff --git a/suite/tests/runall.cmake b/suite/tests/runall.cmake index 502e777f4c6..08eea9ed4d5 100644 --- a/suite/tests/runall.cmake +++ b/suite/tests/runall.cmake @@ -273,40 +273,7 @@ if ("${orig_nudge}" MATCHES "-client") message(FATAL_ERROR "Timed out waiting for more output") endif () endwhile() -elseif ("${orig_nudge}" MATCHES "") - # Wait until attached. - set(iters 0) - while (NOT "${output}" MATCHES "attach\n") - do_sleep(0.1) - file(READ "${out}" output) - math(EXPR iters "${iters}+1") - if (${iters} GREATER ${MAX_ITERS}) - kill_background_process(ON) - message(FATAL_ERROR "Timed out waiting for attach") - endif () - endwhile() - # Wait until thread init. - set(iters 0) - while (NOT "${output}" MATCHES "thread init\n") - do_sleep(0.1) - file(READ "${out}" output) - math(EXPR iters "${iters}+1") - if (${iters} GREATER ${MAX_ITERS}) - kill_background_process(ON) - message(FATAL_ERROR "Timed out waiting for thread init") - endif () - endwhile() -elseif ("${orig_nudge}" MATCHES "") - set(iters 0) - while (NOT "${output}" MATCHES "detach\n") - do_sleep(0.1) - file(READ "${out}" output) - math(EXPR iters "${iters}+1") - if (${iters} GREATER ${MAX_ITERS}) - kill_background_process(ON) - message(FATAL_ERROR "Timed out waiting for detach") - endif () - endwhile() +elseif ("${orig_nudge}" MATCHES "" OR "${orig_nudge}" MATCHES "") # Wait until thread init. set(iters 0) while (NOT "${output}" MATCHES "thread init\n") From a871d8a2fe4eea398f01735b979737d3a394d8ff Mon Sep 17 00:00:00 2001 From: wlmu Date: Fri, 22 Dec 2023 15:12:48 +0800 Subject: [PATCH 35/40] fix: modify the test suite --- suite/tests/client-interface/detach_test.dll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suite/tests/client-interface/detach_test.dll.c b/suite/tests/client-interface/detach_test.dll.c index 0740832f781..a6d4cc9c3ca 100644 --- a/suite/tests/client-interface/detach_test.dll.c +++ b/suite/tests/client-interface/detach_test.dll.c @@ -49,7 +49,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 } From 9eea0c4ed6e94838b10075eb3a41f2eca8710efb Mon Sep 17 00:00:00 2001 From: wlmu Date: Sat, 30 Dec 2023 08:12:52 +0800 Subject: [PATCH 36/40] style: modfiy detach helpers --- core/synch.c | 4 ++-- core/synch.h | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/core/synch.c b/core/synch.c index 532c744b886..3af5add4afe 100644 --- a/core/synch.c +++ b/core/synch.c @@ -1965,7 +1965,7 @@ send_all_other_threads_native(void) return; } -void +static void detach_set_mcontext_helper(thread_record_t *thread) { priv_mcontext_t mc; @@ -2015,7 +2015,7 @@ detach_set_mcontext_helper(thread_record_t *thread) IF_WINDOWS(restore_peb_pointer_for_thread(thread->dcontext)); } -void +static void detach_cleanup_helper(thread_record_t *thread _IF_WINDOWS(bool detach_stacked_callbacks)) { DEBUG_DECLARE(int exit_res =) diff --git a/core/synch.h b/core/synch.h index 29e7eee2916..461d429a625 100644 --- a/core/synch.h +++ b/core/synch.h @@ -260,12 +260,6 @@ translate_from_synchall_to_dispatch(thread_record_t *tr, void send_all_other_threads_native(void); -void -detach_cleanup_helper(thread_record_t *thread _IF_WINDOWS(bool detach_stacked_callbacks)); - -void -detach_set_mcontext_helper(thread_record_t *thread); - void detach_on_permanent_stack(bool internal, bool do_cleanup, dr_stats_t *drstats); From 36b9f943ebf18fbe3a2ef8b88c97942f5a47ef1a Mon Sep 17 00:00:00 2001 From: wlmu Date: Sat, 30 Dec 2023 10:02:37 +0800 Subject: [PATCH 37/40] kill background process forcely --- suite/tests/runall.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suite/tests/runall.cmake b/suite/tests/runall.cmake index 08eea9ed4d5..97a101d8c15 100644 --- a/suite/tests/runall.cmake +++ b/suite/tests/runall.cmake @@ -314,7 +314,7 @@ if ("${orig_nudge}" MATCHES "") endwhile() endif () -kill_background_process(OFF) +kill_background_process(ON) if (NOT "${fail_msg}" STREQUAL "") message(FATAL_ERROR "${fail_msg}") From b150436d824b5786e8c2c765613a45ac07741a65 Mon Sep 17 00:00:00 2001 From: wlmu Date: Sat, 30 Dec 2023 10:47:26 +0800 Subject: [PATCH 38/40] rollback: kill background process forcely --- suite/tests/runall.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suite/tests/runall.cmake b/suite/tests/runall.cmake index 97a101d8c15..08eea9ed4d5 100644 --- a/suite/tests/runall.cmake +++ b/suite/tests/runall.cmake @@ -314,7 +314,7 @@ if ("${orig_nudge}" MATCHES "") endwhile() endif () -kill_background_process(ON) +kill_background_process(OFF) if (NOT "${fail_msg}" STREQUAL "") message(FATAL_ERROR "${fail_msg}") From 351b0e062e769e7863f973a2f7013add959de210 Mon Sep 17 00:00:00 2001 From: wlmu Date: Sat, 30 Dec 2023 11:20:36 +0800 Subject: [PATCH 39/40] modify the test suite --- suite/tests/CMakeLists.txt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 4d5d65f7a43..7a81e89cc70 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -1411,14 +1411,12 @@ function(torun test key source native standalone_dr dr_ops exe_ops added_out pas # is failing). set(exe_ops "${exe_ops};-v;-attach") endif () + if ("${runall}" MATCHES "") + set(exe_ops "${exe_ops};-v;") + endif () if ("${runall}" MATCHES "") set(exe_ops "${exe_ops};-block") endif () - if (LINUX) - if ("${runall}" MATCHES "") - set(exe_ops "${exe_ops};-v;") - endif () - endif () else () if ("${runall}" MATCHES "" OR "${runall}" MATCHES "") # For detach we use attachee to attach firstly, and "-detach" option is used From 05c448131f79993e96543e99306e4bb30b91af20 Mon Sep 17 00:00:00 2001 From: wlmu Date: Sat, 30 Dec 2023 11:27:17 +0800 Subject: [PATCH 40/40] test again --- suite/tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 7a81e89cc70..3b1f860e30e 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -3006,7 +3006,7 @@ if (X86 OR AARCH64) "-early_inject" "") append_pure_asm_app_link_flags(allasm_repstr) endif () - endif() + endif () endif () if (NOT RISCV64)