From 85bc498826d4dac4b64f7b02659f6ec52f11c223 Mon Sep 17 00:00:00 2001 From: David Spickett Date: Tue, 14 Mar 2023 11:52:48 +0000 Subject: [PATCH] [LLDB] Show sub type of signals when debugging a core file Previously we only looked at the si_signo field, so you got: ``` (lldb) bt * thread #1, name = 'a.out.mte', stop reason = signal SIGSEGV * frame #0: 0x00000000004007f4 ``` This patch adds si_code so we can show: ``` (lldb) bt * thread #1, name = 'a.out.mte', stop reason = signal SIGSEGV: sync tag check fault * frame #0: 0x00000000004007f4 ``` The order of errno and code was incorrect in ElfLinuxSigInfo::Parse. It was the order that a "swapped" siginfo arch would use, which for Linux, is only MIPS. We removed MIPS Linux support some time ago. See: https://github.com/torvalds/linux/blob/fe15c26ee26efa11741a7b632e9f23b01aca4cc6/include/uapi/asm-generic/siginfo.h#L121 A test is added using memory tagging faults. Which were the original motivation for the changes. Reviewed By: JDevlieghere Differential Revision: https://reviews.llvm.org/D146045 --- lldb/include/lldb/Target/StopInfo.h | 3 +- .../Process/elf-core/ProcessElfCore.cpp | 1 + .../Process/elf-core/ThreadElfCore.cpp | 16 +++++----- .../Plugins/Process/elf-core/ThreadElfCore.h | 2 ++ lldb/source/Target/StopInfo.cpp | 29 ++++++++++++------- .../TestAArch64LinuxMTEMemoryTagCoreFile.py | 11 +++++++ llvm/docs/ReleaseNotes.rst | 3 ++ 7 files changed, 47 insertions(+), 18 deletions(-) diff --git a/lldb/include/lldb/Target/StopInfo.h b/lldb/include/lldb/Target/StopInfo.h index 9527a6ea553e..8d6284e37dac 100644 --- a/lldb/include/lldb/Target/StopInfo.h +++ b/lldb/include/lldb/Target/StopInfo.h @@ -115,7 +115,8 @@ public: static lldb::StopInfoSP CreateStopReasonWithSignal(Thread &thread, int signo, - const char *description = nullptr); + const char *description = nullptr, + std::optional code = std::nullopt); static lldb::StopInfoSP CreateStopReasonToTrace(Thread &thread); diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 2771d1d20cf0..a0f391b9b26c 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -922,6 +922,7 @@ llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef notes) { if (status.Fail()) return status.ToError(); thread_data.signo = siginfo.si_signo; + thread_data.code = siginfo.si_code; break; } case ELF::NT_FILE: { diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index bb190104cf2f..0191562d7223 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -46,7 +46,8 @@ using namespace lldb_private; // Construct a Thread object with given data ThreadElfCore::ThreadElfCore(Process &process, const ThreadData &td) : Thread(process, td.tid), m_thread_name(td.name), m_thread_reg_ctx_sp(), - m_signo(td.signo), m_gpregset_data(td.gpregset), m_notes(td.notes) {} + m_signo(td.signo), m_code(td.code), m_gpregset_data(td.gpregset), + m_notes(td.notes) {} ThreadElfCore::~ThreadElfCore() { DestroyThread(); } @@ -221,11 +222,12 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { bool ThreadElfCore::CalculateStopInfo() { ProcessSP process_sp(GetProcess()); - if (process_sp) { - SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, m_signo)); - return true; - } - return false; + if (!process_sp) + return false; + + SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *this, m_signo, /*description=*/nullptr, m_code)); + return true; } // Parse PRSTATUS from NOTE entry @@ -409,8 +411,8 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch) { // properly, because the struct is for the 64 bit version offset_t offset = 0; si_signo = data.GetU32(&offset); - si_code = data.GetU32(&offset); si_errno = data.GetU32(&offset); + si_code = data.GetU32(&offset); return error; } diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 8d973bb840d2..2f3ed2a01779 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -128,6 +128,7 @@ struct ThreadData { std::vector notes; lldb::tid_t tid; int signo = 0; + int code = 0; int prstatus_sig = 0; std::string name; }; @@ -166,6 +167,7 @@ protected: lldb::RegisterContextSP m_thread_reg_ctx_sp; int m_signo; + int m_code; lldb_private::DataExtractor m_gpregset_data; std::vector m_notes; diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index ebc355c90d0a..a98fc28c7338 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -1044,8 +1044,9 @@ private: class StopInfoUnixSignal : public StopInfo { public: - StopInfoUnixSignal(Thread &thread, int signo, const char *description) - : StopInfo(thread, signo) { + StopInfoUnixSignal(Thread &thread, int signo, const char *description, + std::optional code) + : StopInfo(thread, signo), m_code(code) { SetDescription(description); } @@ -1100,19 +1101,26 @@ public: if (m_description.empty()) { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { + UnixSignalsSP unix_signals = thread_sp->GetProcess()->GetUnixSignals(); StreamString strm; - const char *signal_name = - thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString( - m_value); - if (signal_name) - strm.Printf("signal %s", signal_name); + strm << "signal "; + + std::string signal_name = + unix_signals->GetSignalDescription(m_value, m_code); + if (signal_name.size()) + strm << signal_name; else - strm.Printf("signal %" PRIi64, m_value); + strm.Printf("%" PRIi64, m_value); + m_description = std::string(strm.GetString()); } } return m_description.c_str(); } + +private: + // In siginfo_t terms, if m_value is si_signo, m_code is si_code. + std::optional m_code; }; // StopInfoTrace @@ -1371,9 +1379,10 @@ StopInfo::CreateStopReasonWithWatchpointID(Thread &thread, break_id_t watch_id, } StopInfoSP StopInfo::CreateStopReasonWithSignal(Thread &thread, int signo, - const char *description) { + const char *description, + std::optional code) { thread.GetProcess()->GetUnixSignals()->IncrementSignalHitCount(signo); - return StopInfoSP(new StopInfoUnixSignal(thread, signo, description)); + return StopInfoSP(new StopInfoUnixSignal(thread, signo, description, code)); } StopInfoSP StopInfo::CreateStopReasonToTrace(Thread &thread) { diff --git a/lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py b/lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py index a174616cd89d..e742dd06b3f1 100644 --- a/lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py +++ b/lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py @@ -166,3 +166,14 @@ class AArch64LinuxMTEMemoryTagCoreFileTestCase(TestBase): # the MTE core file which does support it but does not allow writing tags. self.expect("memory tag write 0 1", substrs=["error: Process does not support memory tagging"], error=True) + + @skipIfLLVMTargetMissing("AArch64") + def test_mte_tag_fault_reason(self): + """ Test that we correctly report the fault reason. """ + self.runCmd("target create --core core.mte") + + # There is no fault address shown here because core files do not include + # si_addr. + self.expect("bt", substrs=[ + "* thread #1, name = 'a.out.mte', stop reason = signal SIGSEGV: " + "sync tag check fault"]) diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst index 9d7b1dbd79ef..d87d20704f16 100644 --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -221,6 +221,9 @@ Changes to LLDB omit defaulted template parameters. The full template parameter list can still be viewed with ``expr --raw-output``/``frame var --raw-output``. (`D141828 `_) +* LLDB is now able to show the subtype of signals found in a core file. For example + memory tagging specific segfaults such as ``SIGSEGV: sync tag check fault``. + Changes to Sanitizers ---------------------