33 changes: 32 additions & 1 deletion lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,29 @@ Error ProcessElfCore::DoLoadCore() {

SetUnixSignals(UnixSignals::Create(GetArchitecture()));

// Ensure we found at least one thread that was stopped on a signal.
bool siginfo_signal_found = false;
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)
siginfo_signal_found = true;
if (thread_data.prstatus_sig != 0)
prstatus_signal_found = true;
}
if (!siginfo_signal_found) {
// If we don't have signal from SIGINFO use the signal from each threads
// PRSTATUS note.
if (prstatus_signal_found) {
for (auto &thread_data: m_thread_data)
thread_data.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 =
GetUnixSignals()->GetSignalNumberFromName("SIGSTOP");
}
}

// Core files are useless without the main executable. See if we can locate
// the main
// executable using data we found in the core file notes.
Expand Down Expand Up @@ -402,6 +425,7 @@ enum {
NT_AUXV,
NT_FILE = 0x46494c45,
NT_PRXFPREG = 0x46e62b7f,
NT_SIGINFO = 0x53494749,
};

namespace FREEBSD {
Expand Down Expand Up @@ -485,6 +509,7 @@ Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
ArchSpec arch = GetArchitecture();
ELFLinuxPrPsInfo prpsinfo;
ELFLinuxPrStatus prstatus;
ELFLinuxSigInfo siginfo;
size_t header_size;
size_t len;
Error error;
Expand Down Expand Up @@ -546,7 +571,7 @@ Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
error = prstatus.Parse(note_data, arch);
if (error.Fail())
return error;
thread_data->signo = prstatus.pr_cursig;
thread_data->prstatus_sig = prstatus.pr_cursig;
thread_data->tid = prstatus.pr_pid;
header_size = ELFLinuxPrStatus::GetSize(arch);
len = note_data.GetByteSize() - header_size;
Expand Down Expand Up @@ -588,6 +613,12 @@ Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
m_nt_file_entries[i].path.SetCString(path);
}
} break;
case NT_SIGINFO: {
error = siginfo.Parse(note_data, arch);
if (error.Fail())
return error;
thread_data->signo = siginfo.si_signo;
} break;
default:
break;
}
Expand Down
42 changes: 42 additions & 0 deletions lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,3 +320,45 @@ Error ELFLinuxPrPsInfo::Parse(DataExtractor &data, ArchSpec &arch) {

return error;
}

//----------------------------------------------------------------
// Parse SIGINFO from NOTE entry
//----------------------------------------------------------------
ELFLinuxSigInfo::ELFLinuxSigInfo() {
memset(this, 0, sizeof(ELFLinuxSigInfo));
}

Error ELFLinuxSigInfo::Parse(DataExtractor &data, const ArchSpec &arch) {
Error error;
ByteOrder byteorder = data.GetByteOrder();
if (GetSize(arch) > data.GetByteSize()) {
error.SetErrorStringWithFormat(
"NT_SIGINFO size should be %zu, but the remaining bytes are: %" PRIu64,
GetSize(arch), data.GetByteSize());
return error;
}

switch (arch.GetCore()) {
case ArchSpec::eCore_x86_64_x86_64:
data.ExtractBytes(0, sizeof(ELFLinuxPrStatus), byteorder, this);
break;
case ArchSpec::eCore_s390x_generic:
case ArchSpec::eCore_x86_32_i386:
case ArchSpec::eCore_x86_32_i486: {
// 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_code = data.GetU32(&offset);
si_errno = data.GetU32(&offset);

break;
}
default:
error.SetErrorStringWithFormat("ELFLinuxSigInfo::%s Unknown architecture",
__FUNCTION__);
break;
}

return error;
}
35 changes: 34 additions & 1 deletion lldb/source/Plugins/Process/elf-core/ThreadElfCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,38 @@ struct ELFLinuxPrStatus {
static_assert(sizeof(ELFLinuxPrStatus) == 112,
"sizeof ELFLinuxPrStatus is not correct!");

struct ELFLinuxSigInfo {
int32_t si_signo;
int32_t si_code;
int32_t si_errno;

ELFLinuxSigInfo();

lldb_private::Error Parse(lldb_private::DataExtractor &data,
const lldb_private::ArchSpec &arch);

// Return the bytesize of the structure
// 64 bit - just sizeof
// 32 bit - hardcoded because we are reusing the struct, but some of the
// members are smaller -
// so the layout is not the same
static size_t GetSize(const lldb_private::ArchSpec &arch) {
switch (arch.GetCore()) {
case lldb_private::ArchSpec::eCore_x86_64_x86_64:
return sizeof(ELFLinuxSigInfo);
case lldb_private::ArchSpec::eCore_s390x_generic:
case lldb_private::ArchSpec::eCore_x86_32_i386:
case lldb_private::ArchSpec::eCore_x86_32_i486:
return 12;
default:
return 0;
}
}
};

static_assert(sizeof(ELFLinuxSigInfo) == 12,
"sizeof ELFLinuxSigInfo is not correct!");

// PRPSINFO structure's size differs based on architecture.
// This is the layout in the x86-64 arch case.
// In the i386 case we parse it manually and fill it again
Expand Down Expand Up @@ -133,7 +165,8 @@ struct ThreadData {
lldb_private::DataExtractor fpregset;
lldb_private::DataExtractor vregset;
lldb::tid_t tid;
int signo;
int signo = 0;
int prstatus_sig = 0;
std::string name;
};

Expand Down