[Lldb-commits] [lldb] 1e74e5e - [lldb] [llgs] Implement qXfer:siginfo:read
Michał Górny via lldb-commits
lldb-commits at lists.llvm.org
Thu Jan 13 02:24:56 PST 2022
Author: Michał Górny
Date: 2022-01-13T11:24:36+01:00
New Revision: 1e74e5e9e3b903af568de834deab29fa342c665a
URL: https://github.com/llvm/llvm-project/commit/1e74e5e9e3b903af568de834deab29fa342c665a
DIFF: https://github.com/llvm/llvm-project/commit/1e74e5e9e3b903af568de834deab29fa342c665a.diff
LOG: [lldb] [llgs] Implement qXfer:siginfo:read
Implement the qXfer:siginfo:read that is used to read the siginfo_t
(extended signal information) for the current thread. This is currently
implemented on FreeBSD and Linux.
Differential Revision: https://reviews.llvm.org/D117113
Added:
Modified:
lldb/include/lldb/Host/common/NativeProcessProtocol.h
lldb/include/lldb/Host/common/NativeThreadProtocol.h
lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp
lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp
lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h
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/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
Removed:
################################################################################
diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
index 7c3458527616..c7494ba6b195 100644
--- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -204,7 +204,7 @@ class NativeProcessProtocol {
void SetCurrentThreadID(lldb::tid_t tid) { m_current_thread_id = tid; }
- lldb::tid_t GetCurrentThreadID() { return m_current_thread_id; }
+ lldb::tid_t GetCurrentThreadID() const { return m_current_thread_id; }
NativeThreadProtocol *GetCurrentThread() {
return GetThreadByID(m_current_thread_id);
@@ -251,8 +251,9 @@ class NativeProcessProtocol {
libraries_svr4 = (1u << 5),
memory_tagging = (1u << 6),
savecore = (1u << 7),
+ siginfo_read = (1u << 8),
- LLVM_MARK_AS_BITMASK_ENUM(savecore)
+ LLVM_MARK_AS_BITMASK_ENUM(siginfo_read)
};
class Factory {
diff --git a/lldb/include/lldb/Host/common/NativeThreadProtocol.h b/lldb/include/lldb/Host/common/NativeThreadProtocol.h
index 5cf26bd95939..35ccc48d62d8 100644
--- a/lldb/include/lldb/Host/common/NativeThreadProtocol.h
+++ b/lldb/include/lldb/Host/common/NativeThreadProtocol.h
@@ -12,9 +12,13 @@
#include <memory>
#include "lldb/Host/Debug.h"
+#include "lldb/Utility/UnimplementedError.h"
#include "lldb/lldb-private-forward.h"
#include "lldb/lldb-types.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+
namespace lldb_private {
// NativeThreadProtocol
class NativeThreadProtocol {
@@ -47,6 +51,11 @@ class NativeThreadProtocol {
virtual Status RemoveHardwareBreakpoint(lldb::addr_t addr) = 0;
+ virtual llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+ GetSiginfo() const {
+ return llvm::make_error<UnimplementedError>();
+ }
+
protected:
NativeProcessProtocol &m_process;
lldb::tid_t m_tid;
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
index 97a7543b5c1e..ef67619e4835 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
@@ -851,6 +851,7 @@ def add_qSupported_packets(self, client_features=[]):
"qXfer:libraries:read",
"qXfer:libraries-svr4:read",
"qXfer:features:read",
+ "qXfer:siginfo:read",
"qEcho",
"QPassSignals",
"multiprocess",
diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp
index 7290d300a41f..25fc7028216e 100644
--- a/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp
@@ -135,7 +135,8 @@ NativeProcessFreeBSD::Factory::GetSupportedExtensions() const {
Extension::savecore |
#endif
Extension::multiprocess | Extension::fork | Extension::vfork |
- Extension::pass_signals | Extension::auxv | Extension::libraries_svr4;
+ Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 |
+ Extension::siginfo_read;
}
// Public Instance Methods
diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp
index 80b3527aebce..20e9d6cfcd7f 100644
--- a/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp
@@ -313,3 +313,27 @@ NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) {
}
return s;
}
+
+llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+NativeThreadFreeBSD::GetSiginfo() const {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+
+ struct ptrace_lwpinfo info;
+ const auto siginfo_err = NativeProcessFreeBSD::PtraceWrapper(
+ PT_LWPINFO, GetID(), &info, sizeof(info));
+ if (siginfo_err.Fail()) {
+ LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
+ return siginfo_err.ToError();
+ }
+
+ if (info.pl_event != PL_EVENT_SIGNAL)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Thread not signaled");
+ if (!(info.pl_flags & PL_FLAG_SI))
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No siginfo for thread");
+
+ return llvm::MemoryBuffer::getMemBufferCopy(
+ llvm::StringRef(reinterpret_cast<const char *>(&info.pl_siginfo),
+ sizeof(info.pl_siginfo)));
+}
diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h b/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h
index 3ec6daa409e4..6294a7a70963 100644
--- a/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h
+++ b/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h
@@ -47,6 +47,9 @@ class NativeThreadFreeBSD : public NativeThreadProtocol {
Status RemoveHardwareBreakpoint(lldb::addr_t addr) override;
+ llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+ GetSiginfo() const override;
+
private:
// Interface for friend classes
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index 02d2b33c4273..74366d720814 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -292,7 +292,8 @@ NativeProcessLinux::Extension
NativeProcessLinux::Factory::GetSupportedExtensions() const {
NativeProcessLinux::Extension supported =
Extension::multiprocess | Extension::fork | Extension::vfork |
- Extension::pass_signals | Extension::auxv | Extension::libraries_svr4;
+ Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 |
+ Extension::siginfo_read;
#ifdef __aarch64__
// At this point we do not have a process so read auxv directly.
@@ -1622,7 +1623,7 @@ Status NativeProcessLinux::WriteMemory(lldb::addr_t addr, const void *buf,
return error;
}
-Status NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo) {
+Status NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo) const {
return PtraceWrapper(PTRACE_GETSIGINFO, tid, nullptr, siginfo);
}
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
index 65f455a10968..407062ad0b46 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -135,6 +135,10 @@ class NativeProcessLinux : public NativeProcessELF,
bool SupportHardwareSingleStepping() const;
+ /// Writes a siginfo_t structure corresponding to the given thread ID to the
+ /// memory region pointed to by \p siginfo.
+ Status GetSignalInfo(lldb::tid_t tid, void *siginfo) const;
+
protected:
llvm::Expected<llvm::ArrayRef<uint8_t>>
GetSoftwareBreakpointTrapOpcode(size_t size_hint) override;
@@ -205,10 +209,6 @@ class NativeProcessLinux : public NativeProcessELF,
/// stopping for threads being destroyed.
Status NotifyTracersOfThreadDestroyed(lldb::tid_t tid);
- /// Writes a siginfo_t structure corresponding to the given thread ID to the
- /// memory region pointed to by \p siginfo.
- Status GetSignalInfo(lldb::tid_t tid, void *siginfo);
-
/// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
/// corresponding to the given thread ID to the memory pointed to by @p
/// message.
diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
index a7e4e9b13ff0..50d8ce9c161c 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -536,3 +536,18 @@ void NativeThreadLinux::MaybeLogStateChange(lldb::StateType new_state) {
NativeProcessLinux &NativeThreadLinux::GetProcess() {
return static_cast<NativeProcessLinux &>(m_process);
}
+
+const NativeProcessLinux &NativeThreadLinux::GetProcess() const {
+ return static_cast<const NativeProcessLinux &>(m_process);
+}
+
+llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+NativeThreadLinux::GetSiginfo() const {
+ auto siginfo_buf =
+ llvm::WritableMemoryBuffer::getNewUninitMemBuffer(sizeof(siginfo_t));
+ Status error =
+ GetProcess().GetSignalInfo(GetID(), siginfo_buf->getBufferStart());
+ if (!error.Success())
+ return error.ToError();
+ return siginfo_buf;
+}
diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
index c18665b0107e..030a4012f46a 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
@@ -55,6 +55,11 @@ class NativeThreadLinux : public NativeThreadProtocol {
NativeProcessLinux &GetProcess();
+ const NativeProcessLinux &GetProcess() const;
+
+ llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+ GetSiginfo() const override;
+
private:
// Interface for friend classes
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index 30f14a52dfb5..a6749274ca99 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -2920,6 +2920,18 @@ GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object,
return std::move(*buffer_or_error);
}
+ if (object == "siginfo") {
+ NativeThreadProtocol *thread = m_current_process->GetCurrentThread();
+ if (!thread)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "no current thread");
+
+ auto buffer_or_error = thread->GetSiginfo();
+ if (!buffer_or_error)
+ return buffer_or_error.takeError();
+ return std::move(*buffer_or_error);
+ }
+
if (object == "libraries-svr4") {
auto library_list = m_current_process->GetLoadedSVR4Libraries();
if (!library_list)
@@ -3838,6 +3850,8 @@ std::vector<std::string> GDBRemoteCommunicationServerLLGS::HandleFeatures(
ret.push_back("qXfer:auxv:read+");
if (bool(plugin_features & Extension::libraries_svr4))
ret.push_back("qXfer:libraries-svr4:read+");
+ if (bool(plugin_features & Extension::siginfo_read))
+ ret.push_back("qXfer:siginfo:read+");
if (bool(plugin_features & Extension::memory_tagging))
ret.push_back("memory-tagging+");
if (bool(plugin_features & Extension::savecore))
diff --git a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
index 01ae2428f338..18461568c02c 100644
--- a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
+++ b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
@@ -12,6 +12,7 @@
import binascii
import itertools
+import struct
import unittest2
import gdbremote_testcase
@@ -993,6 +994,13 @@ def test_qSupported_libraries_svr4(self):
self.assertEqual(supported_dict.get('qXfer:libraries-svr4:read', '-'),
expected)
+ def test_qSupported_siginfo_read(self):
+ expected = ('+' if lldbplatformutil.getPlatform()
+ in ["freebsd", "linux"] else '-')
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(supported_dict.get('qXfer:siginfo:read', '-'),
+ expected)
+
def test_qSupported_QPassSignals(self):
expected = ('+' if lldbplatformutil.getPlatform()
in ["freebsd", "linux", "netbsd"] else '-')
@@ -1374,3 +1382,83 @@ def test_QEnvironmentHexEncoded(self):
True)
context = self.expect_gdbremote_sequence()
self.assertEqual(context["O_content"], b"test\r\na=z\r\na*}#z\r\n")
+
+ @skipUnlessPlatform(oslist=["freebsd", "linux"])
+ @add_test_categories(["llgs"])
+ def test_qXfer_siginfo_read(self):
+ self.build()
+ self.set_inferior_startup_launch()
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["thread:segfault", "thread:new", "sleep:10"])
+ self.test_sequence.add_log_lines(["read packet: $c#63"], True)
+ self.expect_gdbremote_sequence()
+
+ # Run until SIGSEGV comes in.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [{"direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "signo", 2: "thread_id"},
+ }], True)
+
+ # Figure out which thread crashed.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ self.assertEqual(int(context["signo"], 16),
+ lldbutil.get_signal_number('SIGSEGV'))
+ crashing_thread = int(context["thread_id"], 16)
+
+ # Grab siginfo for the crashing thread.
+ self.reset_test_sequence()
+ self.add_process_info_collection_packets()
+ self.test_sequence.add_log_lines(
+ ["read packet: $Hg{:x}#00".format(crashing_thread),
+ "send packet: $OK#00",
+ "read packet: $qXfer:siginfo:read::0,80:#00",
+ {"direction": "send",
+ "regex": re.compile(r"^\$([^E])(.*)#[0-9a-fA-F]{2}$",
+ re.MULTILINE | re.DOTALL),
+ "capture": {1: "response_type", 2: "content_raw"},
+ }], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Ensure we end up with all data in one packet.
+ self.assertEqual(context.get("response_type"), "l")
+
+ # Decode binary data.
+ content_raw = context.get("content_raw")
+ self.assertIsNotNone(content_raw)
+ content = self.decode_gdbremote_binary(content_raw).encode("latin1")
+
+ # Decode siginfo_t.
+ process_info = self.parse_process_info_response(context)
+ pad = ""
+ if process_info["ptrsize"] == "8":
+ pad = "i"
+ signo_idx = 0
+ errno_idx = 1
+ code_idx = 2
+ addr_idx = -1
+ SEGV_MAPERR = 1
+ if process_info["ostype"] == "linux":
+ # si_signo, si_errno, si_code, [pad], _sifields._sigfault.si_addr
+ format_str = "iii{}P".format(pad)
+ elif process_info["ostype"].startswith("freebsd"):
+ # si_signo, si_errno, si_code, si_pid, si_uid, si_status, si_addr
+ format_str = "iiiiiiP"
+ elif process_info["ostype"].startswith("netbsd"):
+ # _signo, _code, _errno, [pad], _reason._fault._addr
+ format_str = "iii{}P".format(pad)
+ errno_idx = 2
+ code_idx = 1
+ else:
+ assert False, "unknown ostype"
+
+ decoder = struct.Struct(format_str)
+ decoded = decoder.unpack(content[:decoder.size])
+ self.assertEqual(decoded[signo_idx],
+ lldbutil.get_signal_number('SIGSEGV'))
+ self.assertEqual(decoded[errno_idx], 0) # si_errno
+ self.assertEqual(decoded[code_idx], SEGV_MAPERR) # si_code
+ self.assertEqual(decoded[addr_idx], 0) # si_addr
More information about the lldb-commits
mailing list