diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -2075,6 +2075,10 @@ void UpdateThreadListIfNeeded(); + /// Method to be invoked to signal that the underlying process has exec'ed + /// and some clean up should be done to prepare for the new process state. + void ProcessDidExec(); + ThreadList &GetThreadList() { return m_thread_list; } // When ExtendedBacktraces are requested, the HistoryThreads that are created diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -2611,8 +2611,7 @@ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); LLDB_LOGF(log, "ProcessGDBRemote::SetLastStopPacket () - detected exec"); - m_thread_list_real.Clear(); - m_thread_list.Clear(); + ProcessDidExec(); BuildDynamicRegisterInfo(true); m_gdb_comm.ResetDiscoverableSettings(did_exec); } diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -1248,6 +1248,12 @@ return false; } +void Process::ProcessDidExec() { + m_thread_list_real.Clear(); + m_thread_list.Clear(); + m_thread_plans.Clear(); +} + void Process::UpdateThreadListIfNeeded() { const uint32_t stop_id = GetStopID(); if (m_thread_list.GetSize(false) == 0 || diff --git a/lldb/test/API/functionalities/exec/TestExec.py b/lldb/test/API/functionalities/exec/TestExec.py --- a/lldb/test/API/functionalities/exec/TestExec.py +++ b/lldb/test/API/functionalities/exec/TestExec.py @@ -24,7 +24,8 @@ @skipIfAsan # rdar://problem/43756823 @skipIfWindows def test_hitting_exec (self): - self.do_test(False) + self.do_test(False, False) + self.do_test(False, True) @expectedFailureAll(archs=['i386'], oslist=no_match(["freebsd"]), @@ -34,9 +35,10 @@ @skipIfAsan # rdar://problem/43756823 @skipIfWindows def test_skipping_exec (self): - self.do_test(True) + self.do_test(True, False) + self.do_test(True, True) - def do_test(self, skip_exec): + def do_test(self, skip_exec, should_attach): self.build() exe = self.getBuildArtifact("a.out") secondprog = self.getBuildArtifact("secondprog") @@ -52,10 +54,31 @@ 'Set breakpoint 2 here', lldb.SBFileSpec("secondprog.cpp", False)) self.assertTrue(breakpoint2, VALID_BREAKPOINT) - # Launch the process - process = target.LaunchSimple( - None, None, self.get_process_working_directory()) - self.assertTrue(process, PROCESS_IS_VALID) + if not should_attach: + # Launch the process + process = target.LaunchSimple( + None, None, self.get_process_working_directory()) + self.assertTrue(process, PROCESS_IS_VALID) + else: + # Spawn the process and attach to it + popen = subprocess.Popen(exe, env={"LLDB_TEST_SHOULD_ATTACH": "1"}) + if self.TraceOn(): + print("Will attach to PID" + str(popen.pid)) + + error = lldb.SBError() + attach_info = lldb.SBAttachInfo(popen.pid) + process = target.Attach(attach_info, error) + self.assertTrue(error.Success() and process) + + # In some systems lldb will stop for a second time at the SIGSTOP attach + # point. That might be need to be fixed in a different patch. + # To avoid making guesses, we continue until we hit breakpoint1. + while True: + error = process.Continue() + self.assertTrue(error.Success()) + threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint1) + if len(threads) > 0: + break if self.TraceOn(): self.runCmd("settings show target.process.stop-on-exec", check=False) diff --git a/lldb/test/API/functionalities/exec/main.cpp b/lldb/test/API/functionalities/exec/main.cpp --- a/lldb/test/API/functionalities/exec/main.cpp +++ b/lldb/test/API/functionalities/exec/main.cpp @@ -1,5 +1,6 @@ #define _POSIX_C_SOURCE 200809L +#include #include #include #include @@ -8,6 +9,9 @@ #include int main(int argc, char const **argv) { + if (getenv("LLDB_TEST_SHOULD_ATTACH") != nullptr) + raise(SIGSTOP); + char *buf = strdup(argv[0]); // Set breakpoint 1 here std::string directory_name(::dirname(buf));