diff --git a/pwndbg/dbg/lldb/repl/proc.py b/pwndbg/dbg/lldb/repl/proc.py index 63d433074..79ad9cbf6 100644 --- a/pwndbg/dbg/lldb/repl/proc.py +++ b/pwndbg/dbg/lldb/repl/proc.py @@ -233,16 +233,20 @@ class ProcessDriver: sys.stdout.buffer.write(out.encode(sys.stdout.encoding, errors="backslashreplace")) print() + if self.debug: + print(f"[-] ProcessDriver: LLDB Command Status: {ret.GetStatus():#x}") + # Only call _run_until_next_stop() if the command started the process. + start_expected = True s = ret.GetStatus() if s == lldb.eReturnStatusFailed: - return + start_expected = False if s == lldb.eReturnStatusQuit: - return + start_expected = False if s == lldb.eReturnStatusSuccessFinishResult: - return + start_expected = False if s == lldb.eReturnStatusSuccessFinishNoResult: - return + start_expected = False # It's important to note that we can't trigger the resumed event # now because the process might've already started, and LLDB @@ -253,7 +257,16 @@ class ProcessDriver: # # TODO/FIXME: Find a way to trigger the continued event before the process is resumed in LLDB - self._run_until_next_stop() + if not start_expected: + # Even if the current process has not been resumed, LLDB might + # have posted process events for us to handle. Do so now, but + # stop right away if there is nothing for us in the listener. + # + # This lets us handle things like `detach`, which would otherwise + # pass as a command that does not change process state at all. + self._run_until_next_stop(first_timeout=0, only_if_started=True) + else: + self._run_until_next_stop() def run_coroutine(self, coroutine: Coroutine[Any, Any, None]) -> bool: """