diff --git a/lldb/bindings/interface/SBThread.i b/lldb/bindings/interface/SBThread.i --- a/lldb/bindings/interface/SBThread.i +++ b/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(); + STRING_EXTENSION(SBThread) #ifdef SWIGPYTHON diff --git a/lldb/include/lldb/API/SBThread.h b/lldb/include/lldb/API/SBThread.h --- a/lldb/include/lldb/API/SBThread.h +++ b/lldb/include/lldb/API/SBThread.h @@ -208,6 +208,8 @@ bool SafeToCallFunctions(); + SBValue GetSiginfo(); + private: friend class SBBreakpoint; friend class SBBreakpointLocation; diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h --- a/lldb/include/lldb/Target/Thread.h +++ b/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,8 @@ lldb::ThreadSP GetCurrentExceptionBacktrace(); + lldb::ValueObjectSP GetSiginfoValue(); + protected: friend class ThreadPlan; friend class ThreadList; @@ -1233,6 +1236,11 @@ void FrameSelectedCallback(lldb_private::StackFrame *frame); + virtual llvm::Expected> + GetSiginfo(size_t max_size) const { + return llvm::make_error(); + } + // Classes that inherit from Process can see and modify these lldb::ProcessWP m_process_wp; ///< The process that owns this thread. lldb::StopInfoSP m_stop_info_sp; ///< The private stop reason for this thread diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -1317,3 +1317,12 @@ lldb_private::Thread *SBThread::get() { return m_opaque_sp->GetThreadSP().get(); } + +SBValue SBThread::GetSiginfo() { + LLDB_INSTRUMENT_VA(this); + + ThreadSP thread_sp = m_opaque_sp->GetThreadSP(); + if (!thread_sp) + return SBValue(); + return thread_sp->GetSiginfoValue(); +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/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; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/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+") diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -115,6 +115,9 @@ void SetStopInfoFromPacket(StringExtractor &stop_packet, uint32_t stop_id); bool CalculateStopInfo() override; + + llvm::Expected> + GetSiginfo(size_t max_size) const override; }; } // namespace process_gdb_remote diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/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()); +} diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -13,6 +13,7 @@ #include "lldb/Core/Module.h" #include "lldb/Core/StructuredDataImpl.h" #include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/OptionValueFileSpecList.h" #include "lldb/Interpreter/OptionValueProperties.h" @@ -2005,3 +2006,26 @@ return ThreadSP(); } + +lldb::ValueObjectSP Thread::GetSiginfoValue() { + ProcessSP process_sp = GetProcess(); + assert(process_sp); + Target &target = process_sp->GetTarget(); + PlatformSP platform_sp = target.GetPlatform(); + assert(platform_sp); + ArchSpec arch = target.GetArchitecture(); + + CompilerType type = platform_sp->GetSiginfoType(arch.GetTriple()); + if (!type.IsValid()) + return ValueObjectConstResult::Create(&target, Status("no siginfo_t for the platform")); + + llvm::Optional type_size = type.GetByteSize(nullptr); + assert(type_size); + llvm::Expected> data = GetSiginfo(type_size.getValue()); + if (!data) + return ValueObjectConstResult::Create(&target, Status(data.takeError())); + + DataExtractor data_extractor{data.get()->getBufferStart(), data.get()->getBufferSize(), + process_sp->GetByteOrder(), arch.GetAddressByteSize()}; + return ValueObjectConstResult::Create(&target, type, ConstString("__lldb_siginfo"), data_extractor); +} diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py --- a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py +++ b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py @@ -490,3 +490,98 @@ lldb.eStopReasonSignal) self.assertEqual(process.threads[0].GetStopDescription(100), 'signal SIGUSR1') + + def do_siginfo_test(self, platform, target_yaml, raw_data, expected): + 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 raw_data, False + else: + return None, False + + def haltReason(self): + return "T02" + + def cont(self): + return self.haltReason() + + self.server.responder = MyResponder() + + self.runCmd("platform select " + platform) + target = self.createTarget(target_yaml) + process = self.connect(target) + + siginfo = process.threads[0].GetSiginfo() + self.assertTrue(siginfo.GetError().Success(), siginfo.GetError()) + + for key, value in expected.items(): + self.assertEqual(siginfo.GetValueForExpressionPath("." + key) + .GetValueAsUnsigned(), + value) + + + def test_siginfo_linux_amd64(self): + data = ( + # si_signo si_errno si_code + "\x11\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00" + # __pad0 si_pid si_uid + "\x00\x00\x00\x00\xbf\xf7\x0b\x00\xe8\x03\x00\x00" + # si_status + "\x0c\x00\x00\x00" + "\x00" * 100) + 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_utime": 0, + "_sifields._sigchld.si_stime": 0, + } + self.do_siginfo_test("remote-linux", "basic_eh_frame.yaml", + data, expected) + + def test_siginfo_linux_i386(self): + data = ( + # si_signo si_errno si_code + "\x11\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00" + # si_pid si_uid si_status + "\x49\x43\x07\x00\xe8\x03\x00\x00\x0c\x00\x00\x00" + + "\x00" * 104) + expected = { + "si_signo": 17, # SIGCHLD + "si_errno": 0, + "si_code": 1, # CLD_EXITED + "_sifields._sigchld.si_pid": 475977, + "_sifields._sigchld.si_uid": 1000, + "_sifields._sigchld.si_status": 12, + "_sifields._sigchld.si_utime": 0, + "_sifields._sigchld.si_stime": 0, + } + self.do_siginfo_test("remote-linux", "basic_eh_frame-i386.yaml", + data, expected) + + def test_siginfo_freebsd_amd64(self): + data = ( + # si_signo si_errno si_code + "\x0b\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00" + # si_pid si_uid si_status + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + # si_addr + "\x76\x98\xba\xdc\xfe\x00\x00\x00" + # si_status si_trapno + "\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00" + + "\x00" * 36) + + expected = { + "si_signo": 11, # SIGSEGV + "si_errno": 0, + "si_code": 1, # SEGV_MAPERR + "si_addr": 0xfedcba9876, + "_reason._fault._trapno": 12, + } + self.do_siginfo_test("remote-freebsd", "basic_eh_frame.yaml", + data, expected)