mgorny updated this revision to Diff 339257.
mgorny retitled this revision from "[lldb] [Process/Linux] Report fork/vfork
stop reason to client" to "[lldb] [Process/Linux] Report fork/vfork stop
reason".
mgorny edited the summary of this revision.
mgorny added a comment.
Now includes lldb-server tests.
@labath, please let me know if I should merge this with previous patches, or if
it's fine to commit in split.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D100208/new/
https://reviews.llvm.org/D100208
Files:
lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py
lldb/test/API/tools/lldb-server/main.cpp
Index: lldb/test/API/tools/lldb-server/main.cpp
===================================================================
--- lldb/test/API/tools/lldb-server/main.cpp
+++ lldb/test/API/tools/lldb-server/main.cpp
@@ -28,6 +28,8 @@
static const char *const GET_DATA_ADDRESS_PREFIX = "get-data-address-hex:";
static const char *const GET_STACK_ADDRESS_COMMAND = "get-stack-address-hex:";
static const char *const GET_HEAP_ADDRESS_COMMAND = "get-heap-address-hex:";
+static const char *const FORK_COMMAND = "fork";
+static const char *const VFORK_COMMAND = "vfork";
static const char *const GET_CODE_ADDRESS_PREFIX = "get-code-address-hex:";
static const char *const CALL_FUNCTION_PREFIX = "call-function:";
@@ -225,7 +227,13 @@
sig_result = signal(SIGSEGV, signal_handler);
if (sig_result == SIG_ERR) {
- fprintf(stderr, "failed to set SIGUSR1 handler: errno=%d\n", errno);
+ fprintf(stderr, "failed to set SIGSEGV handler: errno=%d\n", errno);
+ exit(1);
+ }
+
+ sig_result = signal(SIGCHLD, SIG_IGN);
+ if (sig_result == SIG_ERR) {
+ fprintf(stderr, "failed to set SIGCHLD handler: errno=%d\n", errno);
exit(1);
}
#endif
@@ -311,6 +319,12 @@
}
if (func_p)
func_p();
+ } else if (!std::strcmp(argv[i], FORK_COMMAND)) {
+ if (fork() == 0)
+ _exit(0);
+ } else if (!std::strcmp(argv[i], VFORK_COMMAND)) {
+ if (vfork() == 0)
+ _exit(0);
} else if (std::strstr(argv[i], THREAD_PREFIX)) {
// Check if we're creating a new thread.
if (std::strstr(argv[i] + strlen(THREAD_PREFIX), THREAD_COMMAND_NEW)) {
Index: lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py
===================================================================
--- /dev/null
+++ lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py
@@ -0,0 +1,58 @@
+import gdbremote_testcase
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestGdbRemoteFork(gdbremote_testcase.GdbRemoteTestCaseBase):
+ mydir = TestBase.compute_mydir(__file__)
+
+ def fork_and_detach_test(self, variant):
+ self.build()
+ self.prep_debug_monitor_and_inferior(inferior_args=[variant])
+ self.add_qSupported_packets(["{}-events+".format(variant)])
+ ret = self.expect_gdbremote_sequence()
+ self.assertIn("{}-events+".format(variant), ret["qSupported_response"])
+ self.reset_test_sequence()
+
+ # continue and expect fork
+ fork_regex = "[$]T.*;{}:p([0-9a-f]*)[.]([0-9a-f]*).*".format(variant)
+ self.test_sequence.add_log_lines([
+ "read packet: $c#00",
+ {"direction": "send", "regex": fork_regex,
+ "capture": {1: "pid", 2: "tid"}},
+ ], True)
+ ret = self.expect_gdbremote_sequence()
+ pid = int(ret["pid"], 16)
+ self.reset_test_sequence()
+
+ # detach the forked child
+ self.test_sequence.add_log_lines([
+ "read packet: $D;{:x}#00".format(pid),
+ {"direction": "send", "regex": r"[$]OK#.*"},
+ ], True)
+ ret = self.expect_gdbremote_sequence()
+ self.reset_test_sequence()
+
+ @skipIf(oslist=no_match(["linux"]))
+ def test_fork(self):
+ self.fork_and_detach_test("fork")
+
+ # resume the parent
+ self.test_sequence.add_log_lines([
+ "read packet: $c#00",
+ {"direction": "send", "regex": r"[$]W00#.*"},
+ ], True)
+ self.expect_gdbremote_sequence()
+
+ @skipIf(oslist=no_match(["linux"]))
+ def test_vfork(self):
+ self.fork_and_detach_test("vfork")
+
+ # resume the parent
+ self.test_sequence.add_log_lines([
+ "read packet: $c#00",
+ {"direction": "send", "regex": r"[$]T.*vforkdone.*"},
+ "read packet: $c#00",
+ {"direction": "send", "regex": r"[$]W00#.*"},
+ ], True)
+ self.expect_gdbremote_sequence()
Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
+++ lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
@@ -85,6 +85,12 @@
void SetStoppedByTrace();
+ void SetStoppedByFork(lldb::pid_t child_pid);
+
+ void SetStoppedByVFork(lldb::pid_t child_pid);
+
+ void SetStoppedByVForkDone();
+
void SetStoppedWithNoReason();
void SetStoppedByProcessorTrace(llvm::StringRef description);
Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -394,6 +394,28 @@
m_stop_info.details.signal.signo = SIGTRAP;
}
+void NativeThreadLinux::SetStoppedByFork(lldb::pid_t child_pid) {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonFork;
+ m_stop_info.details.fork.child_pid = child_pid;
+ m_stop_info.details.fork.child_tid = child_pid;
+}
+
+void NativeThreadLinux::SetStoppedByVFork(lldb::pid_t child_pid) {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonVFork;
+ m_stop_info.details.fork.child_pid = child_pid;
+ m_stop_info.details.fork.child_tid = child_pid;
+}
+
+void NativeThreadLinux::SetStoppedByVForkDone() {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonVForkDone;
+}
+
void NativeThreadLinux::SetStoppedWithNoReason() {
SetStopped();
Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -49,6 +49,8 @@
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
MainLoop &mainloop) const override;
+
+ Extension GetSupportedExtensions() const override;
};
// NativeProcessProtocol Interface
@@ -136,6 +138,7 @@
private:
MainLoop::SignalHandleUP m_sigchld_handle;
ArchSpec m_arch;
+ MainLoop& m_main_loop;
LazyBool m_supports_mem_region = eLazyBoolCalculate;
std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -281,6 +281,11 @@
pid, -1, native_delegate, Info.GetArchitecture(), mainloop, *tids_or));
}
+NativeProcessLinux::Extension
+NativeProcessLinux::Factory::GetSupportedExtensions() const {
+ return Extension::fork | Extension::vfork;
+}
+
// Public Instance Methods
NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd,
@@ -288,7 +293,7 @@
const ArchSpec &arch, MainLoop &mainloop,
llvm::ArrayRef<::pid_t> tids)
: NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch),
- m_intel_pt_manager(pid) {
+ m_main_loop(mainloop), m_intel_pt_manager(pid) {
if (m_terminal_fd != -1) {
Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
assert(status.Success());
@@ -647,7 +652,12 @@
}
case (SIGTRAP | (PTRACE_EVENT_VFORK_DONE << 8)): {
- ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER);
+ if ((m_enabled_extensions & Extension::vfork) == Extension::vfork) {
+ thread.SetStoppedByVForkDone();
+ StopRunningThreads(thread.GetID());
+ }
+ else
+ ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER);
break;
}
@@ -912,16 +922,28 @@
LLVM_FALLTHROUGH;
case PTRACE_EVENT_FORK:
case PTRACE_EVENT_VFORK: {
- MainLoop unused_loop;
- NativeProcessLinux child_process{static_cast<::pid_t>(child_pid),
- m_terminal_fd,
- m_delegate,
- m_arch,
- unused_loop,
- {static_cast<::pid_t>(child_pid)}};
- child_process.Detach();
- ResumeThread(*parent_thread, parent_thread->GetState(),
- LLDB_INVALID_SIGNAL_NUMBER);
+ bool is_vfork = clone_info->event == PTRACE_EVENT_VFORK;
+ NativeProcessLinux *child_process = new NativeProcessLinux(
+ static_cast<::pid_t>(child_pid), m_terminal_fd, m_delegate, m_arch,
+ m_main_loop, {static_cast<::pid_t>(child_pid)});
+ if (!is_vfork)
+ child_process->m_software_breakpoints = m_software_breakpoints;
+
+ std::unique_ptr<NativeProcessProtocol> child_process_up{child_process};
+ Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork;
+ if ((m_enabled_extensions & expected_ext) == expected_ext) {
+ m_delegate.NewSubprocess(this, std::move(child_process_up));
+ // NB: non-vfork clone() is reported as fork
+ if (is_vfork)
+ parent_thread->SetStoppedByVFork(child_pid);
+ else
+ parent_thread->SetStoppedByFork(child_pid);
+ StopRunningThreads(parent_thread->GetID());
+ } else {
+ child_process_up->Detach();
+ ResumeThread(*parent_thread, parent_thread->GetState(),
+ LLDB_INVALID_SIGNAL_NUMBER);
+ }
break;
}
default:
Index: lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
+++ lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
@@ -835,9 +835,10 @@
"send packet: $OK#00",
], True)
- def add_qSupported_packets(self):
+ def add_qSupported_packets(self, client_features=[]):
+ features = ''.join(';' + x for x in client_features)
self.test_sequence.add_log_lines(
- ["read packet: $qSupported#00",
+ ["read packet: $qSupported{}#00".format(features),
{"direction": "send", "regex": r"^\$(.*)#[0-9a-fA-F]{2}", "capture": {1: "qSupported_response"}},
], True)
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits