Index: source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp =================================================================== --- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -52,6 +52,7 @@ const char *const LLDB_NT_OWNER_FREEBSD = "FreeBSD"; const char *const LLDB_NT_OWNER_GNU = "GNU"; const char *const LLDB_NT_OWNER_NETBSD = "NetBSD"; +const char *const LLDB_NT_OWNER_NETBSDCORE = "NetBSD-CORE"; const char *const LLDB_NT_OWNER_OPENBSD = "OpenBSD"; const char *const LLDB_NT_OWNER_CSR = "csr"; const char *const LLDB_NT_OWNER_ANDROID = "Android"; @@ -67,8 +68,10 @@ const elf_word LLDB_NT_GNU_BUILD_ID_TAG = 0x03; -const elf_word LLDB_NT_NETBSD_ABI_TAG = 0x01; -const elf_word LLDB_NT_NETBSD_ABI_SIZE = 4; +const elf_word LLDB_NT_NETBSD_NT_NETBSD_IDENT_TAG = 1; +const elf_word LLDB_NT_NETBSD_NT_NETBSD_IDENT_DESCSZ = 4; +const elf_word LLDB_NT_NETBSD_NT_NETBSD_IDENT_NAMESZ = 7; +const elf_word LLDB_NT_NETBSD_NT_PROCINFO = 1; // GNU ABI note OS constants const elf_word LLDB_NT_GNU_ABI_OS_LINUX = 0x00; @@ -288,14 +291,15 @@ return kal_arch_variant; } -static uint32_t mipsVariantFromElfFlags (const elf::ELFHeader &header) { +static uint32_t mipsVariantFromElfFlags(const elf::ELFHeader &header) { const uint32_t mips_arch = header.e_flags & llvm::ELF::EF_MIPS_ARCH; uint32_t endian = header.e_ident[EI_DATA]; uint32_t arch_variant = ArchSpec::eMIPSSubType_unknown; uint32_t fileclass = header.e_ident[EI_CLASS]; - // If there aren't any elf flags available (e.g core elf file) then return default - // 32 or 64 bit arch (without any architecture revision) based on object file's class. + // If there aren't any elf flags available (e.g core elf file) then return + // default 32 or 64 bit arch (without any architecture revision) based on + // object file's class. if (header.e_type == ET_CORE) { switch (fileclass) { case llvm::ELF::ELFCLASS32: @@ -404,8 +408,8 @@ lldb::offset_t file_offset, lldb::offset_t length) { if (!data_sp) { - data_sp = - DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset); + data_sp = DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, + file_offset); if (!data_sp) return nullptr; data_offset = 0; @@ -422,8 +426,8 @@ // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { - data_sp = - DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset); + data_sp = DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, + file_offset); if (!data_sp) return nullptr; data_offset = 0; @@ -681,7 +685,7 @@ // with a bigger data source to get the actual values. size_t section_header_end = header.e_shoff + header.e_shentsize; if (header.HasHeaderExtension() && - section_header_end > data_sp->GetByteSize()) { + section_header_end > data_sp->GetByteSize()) { data_sp = DataBufferLLVM::CreateSliceFromPath( file.GetPath(), section_header_end, file_offset); if (data_sp) { @@ -767,8 +771,8 @@ CalculateELFNotesSegmentsCRC32(program_headers, data); } else { // Need to map entire file into memory to calculate the crc. - data_sp = DataBufferLLVM::CreateSliceFromPath(file.GetPath(), -1, - file_offset); + data_sp = DataBufferLLVM::CreateSliceFromPath(file.GetPath(), + -1, file_offset); if (data_sp) { data.SetData(data_sp); gnu_debuglink_crc = calc_gnu_debuglink_crc32( @@ -1370,25 +1374,41 @@ // The note.n_name == LLDB_NT_OWNER_GNU is valid for Linux platform arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); } - // Process NetBSD ELF notes. + // Process NetBSD ELF executables and shared libraries else if ((note.n_name == LLDB_NT_OWNER_NETBSD) && - (note.n_type == LLDB_NT_NETBSD_ABI_TAG) && - (note.n_descsz == LLDB_NT_NETBSD_ABI_SIZE)) { - // Pull out the min version info. + (note.n_type == LLDB_NT_NETBSD_NT_NETBSD_IDENT_TAG) && + (note.n_descsz == LLDB_NT_NETBSD_NT_NETBSD_IDENT_DESCSZ) && + (note.n_namesz == LLDB_NT_NETBSD_NT_NETBSD_IDENT_NAMESZ)) { + // Pull out the version info uint32_t version_info; if (data.GetU32(&offset, &version_info, 1) == nullptr) { error.SetErrorString("failed to read NetBSD ABI note payload"); return error; } - + // Convert the version info into a major/minor/patch number. + // #define __NetBSD_Version__ MMmmrrpp00 + // + // M = major version + // m = minor version; a minor number of 99 indicates current. + // r = 0 (since NetBSD 3.0 not used) + // p = patchlevel + const uint32_t version_major = version_info / 100000000; + const uint32_t version_minor = (version_info % 100000000) / 1000000; + const uint32_t version_patch = (version_info % 10000) / 100; + char os_name[32]; + snprintf(os_name, sizeof(os_name), + "netbsd%" PRIu32 ".%" PRIu32 ".%" PRIu32, version_major, + version_minor, version_patch); + // Set the elf OS version to NetBSD. Also clear the vendor. + arch_spec.GetTriple().setOSName(os_name); + arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::UnknownVendor); + } + // Process NetBSD ELF core(5) notes + else if ((note.n_name == LLDB_NT_OWNER_NETBSDCORE) && + (note.n_type == LLDB_NT_NETBSD_NT_PROCINFO)) { // Set the elf OS version to NetBSD. Also clear the vendor. arch_spec.GetTriple().setOS(llvm::Triple::OSType::NetBSD); arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::UnknownVendor); - - if (log) - log->Printf( - "ObjectFileELF::%s detected NetBSD, min version constant %" PRIu32, - __FUNCTION__, version_info); } // Process OpenBSD ELF notes. else if (note.n_name == LLDB_NT_OWNER_OPENBSD) { @@ -1465,7 +1485,8 @@ return error; } llvm::StringRef path(cstr); - if (path.contains("/lib/x86_64-linux-gnu") || path.contains("/lib/i386-linux-gnu")) { + if (path.contains("/lib/x86_64-linux-gnu") || + path.contains("/lib/i386-linux-gnu")) { arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); break; } @@ -1475,7 +1496,7 @@ // In case of MIPSR6, the LLDB_NT_OWNER_GNU note is missing // for some cases (e.g. compile with -nostdlib) // Hence set OS to Linux - arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); + arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); } } @@ -1579,7 +1600,7 @@ const uint32_t sub_type = subTypeFromElfHeader(header); arch_spec.SetArchitecture(eArchTypeELF, header.e_machine, sub_type, header.e_ident[EI_OSABI]); - + // Validate if it is ok to remove GetOsFromOSABI. // Note, that now the OS is determined based on EI_OSABI flag and // the info extracted from ELF notes (see RefineModuleDetailsFromNote). @@ -2357,7 +2378,7 @@ * flag to check whether the symbol is microMIPS and then set the address * class * accordingly. - */ + */ const llvm::Triple::ArchType llvm_arch = arch.GetMachine(); if (llvm_arch == llvm::Triple::mips || llvm_arch == llvm::Triple::mipsel || @@ -3016,41 +3037,42 @@ // it have to recalculate the index first. std::vector new_symbols; - eh_frame->ForEachFDEEntries([this, symbol_table, section_list, &new_symbols]( - lldb::addr_t file_addr, uint32_t size, dw_offset_t) { - Symbol *symbol = symbol_table->FindSymbolAtFileAddress(file_addr); - if (symbol) { - if (!symbol->GetByteSizeIsValid()) { - symbol->SetByteSize(size); - symbol->SetSizeIsSynthesized(true); - } - } else { - SectionSP section_sp = - section_list->FindSectionContainingFileAddress(file_addr); - if (section_sp) { - addr_t offset = file_addr - section_sp->GetFileAddress(); - const char *symbol_name = GetNextSyntheticSymbolName().GetCString(); - uint64_t symbol_id = symbol_table->GetNumSymbols(); - Symbol eh_symbol( - symbol_id, // Symbol table index. - symbol_name, // Symbol name. - false, // Is the symbol name mangled? - eSymbolTypeCode, // Type of this symbol. - true, // Is this globally visible? - false, // Is this symbol debug info? - false, // Is this symbol a trampoline? - true, // Is this symbol artificial? - section_sp, // Section in which this symbol is defined or null. - offset, // Offset in section or symbol value. - 0, // Size: Don't specify the size as an FDE can - false, // Size is valid: cover multiple symbols. - false, // Contains linker annotations? - 0); // Symbol flags. - new_symbols.push_back(eh_symbol); - } - } - return true; - }); + eh_frame->ForEachFDEEntries( + [this, symbol_table, section_list, + &new_symbols](lldb::addr_t file_addr, uint32_t size, dw_offset_t) { + Symbol *symbol = symbol_table->FindSymbolAtFileAddress(file_addr); + if (symbol) { + if (!symbol->GetByteSizeIsValid()) { + symbol->SetByteSize(size); + symbol->SetSizeIsSynthesized(true); + } + } else { + SectionSP section_sp = + section_list->FindSectionContainingFileAddress(file_addr); + if (section_sp) { + addr_t offset = file_addr - section_sp->GetFileAddress(); + const char *symbol_name = GetNextSyntheticSymbolName().GetCString(); + uint64_t symbol_id = symbol_table->GetNumSymbols(); + Symbol eh_symbol( + symbol_id, // Symbol table index. + symbol_name, // Symbol name. + false, // Is the symbol name mangled? + eSymbolTypeCode, // Type of this symbol. + true, // Is this globally visible? + false, // Is this symbol debug info? + false, // Is this symbol a trampoline? + true, // Is this symbol artificial? + section_sp, // Section in which this symbol is defined or null. + offset, // Offset in section or symbol value. + 0, // Size: Don't specify the size as an FDE can + false, // Size is valid: cover multiple symbols. + false, // Contains linker annotations? + 0); // Symbol flags. + new_symbols.push_back(eh_symbol); + } + } + return true; + }); for (const Symbol &s : new_symbols) symbol_table->AddSymbol(s); Index: source/Plugins/Process/elf-core/ProcessElfCore.h =================================================================== --- source/Plugins/Process/elf-core/ProcessElfCore.h +++ source/Plugins/Process/elf-core/ProcessElfCore.h @@ -125,6 +125,18 @@ lldb_private::ConstString path; }; + // Parse thread(s) data structuresNetBSD(prstatus, prpsinfo) from given NOTE + // segment + lldb_private::Error ParseThreadContextsFromNoteSegmentNetBSD( + const elf::ELFProgramHeader *segment_header, + lldb_private::DataExtractor segment_data); + + // Parse thread(s) data structuresGeneric(prstatus, prpsinfo) from given NOTE + // segment + lldb_private::Error ParseThreadContextsFromNoteSegmentGeneric( + const elf::ELFProgramHeader *segment_header, + lldb_private::DataExtractor segment_data); + //------------------------------------------------------------------ // For ProcessElfCore only //------------------------------------------------------------------ Index: source/Plugins/Process/elf-core/ProcessElfCore.cpp =================================================================== --- source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -27,6 +27,7 @@ #include "lldb/Utility/DataBufferLLVM.h" #include "lldb/Utility/Log.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Threading.h" @@ -219,7 +220,7 @@ ArchSpec core_arch(m_core_module_sp->GetArchitecture()); target_arch.MergeFrom(core_arch); GetTarget().SetArchitecture(target_arch); - + SetUnixSignals(UnixSignals::Create(GetArchitecture())); // Ensure we found at least one thread that was stopped on a signal. @@ -373,7 +374,8 @@ lldb::addr_t bytes_left = 0; // Number of bytes available in the core file from the given address - // Don't proceed if core file doesn't contain the actual data for this address range. + // Don't proceed if core file doesn't contain the actual data for this address + // range. if (file_start == file_end) return 0; @@ -458,9 +460,14 @@ namespace NETBSD { -enum { NT_PROCINFO = 1, NT_AUXV, NT_AMD64_REGS = 33, NT_AMD64_FPREGS = 35 }; +enum { NT_PROCINFO = 1, NT_PROCINFO_SIZE = 160, NT_AUXV = 2 }; + +namespace AMD64 { +enum { NT_REGS = 33, NT_FPREGS = 35 }; } +} // namespace NETBSD + // Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details. static void ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data, ArchSpec &arch) { @@ -497,15 +504,29 @@ thread_data.name = data.GetCStr(&offset, 20); } -static void ParseNetBSDProcInfo(ThreadData &thread_data, DataExtractor &data) { +static Error ParseNetBSDProcInfo(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 Error( + "Error parsing NetBSD core(5) notes: Unsupported procinfo version"); - offset += 4; - thread_data.signo = data.GetU32(&offset); + uint32_t cpisize = data.GetU32(&offset); + if (cpisize != NETBSD::NT_PROCINFO_SIZE) + return Error( + "Error parsing NetBSD core(5) notes: Unsupported procinfo size"); + + cpi_signo = data.GetU32(&offset); /* killing signal */ + + offset += 108; + cpi_nlwps = data.GetU32(&offset); /* number of LWPs */ + + offset += 32; + cpi_siglwp = data.GetU32(&offset); /* LWP target of killing signal */ + + return Error(); } static void ParseOpenBSDProcInfo(ThreadData &thread_data, DataExtractor &data) { @@ -524,12 +545,28 @@ /// 1) A PT_NOTE segment is composed of one or more NOTE entries. /// 2) NOTE Entry contains a standard header followed by variable size data. /// (see ELFNote structure) -/// 3) A Thread Context in a core file usually described by 3 NOTE entries. +Error ProcessElfCore::ParseThreadContextsFromNoteSegment( + const elf::ELFProgramHeader *segment_header, DataExtractor segment_data) { + + assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE); + + switch (GetArchitecture().GetTriple().getOS()) { + case llvm::Triple::NetBSD: + return ParseThreadContextsFromNoteSegmentNetBSD(segment_header, + segment_data); + default: + return ParseThreadContextsFromNoteSegmentGeneric(segment_header, + segment_data); + } +} + +/// Generic (Linux, Android, FreeBSD, ...) Thread context from PT_NOTE segment +/// 1) A Thread Context in a core file usually described by 3 NOTE entries. /// a) NT_PRSTATUS - Register context /// b) NT_PRPSINFO - Process info(pid..) /// c) NT_FPREGSET - Floating point registers -/// 4) The NOTE entries can be in any order -/// 5) If a core file contains multiple thread contexts then there is two data +/// 2) The NOTE entries can be in any order +/// 3) If a core file contains multiple thread contexts then there is two data /// forms /// a) Each thread context(2 or more NOTE entries) contained in its own /// segment (PT_NOTE) @@ -540,8 +577,9 @@ /// new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry. /// For case (b) there may be either one NT_PRPSINFO per thread, or a single /// one that applies to all threads (depending on the platform type). -Error ProcessElfCore::ParseThreadContextsFromNoteSegment( +Error ProcessElfCore::ParseThreadContextsFromNoteSegmentGeneric( const elf::ELFProgramHeader *segment_header, DataExtractor segment_data) { + assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE); lldb::offset_t offset = 0; @@ -607,21 +645,6 @@ default: break; } - } else if (note.n_name.substr(0, 11) == "NetBSD-CORE") { - // NetBSD per-thread information is stored in notes named - // "NetBSD-CORE@nnn" so match on the initial part of the string. - m_os = llvm::Triple::NetBSD; - if (note.n_type == NETBSD::NT_PROCINFO) { - ParseNetBSDProcInfo(*thread_data, note_data); - } else if (note.n_type == NETBSD::NT_AUXV) { - m_auxv = DataExtractor(note_data); - } else if (arch.GetMachine() == llvm::Triple::x86_64 && - note.n_type == NETBSD::NT_AMD64_REGS) { - thread_data->gpregset = note_data; - } else if (arch.GetMachine() == llvm::Triple::x86_64 && - note.n_type == NETBSD::NT_AMD64_FPREGS) { - thread_data->fpregset = note_data; - } } else if (note.n_name.substr(0, 7) == "OpenBSD") { // OpenBSD per-thread information is stored in notes named // "OpenBSD@nnn" so match on the initial part of the string. @@ -659,7 +682,7 @@ // The result from FXSAVE is in NT_PRXFPREG for i386 core files if (arch.GetCore() == ArchSpec::eCore_x86_64_x86_64) thread_data->fpregset = note_data; - else if(arch.IsMIPS()) + else if (arch.IsMIPS()) thread_data->fpregset = note_data; break; case NT_PRPSINFO: @@ -717,6 +740,136 @@ return error; } +/// 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 +/// +Error ProcessElfCore::ParseThreadContextsFromNoteSegmentNetBSD( + const elf::ELFProgramHeader *segment_header, DataExtractor segment_data) { + + assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE); + + lldb::offset_t offset = 0; + ArchSpec arch = GetArchitecture(); + m_os = llvm::Triple::NetBSD; + + /* + * 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 */ + + while (offset < segment_header->p_filesz) { + ELFNote note = ELFNote(); + note.Parse(segment_data, &offset); + + size_t note_start, note_size; + note_start = offset; + note_size = llvm::alignTo(note.n_descsz, 4); + + // Store the NOTE information in the current thread + DataExtractor note_data(segment_data, note_start, note_size); + note_data.SetAddressByteSize( + m_core_module_sp->GetArchitecture().GetAddressByteSize()); + + llvm::StringRef name = note.n_name; + + if (name == "NetBSD-CORE") { + if (note.n_type == NETBSD::NT_PROCINFO) { + Error error = ParseNetBSDProcInfo(note_data, nlwps, signo, siglwp); + if (error.Fail()) + return error; + } else if (note.n_type == NETBSD::NT_AUXV) { + m_auxv = DataExtractor(note_data); + } + } else if (name.consume_front("NetBSD-CORE@")) { + lldb::tid_t tid; + if (name.getAsInteger(10, tid)) + return Error("Error parsing NetBSD core(5) notes: Cannot convert " + "LWP ID to integer"); + + switch (arch.GetMachine()) { + case llvm::Triple::x86_64: { + /* Assume order PT_GETREGS, PT_GETFPREGS */ + if (note.n_type == NETBSD::AMD64::NT_REGS) { + m_thread_data.push_back(ThreadData()); + m_thread_data.back().gpregset = note_data; + m_thread_data.back().tid = tid; + } else if (note.n_type == NETBSD::AMD64::NT_FPREGS) { + if (m_thread_data.empty() || tid != m_thread_data.back().tid) + return Error("Error parsing NetBSD core(5) notes: Unexpected order " + "of NOTEs PT_GETFPREG before PT_GETREG"); + m_thread_data.back().fpregset = note_data; + } else { + return Error( + "Error parsing NetBSD core(5) notes: Unsupported AMD64 NOTE"); + } + } break; + default: + return Error( + "Error parsing NetBSD core(5) notes: Unsupported architecture"); + } + } else { + return Error("Error parsing NetBSD core(5) notes: Unrecognized note"); + } + + offset += note_size; + } + + if (m_thread_data.empty()) + return Error("Error parsing NetBSD core(5) notes: No threads information " + "specified in notes"); + + if (m_thread_data.size() != nlwps) + return Error("rror parsing NetBSD core(5) notes: Mismatch between the " + "number of LWPs in netbsd_elfcore_procinfo and the number of " + "LWPs specified by MD notes"); + + /* The whole process signal */ + if (siglwp == 0) { + for (auto &data : m_thread_data) + data.signo = signo; + } + /* Signal destinated 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 Error( + "Error parsing NetBSD core(5) notes: Signal passed to unknown LWP"); + } + + return Error(); +} + uint32_t ProcessElfCore::GetNumThreadContexts() { if (!m_thread_data_valid) DoLoadCore(); @@ -730,7 +883,7 @@ core_file->GetArchitecture(arch); ArchSpec target_arch = GetTarget().GetArchitecture(); - + if (target_arch.IsMIPS()) return target_arch;