[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