Index: lldb/bindings/interface/SBThread.i =================================================================== --- lldb/bindings/interface/SBThread.i +++ lldb/bindings/interface/SBThread.i @@ -405,6 +405,12 @@ bool SafeToCallFunctions (); + %feature("autodoc"," + Retruns a SBValue object representing the siginfo for the current signal. + ") GetSiginfo; + lldb::SBValue + GetSiginfo(SBError &error); + STRING_EXTENSION(SBThread) #ifdef SWIGPYTHON Index: lldb/include/lldb/API/SBThread.h =================================================================== --- lldb/include/lldb/API/SBThread.h +++ lldb/include/lldb/API/SBThread.h @@ -208,6 +208,8 @@ bool SafeToCallFunctions(); + SBValue GetSiginfo(SBError &error); + private: friend class SBBreakpoint; friend class SBBreakpointLocation; Index: lldb/include/lldb/Target/Thread.h =================================================================== --- lldb/include/lldb/Target/Thread.h +++ lldb/include/lldb/Target/Thread.h @@ -22,6 +22,7 @@ #include "lldb/Utility/CompletionRequest.h" #include "lldb/Utility/Event.h" #include "lldb/Utility/StructuredData.h" +#include "lldb/Utility/UnimplementedError.h" #include "lldb/Utility/UserID.h" #include "lldb/lldb-private.h" @@ -1184,6 +1185,11 @@ lldb::ThreadSP GetCurrentExceptionBacktrace(); + virtual llvm::Expected> + GetSiginfo(size_t max_size) const { + return llvm::make_error(); + } + protected: friend class ThreadPlan; friend class ThreadList; Index: lldb/source/API/SBThread.cpp =================================================================== --- lldb/source/API/SBThread.cpp +++ lldb/source/API/SBThread.cpp @@ -1317,3 +1317,47 @@ lldb_private::Thread *SBThread::get() { return m_opaque_sp->GetThreadSP().get(); } + +SBValue SBThread::GetSiginfo(SBError &error) { + LLDB_INSTRUMENT_VA(this, error); + + SBValue value; + SBProcess process = GetProcess(); + if (!process.IsValid()) { + error.SetErrorString("no process"); + return value; + } + SBTarget target = process.GetTarget(); + if (!target.IsValid()) { + error.SetErrorString("unable to get target"); + return value; + } + SBPlatform platform = target.GetPlatform(); + if (!platform.IsValid()) { + error.SetErrorString("unable to get platform"); + return value; + } + SBType type = platform.GetSiginfoType(target); + if (!type.IsValid()) { + error.SetErrorString("no siginfo_t for the platform"); + return value; + } + ThreadSP thread_sp = m_opaque_sp->GetThreadSP(); + if (!thread_sp) { + error.SetErrorString("unable to get thread"); + return value; + } + llvm::Expected> data = + thread_sp->GetSiginfo(type.GetByteSize()); + if (!data) { + error.SetErrorString(llvm::toString(data.takeError()).c_str()); + return value; + } + SBData sb_data; + sb_data.SetData(error, data.get()->getBufferStart(), + data.get()->getBufferSize(), process.GetByteOrder(), 0); + if (!sb_data.IsValid()) + return value; + + return target.CreateValueFromData("siginfo", sb_data, type); +} Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -337,6 +337,8 @@ bool GetQXferMemoryMapReadSupported(); + bool GetQXferSigInfoReadSupported(); + LazyBool SupportsAllocDeallocMemory() // const { // Uncomment this to have lldb pretend the debug server doesn't respond to @@ -551,6 +553,7 @@ LazyBool m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; LazyBool m_supports_qXfer_features_read = eLazyBoolCalculate; LazyBool m_supports_qXfer_memory_map_read = eLazyBoolCalculate; + LazyBool m_supports_qXfer_siginfo_read = eLazyBoolCalculate; LazyBool m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; LazyBool m_supports_jThreadExtendedInfo = eLazyBoolCalculate; LazyBool m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolCalculate; Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -173,6 +173,13 @@ return m_supports_qXfer_memory_map_read == eLazyBoolYes; } +bool GDBRemoteCommunicationClient::GetQXferSigInfoReadSupported() { + if (m_supports_qXfer_siginfo_read == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_qXfer_siginfo_read == eLazyBoolYes; +} + uint64_t GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() { if (m_max_packet_size == 0) { GetRemoteQSupported(); @@ -273,6 +280,7 @@ m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; m_supports_qXfer_features_read = eLazyBoolCalculate; m_supports_qXfer_memory_map_read = eLazyBoolCalculate; + m_supports_qXfer_siginfo_read = eLazyBoolCalculate; m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; m_uses_native_signals = eLazyBoolCalculate; m_supports_qProcessInfoPID = true; @@ -320,6 +328,7 @@ m_supports_augmented_libraries_svr4_read = eLazyBoolNo; m_supports_qXfer_features_read = eLazyBoolNo; m_supports_qXfer_memory_map_read = eLazyBoolNo; + m_supports_qXfer_siginfo_read = eLazyBoolNo; m_supports_multiprocess = eLazyBoolNo; m_supports_qEcho = eLazyBoolNo; m_supports_QPassSignals = eLazyBoolNo; @@ -362,6 +371,8 @@ m_supports_qXfer_features_read = eLazyBoolYes; else if (x == "qXfer:memory-map:read+") m_supports_qXfer_memory_map_read = eLazyBoolYes; + else if (x == "qXfer:siginfo:read+") + m_supports_qXfer_siginfo_read = eLazyBoolYes; else if (x == "qEcho") m_supports_qEcho = eLazyBoolYes; else if (x == "QPassSignals+") Index: lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -90,6 +90,9 @@ StructuredData::ObjectSP FetchThreadExtendedInfo() override; + llvm::Expected> + GetSiginfo(size_t max_size) const override; + protected: friend class ProcessGDBRemote; Index: lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -346,3 +346,23 @@ ->CalculateThreadStopInfo(this); return false; } + +llvm::Expected> +ThreadGDBRemote::GetSiginfo(size_t max_size) const { + ProcessSP process_sp(GetProcess()); + if (!process_sp) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "no process"); + ProcessGDBRemote *gdb_process = + static_cast(process_sp.get()); + if (!gdb_process->m_gdb_comm.GetQXferSigInfoReadSupported()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "qXfer:siginfo:read not supported"); + + llvm::Expected response = + gdb_process->m_gdb_comm.ReadExtFeature("siginfo", ""); + if (!response) + return response.takeError(); + + return llvm::MemoryBuffer::getMemBufferCopy(response.get()); +} Index: lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py =================================================================== --- lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py +++ lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py @@ -490,3 +490,47 @@ lldb.eStopReasonSignal) self.assertEqual(process.threads[0].GetStopDescription(100), 'signal SIGUSR1') + + def test_siginfo(self): + class MyResponder(MockGDBServerResponder): + def qSupported(self, client_supported): + return "PacketSize=3fff;QStartNoAckMode+;qXfer:siginfo:read+" + + def qXferRead(self, obj, annex, offset, length): + if obj == "siginfo": + return "\x11\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xbf\xf7\x0b\x00\xe8\x03\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", False + else: + return None, False + + def haltReason(self): + return "T02" + + def cont(self): + return self.haltReason() + + self.server.responder = MyResponder() + + self.runCmd("platform select remote-linux") + target = self.createTarget("a.yaml") + process = self.connect(target) + + error = lldb.SBError() + siginfo = process.threads[0].GetSiginfo(error) + assert siginfo, error + + expected = { + "si_signo": 17, # SIGCHLD + "si_errno": 0, + "si_code": 1, # CLD_EXITED + "_sifields._sigchld.si_pid": 784319, + "_sifields._sigchld.si_uid": 1000, + "_sifields._sigchld.si_status": 12, + "_sifields._sigchld.si_status": 12, + "_sifields._sigchld.si_utime": 0, + "_sifields._sigchld.si_stime": 0, + } + + for key, value in expected.items(): + self.assertEqual(siginfo.GetValueForExpressionPath("." + key) + .GetValueAsUnsigned(), + value)