[Lldb-commits] [lldb] 0a72429 - [LLDB][ProcessELFCore] Add Description to ProcessELFCore/ELFThread stop reasons (#110065)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Nov 21 14:47:11 PST 2024
Author: Jacob Lalonde
Date: 2024-11-21T14:47:08-08:00
New Revision: 0a7242959f5d3f9ccf7b149009b9eebd45b785b0
URL: https://github.com/llvm/llvm-project/commit/0a7242959f5d3f9ccf7b149009b9eebd45b785b0
DIFF: https://github.com/llvm/llvm-project/commit/0a7242959f5d3f9ccf7b149009b9eebd45b785b0.diff
LOG: [LLDB][ProcessELFCore] Add Description to ProcessELFCore/ELFThread stop reasons (#110065)
This fixes a functionality gap with GDB, where GDB will properly decode
the stop reason and give the address for SIGSEGV. I also added
descriptions to all stop reasons, following the same code path that the
Native Linux Thread uses.
Added:
Modified:
lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
lldb/source/Plugins/Process/elf-core/ThreadElfCore.h
lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py
lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py
lldb/test/Shell/Register/Core/x86-32-linux-multithread.test
lldb/test/Shell/Register/Core/x86-64-linux-multithread.test
Removed:
################################################################################
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index cd95b000469dc5..a5ee3cfdb2932a 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -232,7 +232,7 @@ Status ProcessElfCore::DoLoadCore() {
bool prstatus_signal_found = false;
// Check we found a signal in a SIGINFO note.
for (const auto &thread_data : m_thread_data) {
- if (thread_data.signo != 0)
+ if (thread_data.siginfo.si_signo != 0)
siginfo_signal_found = true;
if (thread_data.prstatus_sig != 0)
prstatus_signal_found = true;
@@ -242,10 +242,10 @@ Status ProcessElfCore::DoLoadCore() {
// PRSTATUS note.
if (prstatus_signal_found) {
for (auto &thread_data : m_thread_data)
- thread_data.signo = thread_data.prstatus_sig;
+ thread_data.siginfo.si_signo = thread_data.prstatus_sig;
} else if (m_thread_data.size() > 0) {
// If all else fails force the first thread to be SIGSTOP
- m_thread_data.begin()->signo =
+ m_thread_data.begin()->siginfo.si_signo =
GetUnixSignals()->GetSignalNumberFromName("SIGSTOP");
}
}
@@ -498,7 +498,7 @@ static void ParseFreeBSDPrStatus(ThreadData &thread_data,
else
offset += 16;
- thread_data.signo = data.GetU32(&offset); // pr_cursig
+ thread_data.siginfo.si_signo = data.GetU32(&offset); // pr_cursig
thread_data.tid = data.GetU32(&offset); // pr_pid
if (lp64)
offset += 4;
@@ -581,7 +581,7 @@ static void ParseOpenBSDProcInfo(ThreadData &thread_data,
return;
offset += 4;
- thread_data.signo = data.GetU32(&offset);
+ thread_data.siginfo.si_signo = data.GetU32(&offset);
}
llvm::Expected<std::vector<CoreNote>>
@@ -819,7 +819,7 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) {
// Signal targeted at the whole process.
if (siglwp == 0) {
for (auto &data : m_thread_data)
- data.signo = signo;
+ data.siginfo.si_signo = signo;
}
// Signal destined for a particular LWP.
else {
@@ -827,7 +827,7 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) {
for (auto &data : m_thread_data) {
if (data.tid == siglwp) {
- data.signo = signo;
+ data.siginfo.si_signo = signo;
passed = true;
break;
}
@@ -930,12 +930,12 @@ llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef<CoreNote> notes) {
break;
}
case ELF::NT_SIGINFO: {
+ const lldb_private::UnixSignals &unix_signals = *GetUnixSignals();
ELFLinuxSigInfo siginfo;
- Status status = siginfo.Parse(note.data, arch);
+ Status status = siginfo.Parse(note.data, arch, unix_signals);
if (status.Fail())
return status.ToError();
- thread_data.signo = siginfo.si_signo;
- thread_data.code = siginfo.si_code;
+ thread_data.siginfo = siginfo;
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 f2838087298efb..c810eb9ed61d26 100644
--- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
@@ -9,6 +9,7 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
+#include "lldb/Target/UnixSignals.h"
#include "lldb/Target/Unwind.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/LLDBLog.h"
@@ -49,9 +50,9 @@ 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_code(td.code), m_gpregset_data(td.gpregset),
- m_notes(td.notes) {}
+ : Thread(process, td.tid), m_thread_reg_ctx_sp(), m_thread_name(td.name),
+ m_gpregset_data(td.gpregset), m_notes(td.notes),
+ m_siginfo(std::move(td.siginfo)) {}
ThreadElfCore::~ThreadElfCore() { DestroyThread(); }
@@ -246,8 +247,21 @@ bool ThreadElfCore::CalculateStopInfo() {
if (!process_sp)
return false;
+ lldb::UnixSignalsSP unix_signals_sp(process_sp->GetUnixSignals());
+ if (!unix_signals_sp)
+ return false;
+
+ const char *sig_description;
+ std::string description = m_siginfo.GetDescription(*unix_signals_sp);
+ if (description.empty())
+ sig_description = nullptr;
+ else
+ sig_description = description.c_str();
+
SetStopInfo(StopInfo::CreateStopReasonWithSignal(
- *this, m_signo, /*description=*/nullptr, m_code));
+ *this, m_siginfo.si_signo, sig_description, m_siginfo.si_code));
+
+ SetStopInfo(m_stop_info_sp);
return true;
}
@@ -547,21 +561,64 @@ size_t ELFLinuxSigInfo::GetSize(const lldb_private::ArchSpec &arch) {
}
}
-Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch) {
+Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch,
+ const lldb_private::UnixSignals &unix_signals) {
Status error;
- if (GetSize(arch) > data.GetByteSize()) {
+ uint64_t size = GetSize(arch);
+ if (size > data.GetByteSize()) {
error = Status::FromErrorStringWithFormat(
"NT_SIGINFO size should be %zu, but the remaining bytes are: %" PRIu64,
GetSize(arch), data.GetByteSize());
return error;
}
+ // Set that we've parsed the siginfo from a SIGINFO note.
+ note_type = eNT_SIGINFO;
// Parsing from a 32 bit ELF core file, and populating/reusing the structure
// properly, because the struct is for the 64 bit version
offset_t offset = 0;
si_signo = data.GetU32(&offset);
si_errno = data.GetU32(&offset);
si_code = data.GetU32(&offset);
+ // 64b ELF have a 4 byte pad.
+ if (data.GetAddressByteSize() == 8)
+ offset += 4;
+ // Not every stop signal has a valid address, but that will get resolved in
+ // the unix_signals.GetSignalDescription() call below.
+ if (unix_signals.GetShouldStop(si_signo)) {
+ // Instead of memcpy we call all these individually as the extractor will
+ // handle endianness for us.
+ sigfault.si_addr = data.GetAddress(&offset);
+ sigfault.si_addr_lsb = data.GetU16(&offset);
+ if (data.GetByteSize() - offset >= sizeof(sigfault.bounds)) {
+ sigfault.bounds._addr_bnd._lower = data.GetAddress(&offset);
+ sigfault.bounds._addr_bnd._upper = data.GetAddress(&offset);
+ sigfault.bounds._pkey = data.GetU32(&offset);
+ } else {
+ // Set these to 0 so we don't use bogus data for the description.
+ sigfault.bounds._addr_bnd._lower = 0;
+ sigfault.bounds._addr_bnd._upper = 0;
+ sigfault.bounds._pkey = 0;
+ }
+ }
return error;
}
+
+std::string ELFLinuxSigInfo::GetDescription(
+ const lldb_private::UnixSignals &unix_signals) const {
+ if (unix_signals.GetShouldStop(si_signo) && note_type == eNT_SIGINFO) {
+ if (sigfault.bounds._addr_bnd._upper != 0)
+ return unix_signals.GetSignalDescription(
+ si_signo, si_code, sigfault.si_addr, sigfault.bounds._addr_bnd._lower,
+ sigfault.bounds._addr_bnd._upper);
+ else
+ return unix_signals.GetSignalDescription(si_signo, si_code,
+ sigfault.si_addr);
+ }
+
+ // This looks weird, but there is an existing pattern where we don't pass a
+ // description to keep up with that, we return empty here, and then the above
+ // function will set the description whether or not this is empty.
+ return std::string();
+}
diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h
index 3fa0b8b0eedb0b..4ebbaadebe9f90 100644
--- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h
+++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h
@@ -35,6 +35,8 @@ class ProcessInstanceInfo;
#undef si_signo
#undef si_code
#undef si_errno
+#undef si_addr
+#undef si_addr_lsb
struct ELFLinuxPrStatus {
int32_t si_signo;
@@ -76,14 +78,36 @@ static_assert(sizeof(ELFLinuxPrStatus) == 112,
"sizeof ELFLinuxPrStatus is not correct!");
struct ELFLinuxSigInfo {
- int32_t si_signo;
- int32_t si_code;
+
+ int32_t si_signo; // Order matters for the first 3.
int32_t si_errno;
+ int32_t si_code;
+ // Copied from siginfo_t so we don't have to include signal.h on non 'Nix
+ // builds.
+ struct {
+ lldb::addr_t si_addr; /* faulting insn/memory ref. */
+ short int si_addr_lsb; /* Valid LSB of the reported address. */
+ union {
+ /* used when si_code=SEGV_BNDERR */
+ struct {
+ lldb::addr_t _lower;
+ lldb::addr_t _upper;
+ } _addr_bnd;
+ /* used when si_code=SEGV_PKUERR */
+ uint32_t _pkey;
+ } bounds;
+ } sigfault;
+
+ enum { eUnspecified, eNT_SIGINFO } note_type;
ELFLinuxSigInfo();
lldb_private::Status Parse(const lldb_private::DataExtractor &data,
- const lldb_private::ArchSpec &arch);
+ const lldb_private::ArchSpec &arch,
+ const lldb_private::UnixSignals &unix_signals);
+
+ std::string
+ GetDescription(const lldb_private::UnixSignals &unix_signals) const;
// Return the bytesize of the structure
// 64 bit - just sizeof
@@ -93,7 +117,7 @@ struct ELFLinuxSigInfo {
static size_t GetSize(const lldb_private::ArchSpec &arch);
};
-static_assert(sizeof(ELFLinuxSigInfo) == 12,
+static_assert(sizeof(ELFLinuxSigInfo) == 56,
"sizeof ELFLinuxSigInfo is not correct!");
// PRPSINFO structure's size
diff ers based on architecture.
@@ -142,10 +166,9 @@ struct ThreadData {
lldb_private::DataExtractor gpregset;
std::vector<lldb_private::CoreNote> notes;
lldb::tid_t tid;
- int signo = 0;
- int code = 0;
- int prstatus_sig = 0;
std::string name;
+ ELFLinuxSigInfo siginfo;
+ int prstatus_sig = 0;
};
class ThreadElfCore : public lldb_private::Thread {
@@ -176,16 +199,17 @@ class ThreadElfCore : public lldb_private::Thread {
m_thread_name.clear();
}
+ void CreateStopFromSigInfo(const ELFLinuxSigInfo &siginfo,
+ const lldb_private::UnixSignals &unix_signals);
+
protected:
// Member variables.
std::string m_thread_name;
lldb::RegisterContextSP m_thread_reg_ctx_sp;
- int m_signo;
- int m_code;
-
lldb_private::DataExtractor m_gpregset_data;
std::vector<lldb_private::CoreNote> m_notes;
+ ELFLinuxSigInfo m_siginfo;
bool CalculateStopInfo() override;
};
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 0667759a341b83..779050edb054a4 100644
--- a/lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py
+++ b/lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py
@@ -2,7 +2,6 @@
Test that memory tagging features work with Linux core files.
"""
-
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
@@ -216,8 +215,7 @@ def test_mte_tag_fault_reason(self):
self.expect(
"bt",
substrs=[
- "* thread #1, name = 'a.out.mte', stop reason = signal SIGSEGV: "
- "sync tag check fault"
+ "* thread #1, name = 'a.out.mte', stop reason = SIGSEGV: sync tag check fault (fault address: 0xffff82c74010)"
],
)
diff --git a/lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py b/lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py
index d86070c37f98a3..668fca11903660 100644
--- a/lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py
+++ b/lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py
@@ -6,7 +6,6 @@
API level it won't if we don't remove them there also.
"""
-
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
@@ -199,7 +198,13 @@ def test_non_address_bit_memory_caching(self):
def test_non_address_bit_memory_corefile(self):
self.runCmd("target create --core corefile")
- self.expect("thread list", substrs=["stopped", "stop reason = signal SIGSEGV"])
+ self.expect(
+ "thread list",
+ substrs=[
+ "stopped",
+ "stop reason = SIGSEGV: address not mapped to object (fault address: 0x0)",
+ ],
+ )
# No caching (the program/corefile are the cache) and no writing
# to memory. So just check that tagged/untagged addresses read
diff --git a/lldb/test/Shell/Register/Core/x86-32-linux-multithread.test b/lldb/test/Shell/Register/Core/x86-32-linux-multithread.test
index 62e5bb8ee32fd7..eb0cf8708263cb 100644
--- a/lldb/test/Shell/Register/Core/x86-32-linux-multithread.test
+++ b/lldb/test/Shell/Register/Core/x86-32-linux-multithread.test
@@ -1,7 +1,7 @@
# RUN: %lldb -b -s %s -c %p/Inputs/x86-32-linux-multithread.core | FileCheck %s
thread list
-# CHECK: * thread #1: tid = 330633, 0x080492d2, name = 'a.out', stop reason = signal SIGSEGV
+# CHECK: * thread #1: tid = 330633, 0x080492d2, name = 'a.out', stop reason = SIGSEGV: address not mapped to object (fault address: 0x0)
# CHECK-NEXT: thread #2: tid = 330634, 0x080492dd, stop reason = signal 0
# CHECK-NEXT: thread #3: tid = 330635, 0x080492dd, stop reason = signal 0
# CHECK-NEXT: thread #4: tid = 330632, 0xf7f59549, stop reason = signal 0
diff --git a/lldb/test/Shell/Register/Core/x86-64-linux-multithread.test b/lldb/test/Shell/Register/Core/x86-64-linux-multithread.test
index ab28901cae9f20..a94a4de1c8080b 100644
--- a/lldb/test/Shell/Register/Core/x86-64-linux-multithread.test
+++ b/lldb/test/Shell/Register/Core/x86-64-linux-multithread.test
@@ -1,7 +1,7 @@
# RUN: %lldb -b -s %s -c %p/Inputs/x86-64-linux-multithread.core | FileCheck %s
thread list
-# CHECK: * thread #1: tid = 329384, 0x0000000000401262, name = 'a.out', stop reason = signal SIGSEGV
+# CHECK: * thread #1: tid = 329384, 0x0000000000401262, name = 'a.out', stop reason = SIGSEGV: address not mapped to object (fault address: 0x0)
# CHECK-NEXT: thread #2: tid = 329385, 0x000000000040126d, stop reason = signal 0
# CHECK-NEXT: thread #3: tid = 329386, 0x000000000040126d, stop reason = signal 0
# CHECK-NEXT: thread #4: tid = 329383, 0x00007fcf5582f762, stop reason = signal 0
More information about the lldb-commits
mailing list