Index: lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp =================================================================== --- lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -446,16 +446,47 @@ 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) { lldb::offset_t offset = 0; - int version = data.GetU32(&offset); + uint32_t version = data.GetU32(&offset); if (version != 1) - return; + return llvm::make_error( + "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( + "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; + offset += NETBSD::NT_PROCINFO_CPI_PID_SIZE; + 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 +572,140 @@ 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 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 - 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); + if (error) + return error; + } 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( + "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( + "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( + "Error parsing NetBSD core(5) notes: Unexpected order " + "of NOTEs PT_GETFPREG before PT_GETREG", + llvm::inconvertibleErrorCode()); + thread_data.notes.push_back(note); + } else { + return llvm::make_error( + "Error parsing NetBSD core(5) notes: Unsupported AMD64 NOTE", + llvm::inconvertibleErrorCode()); + } + } break; + default: + return llvm::make_error( + "Error parsing NetBSD core(5) notes: Unsupported architecture", + llvm::inconvertibleErrorCode()); + } + } else { + return llvm::make_error( + "Error parsing NetBSD core(5) notes: Unrecognized note", + llvm::inconvertibleErrorCode()); } } - 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( - "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( + "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( + "Error parsing NetBSD core(5) notes: Signal passed to unknown LWP", + llvm::inconvertibleErrorCode()); + } + return llvm::Error::success(); } Index: lldb/source/Plugins/Process/elf-core/RegisterUtilities.h =================================================================== --- lldb/source/Plugins/Process/elf-core/RegisterUtilities.h +++ lldb/source/Plugins/Process/elf-core/RegisterUtilities.h @@ -27,9 +27,42 @@ } 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 @@ // 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}, };