diff options
author | Michal Gorny <mgorny@gentoo.org> | 2019-03-08 21:10:43 +0000 |
---|---|---|
committer | Michal Gorny <mgorny@gentoo.org> | 2019-03-08 21:10:43 +0000 |
commit | c12f159788dcc791e4a415352031fb761f31c3ec (patch) | |
tree | 6bbcdf3a3a43fd093a4d92c6b9a01205acf01946 /lldb/source/Plugins/Process/elf-core | |
parent | 7a462ab7ae7d4fe45eace5942519bf305391e11f (diff) | |
download | bcm5719-llvm-c12f159788dcc791e4a415352031fb761f31c3ec.tar.gz bcm5719-llvm-c12f159788dcc791e4a415352031fb761f31c3ec.zip |
[lldb] [Process] Add proper support for NetBSD core files with threads
Improve the support for processing NetBSD cores. Fix reading process
identifier, thread information and associating the terminating signal
with the correct thread.
Includes test cases for single-threaded program receiving SIGSEGV,
and two dual-threaded programs: one where thread receives the signal,
and the other one when the whole process is signalled.
Differential Revision: https://reviews.llvm.org/D32149
llvm-svn: 355736
Diffstat (limited to 'lldb/source/Plugins/Process/elf-core')
-rw-r--r-- | lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp | 184 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/elf-core/RegisterUtilities.h | 37 |
2 files changed, 191 insertions, 30 deletions
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 9db6ebcafb0..c2579577a5c 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -446,16 +446,48 @@ static void ParseFreeBSDPrStatus(ThreadData &thread_data, thread_data.gpregset = DataExtractor(data, offset, len); } -static void ParseNetBSDProcInfo(ThreadData &thread_data, - const DataExtractor &data) { +static llvm::Error ParseNetBSDProcInfo(const DataExtractor &data, + uint32_t &cpi_nlwps, + uint32_t &cpi_signo, + uint32_t &cpi_siglwp, + uint32_t &cpi_pid) { lldb::offset_t offset = 0; - int version = data.GetU32(&offset); + uint32_t version = data.GetU32(&offset); if (version != 1) - return; + return llvm::make_error<llvm::StringError>( + "Error parsing NetBSD core(5) notes: Unsupported procinfo version", + llvm::inconvertibleErrorCode()); - offset += 4; - thread_data.signo = data.GetU32(&offset); + uint32_t cpisize = data.GetU32(&offset); + if (cpisize != NETBSD::NT_PROCINFO_SIZE) + return llvm::make_error<llvm::StringError>( + "Error parsing NetBSD core(5) notes: Unsupported procinfo size", + llvm::inconvertibleErrorCode()); + + cpi_signo = data.GetU32(&offset); /* killing signal */ + + offset += NETBSD::NT_PROCINFO_CPI_SIGCODE_SIZE; + offset += NETBSD::NT_PROCINFO_CPI_SIGPEND_SIZE; + offset += NETBSD::NT_PROCINFO_CPI_SIGMASK_SIZE; + offset += NETBSD::NT_PROCINFO_CPI_SIGIGNORE_SIZE; + offset += NETBSD::NT_PROCINFO_CPI_SIGCATCH_SIZE; + cpi_pid = data.GetU32(&offset); + offset += NETBSD::NT_PROCINFO_CPI_PPID_SIZE; + offset += NETBSD::NT_PROCINFO_CPI_PGRP_SIZE; + offset += NETBSD::NT_PROCINFO_CPI_SID_SIZE; + offset += NETBSD::NT_PROCINFO_CPI_RUID_SIZE; + offset += NETBSD::NT_PROCINFO_CPI_EUID_SIZE; + offset += NETBSD::NT_PROCINFO_CPI_SVUID_SIZE; + offset += NETBSD::NT_PROCINFO_CPI_RGID_SIZE; + offset += NETBSD::NT_PROCINFO_CPI_EGID_SIZE; + offset += NETBSD::NT_PROCINFO_CPI_SVGID_SIZE; + cpi_nlwps = data.GetU32(&offset); /* number of LWPs */ + + offset += NETBSD::NT_PROCINFO_CPI_NAME_SIZE; + cpi_siglwp = data.GetU32(&offset); /* LWP target of killing signal */ + + return llvm::Error::success(); } static void ParseOpenBSDProcInfo(ThreadData &thread_data, @@ -541,37 +573,133 @@ llvm::Error ProcessElfCore::parseFreeBSDNotes(llvm::ArrayRef<CoreNote> notes) { return llvm::Error::success(); } +/// NetBSD specific Thread context from PT_NOTE segment +/// +/// NetBSD ELF core files use notes to provide information about +/// the process's state. The note name is "NetBSD-CORE" for +/// information that is global to the process, and "NetBSD-CORE@nn", +/// where "nn" is the lwpid of the LWP that the information belongs +/// to (such as register state). +/// +/// NetBSD uses the following note identifiers: +/// +/// ELF_NOTE_NETBSD_CORE_PROCINFO (value 1) +/// Note is a "netbsd_elfcore_procinfo" structure. +/// ELF_NOTE_NETBSD_CORE_AUXV (value 2; since NetBSD 8.0) +/// Note is an array of AuxInfo structures. +/// +/// NetBSD also uses ptrace(2) request numbers (the ones that exist in +/// machine-dependent space) to identify register info notes. The +/// info in such notes is in the same format that ptrace(2) would +/// export that information. +/// +/// For more information see /usr/include/sys/exec_elf.h +/// llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) { ThreadData thread_data; - for (const auto ¬e : notes) { - // NetBSD per-thread information is stored in notes named "NetBSD-CORE@nnn" - // so match on the initial part of the string. - if (!llvm::StringRef(note.info.n_name).startswith("NetBSD-CORE")) - continue; + bool had_nt_regs = false; - switch (note.info.n_type) { - case NETBSD::NT_PROCINFO: - ParseNetBSDProcInfo(thread_data, note.data); - break; - case NETBSD::NT_AUXV: - m_auxv = note.data; - break; + // To be extracted from struct netbsd_elfcore_procinfo + // Used to sanity check of the LWPs of the process + uint32_t nlwps = 0; + uint32_t signo; // killing signal + uint32_t siglwp; // LWP target of killing signal + uint32_t pr_pid; - case NETBSD::NT_AMD64_REGS: - if (GetArchitecture().GetMachine() == llvm::Triple::x86_64) - thread_data.gpregset = note.data; - break; - default: - thread_data.notes.push_back(note); - break; + for (const auto ¬e : notes) { + llvm::StringRef name = note.info.n_name; + + if (name == "NetBSD-CORE") { + if (note.info.n_type == NETBSD::NT_PROCINFO) { + llvm::Error error = ParseNetBSDProcInfo(note.data, nlwps, signo, + siglwp, pr_pid); + if (error) + return error; + SetID(pr_pid); + } else if (note.info.n_type == NETBSD::NT_AUXV) { + m_auxv = note.data; + } + } else if (name.consume_front("NetBSD-CORE@")) { + lldb::tid_t tid; + if (name.getAsInteger(10, tid)) + return llvm::make_error<llvm::StringError>( + "Error parsing NetBSD core(5) notes: Cannot convert LWP ID " + "to integer", + llvm::inconvertibleErrorCode()); + + switch (GetArchitecture().GetMachine()) { + case llvm::Triple::x86_64: { + // Assume order PT_GETREGS, PT_GETFPREGS + if (note.info.n_type == NETBSD::AMD64::NT_REGS) { + // If this is the next thread, push the previous one first. + if (had_nt_regs) { + m_thread_data.push_back(thread_data); + thread_data = ThreadData(); + had_nt_regs = false; + } + + thread_data.gpregset = note.data; + thread_data.tid = tid; + if (thread_data.gpregset.GetByteSize() == 0) + return llvm::make_error<llvm::StringError>( + "Could not find general purpose registers note in core file.", + llvm::inconvertibleErrorCode()); + had_nt_regs = true; + } else if (note.info.n_type == NETBSD::AMD64::NT_FPREGS) { + if (!had_nt_regs || tid != thread_data.tid) + return llvm::make_error<llvm::StringError>( + "Error parsing NetBSD core(5) notes: Unexpected order " + "of NOTEs PT_GETFPREG before PT_GETREG", + llvm::inconvertibleErrorCode()); + thread_data.notes.push_back(note); + } + } break; + default: + break; + } } } - if (thread_data.gpregset.GetByteSize() == 0) { + + // Push the last thread. + if (had_nt_regs) + m_thread_data.push_back(thread_data); + + if (m_thread_data.empty()) return llvm::make_error<llvm::StringError>( - "Could not find general purpose registers note in core file.", + "Error parsing NetBSD core(5) notes: No threads information " + "specified in notes", + llvm::inconvertibleErrorCode()); + + if (m_thread_data.size() != nlwps) + return llvm::make_error<llvm::StringError>( + "Error parsing NetBSD core(5) notes: Mismatch between the number " + "of LWPs in netbsd_elfcore_procinfo and the number of LWPs specified " + "by MD notes", llvm::inconvertibleErrorCode()); + + // Signal targeted at the whole process. + if (siglwp == 0) { + for (auto &data : m_thread_data) + data.signo = signo; } - m_thread_data.push_back(thread_data); + // Signal destined for a particular LWP. + else { + bool passed = false; + + for (auto &data : m_thread_data) { + if (data.tid == siglwp) { + data.signo = signo; + passed = true; + break; + } + } + + if (!passed) + return llvm::make_error<llvm::StringError>( + "Error parsing NetBSD core(5) notes: Signal passed to unknown LWP", + llvm::inconvertibleErrorCode()); + } + return llvm::Error::success(); } diff --git a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h index a2c76d1ac20..26b0fdd6143 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h @@ -27,9 +27,42 @@ enum { } namespace NETBSD { -enum { NT_PROCINFO = 1, NT_AUXV, NT_AMD64_REGS = 33, NT_AMD64_FPREGS = 35 }; +enum { NT_PROCINFO = 1, NT_AUXV = 2 }; + +/* Size in bytes */ +enum { NT_PROCINFO_SIZE = 160 }; + +/* Size in bytes */ +enum { + NT_PROCINFO_CPI_VERSION_SIZE = 4, + NT_PROCINFO_CPI_CPISIZE_SIZE = 4, + NT_PROCINFO_CPI_SIGNO_SIZE = 4, + NT_PROCINFO_CPI_SIGCODE_SIZE = 4, + NT_PROCINFO_CPI_SIGPEND_SIZE = 16, + NT_PROCINFO_CPI_SIGMASK_SIZE = 16, + NT_PROCINFO_CPI_SIGIGNORE_SIZE = 16, + NT_PROCINFO_CPI_SIGCATCH_SIZE = 16, + NT_PROCINFO_CPI_PID_SIZE = 4, + NT_PROCINFO_CPI_PPID_SIZE = 4, + NT_PROCINFO_CPI_PGRP_SIZE = 4, + NT_PROCINFO_CPI_SID_SIZE = 4, + NT_PROCINFO_CPI_RUID_SIZE = 4, + NT_PROCINFO_CPI_EUID_SIZE = 4, + NT_PROCINFO_CPI_SVUID_SIZE = 4, + NT_PROCINFO_CPI_RGID_SIZE = 4, + NT_PROCINFO_CPI_EGID_SIZE = 4, + NT_PROCINFO_CPI_SVGID_SIZE = 4, + NT_PROCINFO_CPI_NLWPS_SIZE = 4, + NT_PROCINFO_CPI_NAME_SIZE = 32, + NT_PROCINFO_CPI_SIGLWP_SIZE = 4, +}; + +namespace AMD64 { +enum { NT_REGS = 33, NT_FPREGS = 35 }; } +} // namespace NETBSD + namespace OPENBSD { enum { NT_PROCINFO = 10, @@ -91,7 +124,7 @@ constexpr RegsetDesc FPR_Desc[] = { // The result from FXSAVE is in NT_PRXFPREG for i386 core files {llvm::Triple::Linux, llvm::Triple::x86, LINUX::NT_PRXFPREG}, {llvm::Triple::Linux, llvm::Triple::UnknownArch, LINUX::NT_FPREGSET}, - {llvm::Triple::NetBSD, llvm::Triple::x86_64, NETBSD::NT_AMD64_FPREGS}, + {llvm::Triple::NetBSD, llvm::Triple::x86_64, NETBSD::AMD64::NT_FPREGS}, {llvm::Triple::OpenBSD, llvm::Triple::UnknownArch, OPENBSD::NT_FPREGS}, }; |