diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:06:29 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:06:29 +0000 |
commit | 94994d372d014ce4c8758b9605d63fae651bd8aa (patch) | |
tree | 51c0b708bd59f205d6b35cb2a8c24d62f0c33d77 /source/Plugins/ObjectFile | |
parent | 39be7ce23363d12ae3e49aeb1fdb2bfeb892e836 (diff) |
Notes
Diffstat (limited to 'source/Plugins/ObjectFile')
-rw-r--r-- | source/Plugins/ObjectFile/Breakpad/CMakeLists.txt | 11 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp | 315 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h | 109 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/CMakeLists.txt | 3 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/ELF/ELFHeader.cpp | 29 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 735 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/ELF/ObjectFileELF.h | 28 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp | 16 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/JIT/ObjectFileJIT.h | 8 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp | 435 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h | 21 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 441 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h | 19 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp | 2 |
14 files changed, 1455 insertions, 717 deletions
diff --git a/source/Plugins/ObjectFile/Breakpad/CMakeLists.txt b/source/Plugins/ObjectFile/Breakpad/CMakeLists.txt new file mode 100644 index 000000000000..2f51b2c8719a --- /dev/null +++ b/source/Plugins/ObjectFile/Breakpad/CMakeLists.txt @@ -0,0 +1,11 @@ +add_lldb_library(lldbPluginObjectFileBreakpad PLUGIN + ObjectFileBreakpad.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbUtility + LINK_COMPONENTS + Support + ) diff --git a/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp b/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp new file mode 100644 index 000000000000..917025030ada --- /dev/null +++ b/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp @@ -0,0 +1,315 @@ +//===-- ObjectFileBreakpad.cpp -------------------------------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Utility/DataBuffer.h" +#include "llvm/ADT/StringExtras.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::breakpad; + +namespace { +struct Header { + ArchSpec arch; + UUID uuid; + static llvm::Optional<Header> parse(llvm::StringRef text); +}; + +enum class Token { Unknown, Module, Info, File, Func, Public, Stack }; +} // namespace + +static Token toToken(llvm::StringRef str) { + return llvm::StringSwitch<Token>(str) + .Case("MODULE", Token::Module) + .Case("INFO", Token::Info) + .Case("FILE", Token::File) + .Case("FUNC", Token::Func) + .Case("PUBLIC", Token::Public) + .Case("STACK", Token::Stack) + .Default(Token::Unknown); +} + +static llvm::StringRef toString(Token t) { + switch (t) { + case Token::Unknown: + return ""; + case Token::Module: + return "MODULE"; + case Token::Info: + return "INFO"; + case Token::File: + return "FILE"; + case Token::Func: + return "FUNC"; + case Token::Public: + return "PUBLIC"; + case Token::Stack: + return "STACK"; + } + llvm_unreachable("Unknown token!"); +} + +static llvm::Triple::OSType toOS(llvm::StringRef str) { + using llvm::Triple; + return llvm::StringSwitch<Triple::OSType>(str) + .Case("Linux", Triple::Linux) + .Case("mac", Triple::MacOSX) + .Case("windows", Triple::Win32) + .Default(Triple::UnknownOS); +} + +static llvm::Triple::ArchType toArch(llvm::StringRef str) { + using llvm::Triple; + return llvm::StringSwitch<Triple::ArchType>(str) + .Case("arm", Triple::arm) + .Case("arm64", Triple::aarch64) + .Case("mips", Triple::mips) + .Case("ppc", Triple::ppc) + .Case("ppc64", Triple::ppc64) + .Case("s390", Triple::systemz) + .Case("sparc", Triple::sparc) + .Case("sparcv9", Triple::sparcv9) + .Case("x86", Triple::x86) + .Case("x86_64", Triple::x86_64) + .Default(Triple::UnknownArch); +} + +static llvm::StringRef consume_front(llvm::StringRef &str, size_t n) { + llvm::StringRef result = str.take_front(n); + str = str.drop_front(n); + return result; +} + +static UUID parseModuleId(llvm::Triple::OSType os, llvm::StringRef str) { + struct uuid_data { + llvm::support::ulittle32_t uuid1; + llvm::support::ulittle16_t uuid2[2]; + uint8_t uuid3[8]; + llvm::support::ulittle32_t age; + } data; + static_assert(sizeof(data) == 20, ""); + // The textual module id encoding should be between 33 and 40 bytes long, + // depending on the size of the age field, which is of variable length. + // The first three chunks of the id are encoded in big endian, so we need to + // byte-swap those. + if (str.size() < 33 || str.size() > 40) + return UUID(); + uint32_t t; + if (to_integer(consume_front(str, 8), t, 16)) + data.uuid1 = t; + else + return UUID(); + for (int i = 0; i < 2; ++i) { + if (to_integer(consume_front(str, 4), t, 16)) + data.uuid2[i] = t; + else + return UUID(); + } + for (int i = 0; i < 8; ++i) { + if (!to_integer(consume_front(str, 2), data.uuid3[i], 16)) + return UUID(); + } + if (to_integer(str, t, 16)) + data.age = t; + else + return UUID(); + + // On non-windows, the age field should always be zero, so we don't include to + // match the native uuid format of these platforms. + return UUID::fromData(&data, os == llvm::Triple::Win32 ? 20 : 16); +} + +llvm::Optional<Header> Header::parse(llvm::StringRef text) { + // A valid module should start with something like: + // MODULE Linux x86_64 E5894855C35DCCCCCCCCCCCCCCCCCCCC0 a.out + // optionally followed by + // INFO CODE_ID 554889E55DC3CCCCCCCCCCCCCCCCCCCC [a.exe] + llvm::StringRef token, line; + std::tie(line, text) = text.split('\n'); + std::tie(token, line) = getToken(line); + if (toToken(token) != Token::Module) + return llvm::None; + + std::tie(token, line) = getToken(line); + llvm::Triple triple; + triple.setOS(toOS(token)); + if (triple.getOS() == llvm::Triple::UnknownOS) + return llvm::None; + + std::tie(token, line) = getToken(line); + triple.setArch(toArch(token)); + if (triple.getArch() == llvm::Triple::UnknownArch) + return llvm::None; + + llvm::StringRef module_id; + std::tie(module_id, line) = getToken(line); + + std::tie(line, text) = text.split('\n'); + std::tie(token, line) = getToken(line); + if (token == "INFO") { + std::tie(token, line) = getToken(line); + if (token != "CODE_ID") + return llvm::None; + + std::tie(token, line) = getToken(line); + // If we don't have any text following the code id (e.g. on linux), we + // should use the module id as UUID. Otherwise, we revert back to the module + // id. + if (line.trim().empty()) { + UUID uuid; + if (uuid.SetFromStringRef(token, token.size() / 2) != token.size()) + return llvm::None; + + return Header{ArchSpec(triple), uuid}; + } + } + + // We reach here if we don't have a INFO CODE_ID section, or we chose not to + // use it. In either case, we need to properly decode the module id, whose + // fields are encoded in big-endian. + UUID uuid = parseModuleId(triple.getOS(), module_id); + if (!uuid) + return llvm::None; + + return Header{ArchSpec(triple), uuid}; +} + +void ObjectFileBreakpad::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileBreakpad::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ConstString ObjectFileBreakpad::GetPluginNameStatic() { + static ConstString g_name("breakpad"); + return g_name; +} + +ObjectFile *ObjectFileBreakpad::CreateInstance( + const ModuleSP &module_sp, DataBufferSP &data_sp, offset_t data_offset, + const FileSpec *file, offset_t file_offset, offset_t length) { + if (!data_sp) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + auto text = toStringRef(data_sp->GetData()); + llvm::Optional<Header> header = Header::parse(text); + if (!header) + return nullptr; + + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + + return new ObjectFileBreakpad(module_sp, data_sp, data_offset, file, + file_offset, length, std::move(header->arch), + std::move(header->uuid)); +} + +ObjectFile *ObjectFileBreakpad::CreateMemoryInstance( + const ModuleSP &module_sp, DataBufferSP &data_sp, + const ProcessSP &process_sp, addr_t header_addr) { + return nullptr; +} + +size_t ObjectFileBreakpad::GetModuleSpecifications( + const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, + offset_t file_offset, offset_t length, ModuleSpecList &specs) { + auto text = toStringRef(data_sp->GetData()); + llvm::Optional<Header> header = Header::parse(text); + if (!header) + return 0; + ModuleSpec spec(file, std::move(header->arch)); + spec.GetUUID() = std::move(header->uuid); + specs.Append(spec); + return 1; +} + +ObjectFileBreakpad::ObjectFileBreakpad(const ModuleSP &module_sp, + DataBufferSP &data_sp, + offset_t data_offset, + const FileSpec *file, offset_t offset, + offset_t length, ArchSpec arch, + UUID uuid) + : ObjectFile(module_sp, file, offset, length, data_sp, data_offset), + m_arch(std::move(arch)), m_uuid(std::move(uuid)) {} + +bool ObjectFileBreakpad::ParseHeader() { + // We already parsed the header during initialization. + return true; +} + +Symtab *ObjectFileBreakpad::GetSymtab() { + // TODO + return nullptr; +} + +bool ObjectFileBreakpad::GetUUID(UUID *uuid) { + *uuid = m_uuid; + return true; +} + +void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) { + if (m_sections_ap) + return; + m_sections_ap = llvm::make_unique<SectionList>(); + + Token current_section = Token::Unknown; + offset_t section_start; + llvm::StringRef text = toStringRef(m_data.GetData()); + uint32_t next_section_id = 1; + auto maybe_add_section = [&](const uint8_t *end_ptr) { + if (current_section == Token::Unknown) + return; // We have been called before parsing the first line. + + offset_t end_offset = end_ptr - m_data.GetDataStart(); + auto section_sp = std::make_shared<Section>( + GetModule(), this, next_section_id++, + ConstString(toString(current_section)), eSectionTypeOther, + /*file_vm_addr*/ 0, /*vm_size*/ 0, section_start, + end_offset - section_start, /*log2align*/ 0, /*flags*/ 0); + m_sections_ap->AddSection(section_sp); + unified_section_list.AddSection(section_sp); + }; + while (!text.empty()) { + llvm::StringRef line; + std::tie(line, text) = text.split('\n'); + + Token token = toToken(getToken(line).first); + if (token == Token::Unknown) { + // We assume this is a line record, which logically belongs to the Func + // section. Errors will be handled when parsing the Func section. + token = Token::Func; + } + if (token == current_section) + continue; + + // Changing sections, finish off the previous one, if there was any. + maybe_add_section(line.bytes_begin()); + // And start a new one. + current_section = token; + section_start = line.bytes_begin() - m_data.GetDataStart(); + } + // Finally, add the last section. + maybe_add_section(m_data.GetDataEnd()); +} diff --git a/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h b/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h new file mode 100644 index 000000000000..ba2a3ad30e5f --- /dev/null +++ b/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h @@ -0,0 +1,109 @@ +//===-- ObjectFileBreakpad.h ---------------------------------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H +#define LLDB_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "llvm/ADT/Triple.h" + +namespace lldb_private { +namespace breakpad { + +class ObjectFileBreakpad : public ObjectFile { +public: + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + static void Terminate(); + + static ConstString GetPluginNameStatic(); + static const char *GetPluginDescriptionStatic() { + return "Breakpad object file reader."; + } + + static ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static ObjectFile *CreateMemoryInstance(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &data_sp, + const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + ModuleSpecList &specs); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + ConstString GetPluginName() override { return GetPluginNameStatic(); } + + uint32_t GetPluginVersion() override { return 1; } + + //------------------------------------------------------------------ + // ObjectFile Protocol. + //------------------------------------------------------------------ + + bool ParseHeader() override; + + lldb::ByteOrder GetByteOrder() const override { + return m_arch.GetByteOrder(); + } + + bool IsExecutable() const override { return false; } + + uint32_t GetAddressByteSize() const override { + return m_arch.GetAddressByteSize(); + } + + AddressClass GetAddressClass(lldb::addr_t file_addr) override { + return AddressClass::eInvalid; + } + + Symtab *GetSymtab() override; + + bool IsStripped() override { return false; } + + void CreateSections(SectionList &unified_section_list) override; + + void Dump(Stream *s) override {} + + ArchSpec GetArchitecture() override { return m_arch; } + + bool GetUUID(UUID *uuid) override; + + FileSpecList GetDebugSymbolFilePaths() override { return FileSpecList(); } + + uint32_t GetDependentModules(FileSpecList &files) override { return 0; } + + Type CalculateType() override { return eTypeDebugInfo; } + + Strata CalculateStrata() override { return eStrataUser; } + +private: + ArchSpec m_arch; + UUID m_uuid; + + ObjectFileBreakpad(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, + const FileSpec *file, lldb::offset_t offset, + lldb::offset_t length, ArchSpec arch, UUID uuid); +}; + +} // namespace breakpad +} // namespace lldb_private +#endif // LLDB_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H diff --git a/source/Plugins/ObjectFile/CMakeLists.txt b/source/Plugins/ObjectFile/CMakeLists.txt index 06aa01c4f004..4edd667b9723 100644 --- a/source/Plugins/ObjectFile/CMakeLists.txt +++ b/source/Plugins/ObjectFile/CMakeLists.txt @@ -1,4 +1,5 @@ +add_subdirectory(Breakpad) add_subdirectory(ELF) add_subdirectory(Mach-O) add_subdirectory(PECOFF) -add_subdirectory(JIT)
\ No newline at end of file +add_subdirectory(JIT) diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp index 16cbb6e5753b..3d4735286bf2 100644 --- a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -38,7 +38,7 @@ static bool GetMaxU64(const lldb_private::DataExtractor &data, lldb::offset_t saved_offset = *offset; for (uint32_t i = 0; i < count; ++i, ++value) { - if (GetMaxU64(data, offset, value, byte_size) == false) { + if (!GetMaxU64(data, offset, value, byte_size)) { *offset = saved_offset; return false; } @@ -60,7 +60,7 @@ static bool GetMaxS64(const lldb_private::DataExtractor &data, lldb::offset_t saved_offset = *offset; for (uint32_t i = 0; i < count; ++i, ++value) { - if (GetMaxS64(data, offset, value, byte_size) == false) { + if (!GetMaxS64(data, offset, value, byte_size)) { *offset = saved_offset; return false; } @@ -133,7 +133,7 @@ bool ELFHeader::Parse(lldb_private::DataExtractor &data, return false; // Read e_entry, e_phoff and e_shoff. - if (GetMaxU64(data, offset, &e_entry, byte_size, 3) == false) + if (!GetMaxU64(data, offset, &e_entry, byte_size, 3)) return false; // Read e_flags. @@ -232,11 +232,11 @@ bool ELFSectionHeader::Parse(const lldb_private::DataExtractor &data, return false; // Read sh_flags. - if (GetMaxU64(data, offset, &sh_flags, byte_size) == false) + if (!GetMaxU64(data, offset, &sh_flags, byte_size)) return false; // Read sh_addr, sh_off and sh_size. - if (GetMaxU64(data, offset, &sh_addr, byte_size, 3) == false) + if (!GetMaxU64(data, offset, &sh_addr, byte_size, 3)) return false; // Read sh_link and sh_info. @@ -244,7 +244,7 @@ bool ELFSectionHeader::Parse(const lldb_private::DataExtractor &data, return false; // Read sh_addralign and sh_entsize. - if (GetMaxU64(data, offset, &sh_addralign, byte_size, 2) == false) + if (!GetMaxU64(data, offset, &sh_addralign, byte_size, 2)) return false; return true; @@ -332,7 +332,7 @@ bool ELFSymbol::Parse(const lldb_private::DataExtractor &data, if (parsing_32) { // Read st_value and st_size. - if (GetMaxU64(data, offset, &st_value, byte_size, 2) == false) + if (!GetMaxU64(data, offset, &st_value, byte_size, 2)) return false; // Read st_info and st_other. @@ -376,7 +376,7 @@ bool ELFProgramHeader::Parse(const lldb_private::DataExtractor &data, if (parsing_32) { // Read p_offset, p_vaddr, p_paddr, p_filesz and p_memsz. - if (GetMaxU64(data, offset, &p_offset, byte_size, 5) == false) + if (!GetMaxU64(data, offset, &p_offset, byte_size, 5)) return false; // Read p_flags. @@ -384,7 +384,7 @@ bool ELFProgramHeader::Parse(const lldb_private::DataExtractor &data, return false; // Read p_align. - if (GetMaxU64(data, offset, &p_align, byte_size) == false) + if (!GetMaxU64(data, offset, &p_align, byte_size)) return false; } else { // Read p_flags. @@ -392,7 +392,7 @@ bool ELFProgramHeader::Parse(const lldb_private::DataExtractor &data, return false; // Read p_offset, p_vaddr, p_paddr, p_filesz, p_memsz and p_align. - if (GetMaxU64(data, offset, &p_offset, byte_size, 6) == false) + if (!GetMaxU64(data, offset, &p_offset, byte_size, 6)) return false; } @@ -420,10 +420,7 @@ bool ELFRel::Parse(const lldb_private::DataExtractor &data, const unsigned byte_size = data.GetAddressByteSize(); // Read r_offset and r_info. - if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false) - return false; - - return true; + return GetMaxU64(data, offset, &r_offset, byte_size, 2) != false; } //------------------------------------------------------------------------------ @@ -436,11 +433,11 @@ bool ELFRela::Parse(const lldb_private::DataExtractor &data, const unsigned byte_size = data.GetAddressByteSize(); // Read r_offset and r_info. - if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false) + if (!GetMaxU64(data, offset, &r_offset, byte_size, 2)) return false; // Read r_addend; - if (GetMaxS64(data, offset, &r_addend, byte_size) == false) + if (!GetMaxS64(data, offset, &r_addend, byte_size)) return false; return true; diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 8701908378f1..9a6563afa0a0 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -17,7 +17,9 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/RangeMap.h" #include "lldb/Core/Section.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/SectionLoadList.h" @@ -29,6 +31,7 @@ #include "lldb/Utility/Stream.h" #include "lldb/Utility/Timer.h" +#include "llvm/ADT/IntervalMap.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/Decompressor.h" @@ -235,6 +238,8 @@ unsigned ELFRelocation::RelocAddend64(const ELFRelocation &rel) { } // end anonymous namespace +static user_id_t SegmentID(size_t PHdrIndex) { return ~PHdrIndex; } + bool ELFNote::Parse(const DataExtractor &data, lldb::offset_t *offset) { // Read all fields. if (data.GetU32(offset, &n_namesz, 3) == NULL) @@ -433,9 +438,8 @@ ObjectFile *ObjectFileELF::CreateInstance(const lldb::ModuleSP &module_sp, if (address_size == 4 || address_size == 8) { std::unique_ptr<ObjectFileELF> objfile_ap(new ObjectFileELF( module_sp, data_sp, data_offset, file, file_offset, length)); - ArchSpec spec; - if (objfile_ap->GetArchitecture(spec) && - objfile_ap->SetModulesArchitecture(spec)) + ArchSpec spec = objfile_ap->GetArchitecture(); + if (spec && objfile_ap->SetModulesArchitecture(spec)) return objfile_ap.release(); } @@ -452,9 +456,8 @@ ObjectFile *ObjectFileELF::CreateMemoryInstance( if (address_size == 4 || address_size == 8) { std::unique_ptr<ObjectFileELF> objfile_ap( new ObjectFileELF(module_sp, data_sp, process_sp, header_addr)); - ArchSpec spec; - if (objfile_ap->GetArchitecture(spec) && - objfile_ap->SetModulesArchitecture(spec)) + ArchSpec spec = objfile_ap->GetArchitecture(); + if (spec && objfile_ap->SetModulesArchitecture(spec)) return objfile_ap.release(); } } @@ -538,14 +541,13 @@ static uint32_t calc_gnu_debuglink_crc32(const void *buf, size_t size) { uint32_t ObjectFileELF::CalculateELFNotesSegmentsCRC32( const ProgramHeaderColl &program_headers, DataExtractor &object_data) { - typedef ProgramHeaderCollConstIter Iter; uint32_t core_notes_crc = 0; - for (Iter I = program_headers.begin(); I != program_headers.end(); ++I) { - if (I->p_type == llvm::ELF::PT_NOTE) { - const elf_off ph_offset = I->p_offset; - const size_t ph_size = I->p_filesz; + for (const ELFProgramHeader &H : program_headers) { + if (H.p_type == llvm::ELF::PT_NOTE) { + const elf_off ph_offset = H.p_offset; + const size_t ph_size = H.p_filesz; DataExtractor segment_data; if (segment_data.SetData(object_data, ph_offset, ph_size) != ph_size) { @@ -713,7 +715,8 @@ size_t ObjectFileELF::GetModuleSpecifications( func_cat, "Calculating module crc32 %s with size %" PRIu64 " KiB", file.GetLastPathComponent().AsCString(), - (file.GetByteSize() - file_offset) / 1024); + (FileSystem::Instance().GetByteSize(file) - file_offset) / + 1024); // For core files - which usually don't happen to have a // gnu_debuglink, and are pretty bulky - calculating whole @@ -803,21 +806,10 @@ bool ObjectFileELF::SetLoadAddress(Target &target, lldb::addr_t value, SectionList *section_list = GetSectionList(); if (section_list) { if (!value_is_offset) { - bool found_offset = false; - for (size_t i = 1, count = GetProgramHeaderCount(); i <= count; ++i) { - const elf::ELFProgramHeader *header = GetProgramHeaderByIndex(i); - if (header == nullptr) - continue; - - if (header->p_type != PT_LOAD || header->p_offset != 0) - continue; - - value = value - header->p_vaddr; - found_offset = true; - break; - } - if (!found_offset) + addr_t base = GetBaseAddress().GetFileAddress(); + if (base == LLDB_INVALID_ADDRESS) return false; + value -= base; } const size_t num_sections = section_list->GetSize(); @@ -827,7 +819,8 @@ bool ObjectFileELF::SetLoadAddress(Target &target, lldb::addr_t value, // Iterate through the object file sections to find all of the sections // that have SHF_ALLOC in their flag bits. SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); - if (section_sp && section_sp->Test(SHF_ALLOC)) { + if (section_sp->Test(SHF_ALLOC) || + section_sp->GetType() == eSectionTypeContainer) { lldb::addr_t load_addr = section_sp->GetFileAddress(); // We don't want to update the load address of a section with type // eSectionTypeAbsoluteAddress as they already have the absolute load @@ -892,11 +885,11 @@ AddressClass ObjectFileELF::GetAddressClass(addr_t file_addr) { } size_t ObjectFileELF::SectionIndex(const SectionHeaderCollIter &I) { - return std::distance(m_section_headers.begin(), I) + 1u; + return std::distance(m_section_headers.begin(), I); } size_t ObjectFileELF::SectionIndex(const SectionHeaderCollConstIter &I) const { - return std::distance(m_section_headers.begin(), I) + 1u; + return std::distance(m_section_headers.begin(), I); } bool ObjectFileELF::ParseHeader() { @@ -953,7 +946,7 @@ lldb_private::FileSpecList ObjectFileELF::GetDebugSymbolFilePaths() { FileSpecList file_spec_list; if (!m_gnu_debuglink_file.empty()) { - FileSpec file_spec(m_gnu_debuglink_file, false); + FileSpec file_spec(m_gnu_debuglink_file); file_spec_list.Append(file_spec); } return file_spec_list; @@ -1055,6 +1048,18 @@ lldb_private::Address ObjectFileELF::GetEntryPointAddress() { return m_entry_point_address; } +Address ObjectFileELF::GetBaseAddress() { + for (const auto &EnumPHdr : llvm::enumerate(ProgramHeaders())) { + const ELFProgramHeader &H = EnumPHdr.value(); + if (H.p_type != PT_LOAD) + continue; + + return Address( + GetSectionList()->FindSectionByID(SegmentID(EnumPHdr.index())), 0); + } + return LLDB_INVALID_ADDRESS; +} + //---------------------------------------------------------------------- // ParseDependentModules //---------------------------------------------------------------------- @@ -1084,7 +1089,7 @@ size_t ObjectFileELF::ParseDependentModules() { return 0; // sh_link: section header index of string table used by entries in the // section. - Section *dynstr = section_list->FindSectionByID(header->sh_link + 1).get(); + Section *dynstr = section_list->FindSectionByID(header->sh_link).get(); if (!dynstr) return 0; @@ -1107,7 +1112,9 @@ size_t ObjectFileELF::ParseDependentModules() { uint32_t str_index = static_cast<uint32_t>(symbol.d_val); const char *lib_name = dynstr_data.PeekCStr(str_index); - m_filespec_ap->Append(FileSpec(lib_name, true)); + FileSpec file_spec(lib_name); + FileSystem::Instance().Resolve(file_spec); + m_filespec_ap->Append(file_spec); } } @@ -1141,7 +1148,7 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers, uint32_t idx; lldb::offset_t offset; for (idx = 0, offset = 0; idx < header.e_phnum; ++idx) { - if (program_headers[idx].Parse(data, &offset) == false) + if (!program_headers[idx].Parse(data, &offset)) break; } @@ -1154,8 +1161,8 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers, //---------------------------------------------------------------------- // ParseProgramHeaders //---------------------------------------------------------------------- -size_t ObjectFileELF::ParseProgramHeaders() { - return GetProgramHeaderInfo(m_program_headers, m_data, m_header); +bool ObjectFileELF::ParseProgramHeaders() { + return GetProgramHeaderInfo(m_program_headers, m_data, m_header) != 0; } lldb_private::Status @@ -1390,7 +1397,7 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, arch_spec.GetTriple().getOS() == llvm::Triple::OSType::UnknownOS) // 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); } } @@ -1494,7 +1501,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, 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). However in some cases that still @@ -1553,7 +1560,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, uint32_t idx; lldb::offset_t offset; for (idx = 0, offset = 0; idx < header.e_shnum; ++idx) { - if (section_headers[idx].Parse(sh_data, &offset) == false) + if (!section_headers[idx].Parse(sh_data, &offset)) break; } if (idx < section_headers.size()) @@ -1701,27 +1708,6 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, return 0; } -size_t ObjectFileELF::GetProgramHeaderCount() { return ParseProgramHeaders(); } - -const elf::ELFProgramHeader * -ObjectFileELF::GetProgramHeaderByIndex(lldb::user_id_t id) { - if (!id || !ParseProgramHeaders()) - return NULL; - - if (--id < m_program_headers.size()) - return &m_program_headers[id]; - - return NULL; -} - -DataExtractor ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id) { - const elf::ELFProgramHeader *segment_header = GetProgramHeaderByIndex(id); - if (segment_header == NULL) - return DataExtractor(); - return DataExtractor(m_data, segment_header->p_offset, - segment_header->p_filesz); -} - llvm::StringRef ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { size_t pos = symbol_name.find('@'); @@ -1739,10 +1725,10 @@ size_t ObjectFileELF::ParseSectionHeaders() { const ObjectFileELF::ELFSectionHeaderInfo * ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id) { - if (!id || !ParseSectionHeaders()) + if (!ParseSectionHeaders()) return NULL; - if (--id < m_section_headers.size()) + if (id < m_section_headers.size()) return &m_section_headers[id]; return NULL; @@ -1757,233 +1743,273 @@ lldb::user_id_t ObjectFileELF::GetSectionIndexByName(const char *name) { return 0; } -void ObjectFileELF::CreateSections(SectionList &unified_section_list) { - if (!m_sections_ap.get() && ParseSectionHeaders()) { - m_sections_ap.reset(new SectionList()); - - // Object files frequently have 0 for every section address, meaning we - // need to compute synthetic addresses in order for "file addresses" from - // different sections to not overlap - bool synthaddrs = (CalculateType() == ObjectFile::Type::eTypeObjectFile); - uint64_t nextaddr = 0; - - for (SectionHeaderCollIter I = m_section_headers.begin(); - I != m_section_headers.end(); ++I) { - const ELFSectionHeaderInfo &header = *I; - - ConstString &name = I->section_name; - const uint64_t file_size = - header.sh_type == SHT_NOBITS ? 0 : header.sh_size; - const uint64_t vm_size = header.sh_flags & SHF_ALLOC ? header.sh_size : 0; - - static ConstString g_sect_name_text(".text"); - static ConstString g_sect_name_data(".data"); - static ConstString g_sect_name_bss(".bss"); - static ConstString g_sect_name_tdata(".tdata"); - static ConstString g_sect_name_tbss(".tbss"); - static ConstString g_sect_name_dwarf_debug_abbrev(".debug_abbrev"); - static ConstString g_sect_name_dwarf_debug_addr(".debug_addr"); - static ConstString g_sect_name_dwarf_debug_aranges(".debug_aranges"); - static ConstString g_sect_name_dwarf_debug_cu_index(".debug_cu_index"); - static ConstString g_sect_name_dwarf_debug_frame(".debug_frame"); - static ConstString g_sect_name_dwarf_debug_info(".debug_info"); - static ConstString g_sect_name_dwarf_debug_line(".debug_line"); - static ConstString g_sect_name_dwarf_debug_loc(".debug_loc"); - static ConstString g_sect_name_dwarf_debug_macinfo(".debug_macinfo"); - static ConstString g_sect_name_dwarf_debug_macro(".debug_macro"); - static ConstString g_sect_name_dwarf_debug_names(".debug_names"); - static ConstString g_sect_name_dwarf_debug_pubnames(".debug_pubnames"); - static ConstString g_sect_name_dwarf_debug_pubtypes(".debug_pubtypes"); - static ConstString g_sect_name_dwarf_debug_ranges(".debug_ranges"); - static ConstString g_sect_name_dwarf_debug_str(".debug_str"); - static ConstString g_sect_name_dwarf_debug_str_offsets( - ".debug_str_offsets"); - static ConstString g_sect_name_dwarf_debug_abbrev_dwo( - ".debug_abbrev.dwo"); - static ConstString g_sect_name_dwarf_debug_info_dwo(".debug_info.dwo"); - static ConstString g_sect_name_dwarf_debug_line_dwo(".debug_line.dwo"); - static ConstString g_sect_name_dwarf_debug_macro_dwo(".debug_macro.dwo"); - static ConstString g_sect_name_dwarf_debug_loc_dwo(".debug_loc.dwo"); - static ConstString g_sect_name_dwarf_debug_str_dwo(".debug_str.dwo"); - static ConstString g_sect_name_dwarf_debug_str_offsets_dwo( - ".debug_str_offsets.dwo"); - static ConstString g_sect_name_dwarf_debug_types(".debug_types"); - static ConstString g_sect_name_eh_frame(".eh_frame"); - static ConstString g_sect_name_arm_exidx(".ARM.exidx"); - static ConstString g_sect_name_arm_extab(".ARM.extab"); - static ConstString g_sect_name_go_symtab(".gosymtab"); - static ConstString g_sect_name_dwarf_gnu_debugaltlink(".gnu_debugaltlink"); - - SectionType sect_type = eSectionTypeOther; - - bool is_thread_specific = false; - - if (name == g_sect_name_text) - sect_type = eSectionTypeCode; - else if (name == g_sect_name_data) - sect_type = eSectionTypeData; - else if (name == g_sect_name_bss) - sect_type = eSectionTypeZeroFill; - else if (name == g_sect_name_tdata) { - sect_type = eSectionTypeData; - is_thread_specific = true; - } else if (name == g_sect_name_tbss) { - sect_type = eSectionTypeZeroFill; - is_thread_specific = true; - } - // .debug_abbrev – Abbreviations used in the .debug_info section - // .debug_aranges – Lookup table for mapping addresses to compilation - // units .debug_frame – Call frame information .debug_info – The core - // DWARF information section .debug_line – Line number information - // .debug_loc – Location lists used in DW_AT_location attributes - // .debug_macinfo – Macro information .debug_pubnames – Lookup table - // for mapping object and function names to compilation units - // .debug_pubtypes – Lookup table for mapping type names to compilation - // units .debug_ranges – Address ranges used in DW_AT_ranges attributes - // .debug_str – String table used in .debug_info MISSING? - // .gnu_debugdata - "mini debuginfo / MiniDebugInfo" section, - // http://sourceware.org/gdb/onlinedocs/gdb/MiniDebugInfo.html MISSING? - // .debug-index - http://src.chromium.org/viewvc/chrome/trunk/src/build - // /gdb-add-index?pathrev=144644 MISSING? .debug_types - Type - // descriptions from DWARF 4? See - // http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo - else if (name == g_sect_name_dwarf_debug_abbrev) - sect_type = eSectionTypeDWARFDebugAbbrev; - else if (name == g_sect_name_dwarf_debug_addr) - sect_type = eSectionTypeDWARFDebugAddr; - else if (name == g_sect_name_dwarf_debug_aranges) - sect_type = eSectionTypeDWARFDebugAranges; - else if (name == g_sect_name_dwarf_debug_cu_index) - sect_type = eSectionTypeDWARFDebugCuIndex; - else if (name == g_sect_name_dwarf_debug_frame) - sect_type = eSectionTypeDWARFDebugFrame; - else if (name == g_sect_name_dwarf_debug_info) - sect_type = eSectionTypeDWARFDebugInfo; - else if (name == g_sect_name_dwarf_debug_line) - sect_type = eSectionTypeDWARFDebugLine; - else if (name == g_sect_name_dwarf_debug_loc) - sect_type = eSectionTypeDWARFDebugLoc; - else if (name == g_sect_name_dwarf_debug_macinfo) - sect_type = eSectionTypeDWARFDebugMacInfo; - else if (name == g_sect_name_dwarf_debug_macro) - sect_type = eSectionTypeDWARFDebugMacro; - else if (name == g_sect_name_dwarf_debug_names) - sect_type = eSectionTypeDWARFDebugNames; - else if (name == g_sect_name_dwarf_debug_pubnames) - sect_type = eSectionTypeDWARFDebugPubNames; - else if (name == g_sect_name_dwarf_debug_pubtypes) - sect_type = eSectionTypeDWARFDebugPubTypes; - else if (name == g_sect_name_dwarf_debug_ranges) - sect_type = eSectionTypeDWARFDebugRanges; - else if (name == g_sect_name_dwarf_debug_str) - sect_type = eSectionTypeDWARFDebugStr; - else if (name == g_sect_name_dwarf_debug_types) - sect_type = eSectionTypeDWARFDebugTypes; - else if (name == g_sect_name_dwarf_debug_str_offsets) - sect_type = eSectionTypeDWARFDebugStrOffsets; - else if (name == g_sect_name_dwarf_debug_abbrev_dwo) - sect_type = eSectionTypeDWARFDebugAbbrev; - else if (name == g_sect_name_dwarf_debug_info_dwo) - sect_type = eSectionTypeDWARFDebugInfo; - else if (name == g_sect_name_dwarf_debug_line_dwo) - sect_type = eSectionTypeDWARFDebugLine; - else if (name == g_sect_name_dwarf_debug_macro_dwo) - sect_type = eSectionTypeDWARFDebugMacro; - else if (name == g_sect_name_dwarf_debug_loc_dwo) - sect_type = eSectionTypeDWARFDebugLoc; - else if (name == g_sect_name_dwarf_debug_str_dwo) - sect_type = eSectionTypeDWARFDebugStr; - else if (name == g_sect_name_dwarf_debug_str_offsets_dwo) - sect_type = eSectionTypeDWARFDebugStrOffsets; - else if (name == g_sect_name_eh_frame) - sect_type = eSectionTypeEHFrame; - else if (name == g_sect_name_arm_exidx) - sect_type = eSectionTypeARMexidx; - else if (name == g_sect_name_arm_extab) - sect_type = eSectionTypeARMextab; - else if (name == g_sect_name_go_symtab) - sect_type = eSectionTypeGoSymtab; - else if (name == g_sect_name_dwarf_gnu_debugaltlink) - sect_type = eSectionTypeDWARFGNUDebugAltLink; - - const uint32_t permissions = - ((header.sh_flags & SHF_ALLOC) ? ePermissionsReadable : 0u) | - ((header.sh_flags & SHF_WRITE) ? ePermissionsWritable : 0u) | - ((header.sh_flags & SHF_EXECINSTR) ? ePermissionsExecutable : 0u); - switch (header.sh_type) { - case SHT_SYMTAB: - assert(sect_type == eSectionTypeOther); - sect_type = eSectionTypeELFSymbolTable; - break; - case SHT_DYNSYM: - assert(sect_type == eSectionTypeOther); - sect_type = eSectionTypeELFDynamicSymbols; - break; - case SHT_RELA: - case SHT_REL: - assert(sect_type == eSectionTypeOther); - sect_type = eSectionTypeELFRelocationEntries; - break; - case SHT_DYNAMIC: - assert(sect_type == eSectionTypeOther); - sect_type = eSectionTypeELFDynamicLinkInfo; - break; - } +static SectionType GetSectionTypeFromName(llvm::StringRef Name) { + return llvm::StringSwitch<SectionType>(Name) + .Case(".ARM.exidx", eSectionTypeARMexidx) + .Case(".ARM.extab", eSectionTypeARMextab) + .Cases(".bss", ".tbss", eSectionTypeZeroFill) + .Cases(".data", ".tdata", eSectionTypeData) + .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev) + .Case(".debug_abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo) + .Case(".debug_addr", eSectionTypeDWARFDebugAddr) + .Case(".debug_aranges", eSectionTypeDWARFDebugAranges) + .Case(".debug_cu_index", eSectionTypeDWARFDebugCuIndex) + .Case(".debug_frame", eSectionTypeDWARFDebugFrame) + .Case(".debug_info", eSectionTypeDWARFDebugInfo) + .Case(".debug_info.dwo", eSectionTypeDWARFDebugInfoDwo) + .Cases(".debug_line", ".debug_line.dwo", eSectionTypeDWARFDebugLine) + .Cases(".debug_line_str", ".debug_line_str.dwo", + eSectionTypeDWARFDebugLineStr) + .Cases(".debug_loc", ".debug_loc.dwo", eSectionTypeDWARFDebugLoc) + .Cases(".debug_loclists", ".debug_loclists.dwo", + eSectionTypeDWARFDebugLocLists) + .Case(".debug_macinfo", eSectionTypeDWARFDebugMacInfo) + .Cases(".debug_macro", ".debug_macro.dwo", eSectionTypeDWARFDebugMacro) + .Case(".debug_names", eSectionTypeDWARFDebugNames) + .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames) + .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes) + .Case(".debug_ranges", eSectionTypeDWARFDebugRanges) + .Case(".debug_rnglists", eSectionTypeDWARFDebugRngLists) + .Case(".debug_str", eSectionTypeDWARFDebugStr) + .Case(".debug_str.dwo", eSectionTypeDWARFDebugStrDwo) + .Case(".debug_str_offsets", eSectionTypeDWARFDebugStrOffsets) + .Case(".debug_str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo) + .Case(".debug_types", eSectionTypeDWARFDebugTypes) + .Case(".eh_frame", eSectionTypeEHFrame) + .Case(".gnu_debugaltlink", eSectionTypeDWARFGNUDebugAltLink) + .Case(".gosymtab", eSectionTypeGoSymtab) + .Case(".text", eSectionTypeCode) + .Default(eSectionTypeOther); +} + +SectionType ObjectFileELF::GetSectionType(const ELFSectionHeaderInfo &H) const { + switch (H.sh_type) { + case SHT_PROGBITS: + if (H.sh_flags & SHF_EXECINSTR) + return eSectionTypeCode; + break; + case SHT_SYMTAB: + return eSectionTypeELFSymbolTable; + case SHT_DYNSYM: + return eSectionTypeELFDynamicSymbols; + case SHT_RELA: + case SHT_REL: + return eSectionTypeELFRelocationEntries; + case SHT_DYNAMIC: + return eSectionTypeELFDynamicLinkInfo; + } + SectionType Type = GetSectionTypeFromName(H.section_name.GetStringRef()); + if (Type == eSectionTypeOther) { + // the kalimba toolchain assumes that ELF section names are free-form. + // It does support linkscripts which (can) give rise to various + // arbitrarily named sections being "Code" or "Data". + Type = kalimbaSectionType(m_header, H); + } + return Type; +} + +static uint32_t GetTargetByteSize(SectionType Type, const ArchSpec &arch) { + switch (Type) { + case eSectionTypeData: + case eSectionTypeZeroFill: + return arch.GetDataByteSize(); + case eSectionTypeCode: + return arch.GetCodeByteSize(); + default: + return 1; + } +} - if (eSectionTypeOther == sect_type) { - // the kalimba toolchain assumes that ELF section names are free-form. - // It does support linkscripts which (can) give rise to various - // arbitrarily named sections being "Code" or "Data". - sect_type = kalimbaSectionType(m_header, header); - } +static Permissions GetPermissions(const ELFSectionHeader &H) { + Permissions Perm = Permissions(0); + if (H.sh_flags & SHF_ALLOC) + Perm |= ePermissionsReadable; + if (H.sh_flags & SHF_WRITE) + Perm |= ePermissionsWritable; + if (H.sh_flags & SHF_EXECINSTR) + Perm |= ePermissionsExecutable; + return Perm; +} - // In common case ELF code section can have arbitrary name (for example, - // we can specify it using section attribute for particular function) so - // assume that section is a code section if it has SHF_EXECINSTR flag set - // and has SHT_PROGBITS type. - if (eSectionTypeOther == sect_type && - llvm::ELF::SHT_PROGBITS == header.sh_type && - (header.sh_flags & SHF_EXECINSTR)) { - sect_type = eSectionTypeCode; - } +static Permissions GetPermissions(const ELFProgramHeader &H) { + Permissions Perm = Permissions(0); + if (H.p_flags & PF_R) + Perm |= ePermissionsReadable; + if (H.p_flags & PF_W) + Perm |= ePermissionsWritable; + if (H.p_flags & PF_X) + Perm |= ePermissionsExecutable; + return Perm; +} - const uint32_t target_bytes_size = - (eSectionTypeData == sect_type || eSectionTypeZeroFill == sect_type) - ? m_arch_spec.GetDataByteSize() - : eSectionTypeCode == sect_type ? m_arch_spec.GetCodeByteSize() - : 1; - elf::elf_xword log2align = - (header.sh_addralign == 0) ? 0 : llvm::Log2_64(header.sh_addralign); - - uint64_t addr = header.sh_addr; - - if ((header.sh_flags & SHF_ALLOC) && synthaddrs) { - nextaddr = - (nextaddr + header.sh_addralign - 1) & ~(header.sh_addralign - 1); - addr = nextaddr; - nextaddr += vm_size; - } +namespace { + +using VMRange = lldb_private::Range<addr_t, addr_t>; - SectionSP section_sp(new Section( - GetModule(), // Module to which this section belongs. - this, // ObjectFile to which this section belongs and should read - // section data from. - SectionIndex(I), // Section ID. - name, // Section name. - sect_type, // Section type. - addr, // VM address. - vm_size, // VM size in bytes of this section. - header.sh_offset, // Offset of this section in the file. - file_size, // Size of the section as found in the file. - log2align, // Alignment of the section - header.sh_flags, // Flags for this section. - target_bytes_size)); // Number of host bytes per target byte - - section_sp->SetPermissions(permissions); - if (is_thread_specific) - section_sp->SetIsThreadSpecific(is_thread_specific); - m_sections_ap->AddSection(section_sp); +struct SectionAddressInfo { + SectionSP Segment; + VMRange Range; +}; + +// (Unlinked) ELF object files usually have 0 for every section address, meaning +// we need to compute synthetic addresses in order for "file addresses" from +// different sections to not overlap. This class handles that logic. +class VMAddressProvider { + using VMMap = llvm::IntervalMap<addr_t, SectionSP, 4, + llvm::IntervalMapHalfOpenInfo<addr_t>>; + + ObjectFile::Type ObjectType; + addr_t NextVMAddress = 0; + VMMap::Allocator Alloc; + VMMap Segments = VMMap(Alloc); + VMMap Sections = VMMap(Alloc); + lldb_private::Log *Log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES); + + VMRange GetVMRange(const ELFSectionHeader &H) { + addr_t Address = H.sh_addr; + addr_t Size = H.sh_flags & SHF_ALLOC ? H.sh_size : 0; + if (ObjectType == ObjectFile::Type::eTypeObjectFile && Segments.empty() && (H.sh_flags & SHF_ALLOC)) { + NextVMAddress = + llvm::alignTo(NextVMAddress, std::max<addr_t>(H.sh_addralign, 1)); + Address = NextVMAddress; + NextVMAddress += Size; } + return VMRange(Address, Size); + } + +public: + VMAddressProvider(ObjectFile::Type Type) : ObjectType(Type) {} + + llvm::Optional<VMRange> GetAddressInfo(const ELFProgramHeader &H) { + if (H.p_memsz == 0) { + LLDB_LOG(Log, + "Ignoring zero-sized PT_LOAD segment. Corrupt object file?"); + return llvm::None; + } + + if (Segments.overlaps(H.p_vaddr, H.p_vaddr + H.p_memsz)) { + LLDB_LOG(Log, + "Ignoring overlapping PT_LOAD segment. Corrupt object file?"); + return llvm::None; + } + return VMRange(H.p_vaddr, H.p_memsz); + } + + llvm::Optional<SectionAddressInfo> GetAddressInfo(const ELFSectionHeader &H) { + VMRange Range = GetVMRange(H); + SectionSP Segment; + auto It = Segments.find(Range.GetRangeBase()); + if ((H.sh_flags & SHF_ALLOC) && It.valid()) { + addr_t MaxSize; + if (It.start() <= Range.GetRangeBase()) { + MaxSize = It.stop() - Range.GetRangeBase(); + Segment = *It; + } else + MaxSize = It.start() - Range.GetRangeBase(); + if (Range.GetByteSize() > MaxSize) { + LLDB_LOG(Log, "Shortening section crossing segment boundaries. " + "Corrupt object file?"); + Range.SetByteSize(MaxSize); + } + } + if (Range.GetByteSize() > 0 && + Sections.overlaps(Range.GetRangeBase(), Range.GetRangeEnd())) { + LLDB_LOG(Log, "Ignoring overlapping section. Corrupt object file?"); + return llvm::None; + } + if (Segment) + Range.Slide(-Segment->GetFileAddress()); + return SectionAddressInfo{Segment, Range}; + } + + void AddSegment(const VMRange &Range, SectionSP Seg) { + Segments.insert(Range.GetRangeBase(), Range.GetRangeEnd(), std::move(Seg)); + } + + void AddSection(SectionAddressInfo Info, SectionSP Sect) { + if (Info.Range.GetByteSize() == 0) + return; + if (Info.Segment) + Info.Range.Slide(Info.Segment->GetFileAddress()); + Sections.insert(Info.Range.GetRangeBase(), Info.Range.GetRangeEnd(), + std::move(Sect)); + } +}; +} + +void ObjectFileELF::CreateSections(SectionList &unified_section_list) { + if (m_sections_ap) + return; + + m_sections_ap = llvm::make_unique<SectionList>(); + VMAddressProvider address_provider(CalculateType()); + + size_t LoadID = 0; + for (const auto &EnumPHdr : llvm::enumerate(ProgramHeaders())) { + const ELFProgramHeader &PHdr = EnumPHdr.value(); + if (PHdr.p_type != PT_LOAD) + continue; + + auto InfoOr = address_provider.GetAddressInfo(PHdr); + if (!InfoOr) + continue; + + ConstString Name(("PT_LOAD[" + llvm::Twine(LoadID++) + "]").str()); + uint32_t Log2Align = llvm::Log2_64(std::max<elf_xword>(PHdr.p_align, 1)); + SectionSP Segment = std::make_shared<Section>( + GetModule(), this, SegmentID(EnumPHdr.index()), Name, + eSectionTypeContainer, InfoOr->GetRangeBase(), InfoOr->GetByteSize(), + PHdr.p_offset, PHdr.p_filesz, Log2Align, /*flags*/ 0); + Segment->SetPermissions(GetPermissions(PHdr)); + m_sections_ap->AddSection(Segment); + + address_provider.AddSegment(*InfoOr, std::move(Segment)); + } + + ParseSectionHeaders(); + if (m_section_headers.empty()) + return; + + for (SectionHeaderCollIter I = std::next(m_section_headers.begin()); + I != m_section_headers.end(); ++I) { + const ELFSectionHeaderInfo &header = *I; + + ConstString &name = I->section_name; + const uint64_t file_size = + header.sh_type == SHT_NOBITS ? 0 : header.sh_size; + + auto InfoOr = address_provider.GetAddressInfo(header); + if (!InfoOr) + continue; + + SectionType sect_type = GetSectionType(header); + + const uint32_t target_bytes_size = + GetTargetByteSize(sect_type, m_arch_spec); + + elf::elf_xword log2align = + (header.sh_addralign == 0) ? 0 : llvm::Log2_64(header.sh_addralign); + + SectionSP section_sp(new Section( + InfoOr->Segment, GetModule(), // Module to which this section belongs. + this, // ObjectFile to which this section belongs and should + // read section data from. + SectionIndex(I), // Section ID. + name, // Section name. + sect_type, // Section type. + InfoOr->Range.GetRangeBase(), // VM address. + InfoOr->Range.GetByteSize(), // VM size in bytes of this section. + header.sh_offset, // Offset of this section in the file. + file_size, // Size of the section as found in the file. + log2align, // Alignment of the section + header.sh_flags, // Flags for this section. + target_bytes_size)); // Number of host bytes per target byte + + section_sp->SetPermissions(GetPermissions(header)); + section_sp->SetIsThreadSpecific(header.sh_flags & SHF_TLS); + (InfoOr->Segment ? InfoOr->Segment->GetChildren() : *m_sections_ap) + .AddSection(section_sp); + address_provider.AddSection(std::move(*InfoOr), std::move(section_sp)); } // For eTypeDebugInfo files, the Symbol Vendor will take care of updating the @@ -2050,8 +2076,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, bool skip_oatdata_oatexec = file_extension == ConstString(".oat") || file_extension == ConstString(".odex"); - ArchSpec arch; - GetArchitecture(arch); + ArchSpec arch = GetArchitecture(); ModuleSP module_sp(GetModule()); SectionList *module_section_list = module_sp ? module_sp->GetSectionList() : nullptr; @@ -2063,7 +2088,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, unsigned i; for (i = 0; i < num_symbols; ++i) { - if (symbol.Parse(symtab_data, &offset) == false) + if (!symbol.Parse(symtab_data, &offset)) break; const char *symbol_name = strtab_data.PeekCStr(symbol.st_name); @@ -2083,9 +2108,9 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, SectionSP symbol_section_sp; SymbolType symbol_type = eSymbolTypeInvalid; - Elf64_Half section_idx = symbol.st_shndx; + Elf64_Half shndx = symbol.st_shndx; - switch (section_idx) { + switch (shndx) { case SHN_ABS: symbol_type = eSymbolTypeAbsolute; break; @@ -2093,7 +2118,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, symbol_type = eSymbolTypeUndefined; break; default: - symbol_section_sp = section_list->GetSectionAtIndex(section_idx); + symbol_section_sp = section_list->FindSectionByID(shndx); break; } @@ -2262,7 +2287,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, // symbols. See above for more details. uint64_t symbol_value = symbol.st_value + symbol_value_offset; - if (symbol_section_sp == nullptr && section_idx == SHN_ABS && + if (symbol_section_sp == nullptr && shndx == SHN_ABS && symbol.st_size != 0) { // We don't have a section for a symbol with non-zero size. Create a new // section for it so the address range covered by the symbol is also @@ -2375,9 +2400,8 @@ unsigned ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, assert(symtab_hdr->sh_type == SHT_SYMTAB || symtab_hdr->sh_type == SHT_DYNSYM); - // sh_link: section header index of associated string table. Section ID's are - // ones based. - user_id_t strtab_id = symtab_hdr->sh_link + 1; + // sh_link: section header index of associated string table. + user_id_t strtab_id = symtab_hdr->sh_link; Section *strtab = section_list->FindSectionByID(strtab_id).get(); if (symtab && strtab) { @@ -2529,7 +2553,7 @@ static unsigned ParsePLTRelocations( unsigned slot_type = hdr->GetRelocationJumpSlotType(); unsigned i; for (i = 0; i < num_relocations; ++i) { - if (rel.Parse(rel_data, &offset) == false) + if (!rel.Parse(rel_data, &offset)) break; if (reloc_type(rel) != slot_type) @@ -2587,10 +2611,6 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, user_id_t start_id, if (!symtab_id || !plt_id) return 0; - // Section ID's are ones based; - symtab_id++; - plt_id++; - const ELFSectionHeaderInfo *plt_hdr = GetSectionHeaderByIndex(plt_id); if (!plt_hdr) return 0; @@ -2616,7 +2636,7 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, user_id_t start_id, return 0; // sh_link points to associated string table. - Section *strtab = section_list->FindSectionByID(sym_hdr->sh_link + 1).get(); + Section *strtab = section_list->FindSectionByID(sym_hdr->sh_link).get(); if (!strtab) return 0; @@ -2662,7 +2682,7 @@ unsigned ObjectFileELF::ApplyRelocations( } for (unsigned i = 0; i < num_relocations; ++i) { - if (rel.Parse(rel_data, &offset) == false) + if (!rel.Parse(rel_data, &offset)) break; Symbol *symbol = NULL; @@ -2684,6 +2704,7 @@ unsigned ObjectFileELF::ApplyRelocations( } } else { switch (reloc_type(rel)) { + case R_AARCH64_ABS64: case R_X86_64_64: { symbol = symtab->FindSymbolByID(reloc_symbol(rel)); if (symbol) { @@ -2692,26 +2713,34 @@ unsigned ObjectFileELF::ApplyRelocations( uint64_t *dst = reinterpret_cast<uint64_t *>( data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset64(rel)); - *dst = value + ELFRelocation::RelocAddend64(rel); + uint64_t val_offset = value + ELFRelocation::RelocAddend64(rel); + memcpy(dst, &val_offset, sizeof(uint64_t)); } break; } case R_X86_64_32: - case R_X86_64_32S: { + case R_X86_64_32S: + case R_AARCH64_ABS32: { symbol = symtab->FindSymbolByID(reloc_symbol(rel)); if (symbol) { addr_t value = symbol->GetAddressRef().GetFileAddress(); value += ELFRelocation::RelocAddend32(rel); - assert( - (reloc_type(rel) == R_X86_64_32 && (value <= UINT32_MAX)) || + if ((reloc_type(rel) == R_X86_64_32 && (value > UINT32_MAX)) || (reloc_type(rel) == R_X86_64_32S && - ((int64_t)value <= INT32_MAX && (int64_t)value >= INT32_MIN))); + ((int64_t)value > INT32_MAX && (int64_t)value < INT32_MIN)) || + (reloc_type(rel) == R_AARCH64_ABS32 && + ((int64_t)value > INT32_MAX && (int64_t)value < INT32_MIN))) { + Log *log = + lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES); + log->Printf("Failed to apply debug info relocations"); + break; + } uint32_t truncated_addr = (value & 0xFFFFFFFF); DataBufferSP &data_buffer_sp = debug_data.GetSharedDataBuffer(); uint32_t *dst = reinterpret_cast<uint32_t *>( data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset32(rel)); - *dst = truncated_addr; + memcpy(dst, &truncated_addr, sizeof(uint32_t)); } break; } @@ -2735,9 +2764,8 @@ unsigned ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, if (!section_list) return 0; - // Section ID's are ones based. - user_id_t symtab_id = rel_hdr->sh_link + 1; - user_id_t debug_id = rel_hdr->sh_info + 1; + user_id_t symtab_id = rel_hdr->sh_link; + user_id_t debug_id = rel_hdr->sh_info; const ELFSectionHeader *symtab_hdr = GetSectionHeaderByIndex(symtab_id); if (!symtab_hdr) @@ -2975,8 +3003,7 @@ void ObjectFileELF::Dump(Stream *s) { s->Indent(); s->PutCString("ObjectFileELF"); - ArchSpec header_arch; - GetArchitecture(header_arch); + ArchSpec header_arch = GetArchitecture(); *s << ", file = '" << m_file << "', arch = " << header_arch.GetArchitectureName() << "\n"; @@ -3153,11 +3180,9 @@ void ObjectFileELF::DumpELFProgramHeaders(Stream *s) { s->PutCString("==== --------------- -------- -------- -------- " "-------- -------- ------------------------- --------\n"); - uint32_t idx = 0; - for (ProgramHeaderCollConstIter I = m_program_headers.begin(); - I != m_program_headers.end(); ++I, ++idx) { - s->Printf("[%2u] ", idx); - ObjectFileELF::DumpELFProgramHeader(s, *I); + for (const auto &H : llvm::enumerate(m_program_headers)) { + s->Format("[{0,2}] ", H.index()); + ObjectFileELF::DumpELFProgramHeader(s, H.value()); s->EOL(); } } @@ -3264,9 +3289,9 @@ void ObjectFileELF::DumpDependentModules(lldb_private::Stream *s) { } } -bool ObjectFileELF::GetArchitecture(ArchSpec &arch) { +ArchSpec ObjectFileELF::GetArchitecture() { if (!ParseHeader()) - return false; + return ArchSpec(); if (m_section_headers.empty()) { // Allow elf notes to be parsed which may affect the detected architecture. @@ -3277,23 +3302,17 @@ bool ObjectFileELF::GetArchitecture(ArchSpec &arch) { m_arch_spec.TripleOSIsUnspecifiedUnknown()) { // Core files don't have section headers yet they have PT_NOTE program // headers that might shed more light on the architecture - if (ParseProgramHeaders()) { - for (size_t i = 1, count = GetProgramHeaderCount(); i <= count; ++i) { - const elf::ELFProgramHeader *header = GetProgramHeaderByIndex(i); - if (header && header->p_type == PT_NOTE && header->p_offset != 0 && - header->p_filesz > 0) { - DataExtractor data; - if (data.SetData(m_data, header->p_offset, header->p_filesz) == - header->p_filesz) { - lldb_private::UUID uuid; - RefineModuleDetailsFromNote(data, m_arch_spec, uuid); - } - } + for (const elf::ELFProgramHeader &H : ProgramHeaders()) { + if (H.p_type != PT_NOTE || H.p_offset == 0 || H.p_filesz == 0) + continue; + DataExtractor data; + if (data.SetData(m_data, H.p_offset, H.p_filesz) == H.p_filesz) { + UUID uuid; + RefineModuleDetailsFromNote(data, m_arch_spec, uuid); } } } - arch = m_arch_spec; - return true; + return m_arch_spec; } ObjectFile::Type ObjectFileELF::CalculateType() { @@ -3385,8 +3404,6 @@ size_t ObjectFileELF::ReadSectionData(Section *section, if (section->GetObjectFile() != this) return section->GetObjectFile()->ReadSectionData(section, section_data); - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES); - size_t result = ObjectFile::ReadSectionData(section, section_data); if (result == 0 || !section->Test(SHF_COMPRESSED)) return result; @@ -3397,29 +3414,43 @@ size_t ObjectFileELF::ReadSectionData(Section *section, size_t(section_data.GetByteSize())}, GetByteOrder() == eByteOrderLittle, GetAddressByteSize() == 8); if (!Decompressor) { - LLDB_LOG_ERROR(log, Decompressor.takeError(), - "Unable to initialize decompressor for section {0}", - section->GetName()); - return result; + GetModule()->ReportWarning( + "Unable to initialize decompressor for section '%s': %s", + section->GetName().GetCString(), + llvm::toString(Decompressor.takeError()).c_str()); + section_data.Clear(); + return 0; } + auto buffer_sp = std::make_shared<DataBufferHeap>(Decompressor->getDecompressedSize(), 0); - if (auto Error = Decompressor->decompress( + if (auto error = Decompressor->decompress( {reinterpret_cast<char *>(buffer_sp->GetBytes()), size_t(buffer_sp->GetByteSize())})) { - LLDB_LOG_ERROR(log, std::move(Error), "Decompression of section {0} failed", - section->GetName()); - return result; + GetModule()->ReportWarning( + "Decompression of section '%s' failed: %s", + section->GetName().GetCString(), + llvm::toString(std::move(error)).c_str()); + section_data.Clear(); + return 0; } + section_data.SetData(buffer_sp); return buffer_sp->GetByteSize(); } +llvm::ArrayRef<ELFProgramHeader> ObjectFileELF::ProgramHeaders() { + ParseProgramHeaders(); + return m_program_headers; +} + +DataExtractor ObjectFileELF::GetSegmentData(const ELFProgramHeader &H) { + return DataExtractor(m_data, H.p_offset, H.p_filesz); +} + bool ObjectFileELF::AnySegmentHasPhysicalAddress() { - size_t header_count = ParseProgramHeaders(); - for (size_t i = 1; i <= header_count; ++i) { - auto header = GetProgramHeaderByIndex(i); - if (header->p_paddr != 0) + for (const ELFProgramHeader &H : ProgramHeaders()) { + if (H.p_paddr != 0) return true; } return false; @@ -3430,19 +3461,17 @@ ObjectFileELF::GetLoadableData(Target &target) { // Create a list of loadable data from loadable segments, using physical // addresses if they aren't all null std::vector<LoadableData> loadables; - size_t header_count = ParseProgramHeaders(); bool should_use_paddr = AnySegmentHasPhysicalAddress(); - for (size_t i = 1; i <= header_count; ++i) { + for (const ELFProgramHeader &H : ProgramHeaders()) { LoadableData loadable; - auto header = GetProgramHeaderByIndex(i); - if (header->p_type != llvm::ELF::PT_LOAD) + if (H.p_type != llvm::ELF::PT_LOAD) continue; - loadable.Dest = should_use_paddr ? header->p_paddr : header->p_vaddr; + loadable.Dest = should_use_paddr ? H.p_paddr : H.p_vaddr; if (loadable.Dest == LLDB_INVALID_ADDRESS) continue; - if (header->p_filesz == 0) + if (H.p_filesz == 0) continue; - auto segment_data = GetSegmentDataByIndex(i); + auto segment_data = GetSegmentData(H); loadable.Contents = llvm::ArrayRef<uint8_t>(segment_data.GetDataStart(), segment_data.GetByteSize()); loadables.push_back(loadable); diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 2664595fd81d..08fd5bdc60a9 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -10,10 +10,8 @@ #ifndef liblldb_ObjectFileELF_h_ #define liblldb_ObjectFileELF_h_ -// C Includes #include <stdint.h> -// C++ Includes #include <vector> #include "lldb/Symbol/ObjectFile.h" @@ -123,7 +121,7 @@ public: void Dump(lldb_private::Stream *s) override; - bool GetArchitecture(lldb_private::ArchSpec &arch) override; + lldb_private::ArchSpec GetArchitecture() override; bool GetUUID(lldb_private::UUID *uuid) override; @@ -136,6 +134,8 @@ public: lldb_private::Address GetEntryPointAddress() override; + lldb_private::Address GetBaseAddress() override; + ObjectFile::Type CalculateType() override; ObjectFile::Strata CalculateStrata() override; @@ -147,14 +147,8 @@ public: size_t ReadSectionData(lldb_private::Section *section, lldb_private::DataExtractor §ion_data) override; - // Returns number of program headers found in the ELF file. - size_t GetProgramHeaderCount(); - - // Returns the program header with the given index. - const elf::ELFProgramHeader *GetProgramHeaderByIndex(lldb::user_id_t id); - - // Returns segment data for the given index. - lldb_private::DataExtractor GetSegmentDataByIndex(lldb::user_id_t id); + llvm::ArrayRef<elf::ELFProgramHeader> ProgramHeaders(); + lldb_private::DataExtractor GetSegmentData(const elf::ELFProgramHeader &H); llvm::StringRef StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override; @@ -176,8 +170,6 @@ private: const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); typedef std::vector<elf::ELFProgramHeader> ProgramHeaderColl; - typedef ProgramHeaderColl::iterator ProgramHeaderCollIter; - typedef ProgramHeaderColl::const_iterator ProgramHeaderCollConstIter; struct ELFSectionHeaderInfo : public elf::ELFSectionHeader { lldb_private::ConstString section_name; @@ -230,10 +222,10 @@ private: /// The address class for each symbol in the elf file FileAddressToAddressClassMap m_address_class_map; - /// Returns a 1 based index of the given section header. + /// Returns the index of the given section header. size_t SectionIndex(const SectionHeaderCollIter &I); - /// Returns a 1 based index of the given section header. + /// Returns the index of the given section header. size_t SectionIndex(const SectionHeaderCollConstIter &I) const; // Parses the ELF program headers. @@ -248,14 +240,16 @@ private: /// Parses all section headers present in this object file and populates /// m_program_headers. This method will compute the header list only once. - /// Returns the number of headers parsed. - size_t ParseProgramHeaders(); + /// Returns true iff the headers have been successfully parsed. + bool ParseProgramHeaders(); /// Parses all section headers present in this object file and populates /// m_section_headers. This method will compute the header list only once. /// Returns the number of headers parsed. size_t ParseSectionHeaders(); + lldb::SectionType GetSectionType(const ELFSectionHeaderInfo &H) const; + static void ParseARMAttributes(lldb_private::DataExtractor &data, uint64_t length, lldb_private::ArchSpec &arch_spec); diff --git a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp index af040322ec52..cfe61992be0d 100644 --- a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp +++ b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp @@ -153,8 +153,7 @@ void ObjectFileJIT::Dump(Stream *s) { s->Indent(); s->PutCString("ObjectFileJIT"); - ArchSpec arch; - if (GetArchitecture(arch)) + if (ArchSpec arch = GetArchitecture()) *s << ", arch = " << arch.GetArchitectureName(); s->EOL(); @@ -184,17 +183,16 @@ lldb_private::Address ObjectFileJIT::GetEntryPointAddress() { return Address(); } -lldb_private::Address ObjectFileJIT::GetHeaderAddress() { return Address(); } +lldb_private::Address ObjectFileJIT::GetBaseAddress() { return Address(); } ObjectFile::Type ObjectFileJIT::CalculateType() { return eTypeJIT; } ObjectFile::Strata ObjectFileJIT::CalculateStrata() { return eStrataJIT; } -bool ObjectFileJIT::GetArchitecture(ArchSpec &arch) { - ObjectFileJITDelegateSP delegate_sp(m_delegate_wp.lock()); - if (delegate_sp) - return delegate_sp->GetArchitecture(arch); - return false; +ArchSpec ObjectFileJIT::GetArchitecture() { + if (ObjectFileJITDelegateSP delegate_sp = m_delegate_wp.lock()) + return delegate_sp->GetArchitecture(); + return ArchSpec(); } //------------------------------------------------------------------ @@ -218,7 +216,7 @@ bool ObjectFileJIT::SetLoadAddress(Target &target, lldb::addr_t value, // that size on disk (to avoid __PAGEZERO) and load them SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); if (section_sp && section_sp->GetFileSize() > 0 && - section_sp->IsThreadSpecific() == false) { + !section_sp->IsThreadSpecific()) { if (target.GetSectionLoadList().SetSectionLoadAddress( section_sp, section_sp->GetFileAddress() + value)) ++num_loaded_sections; diff --git a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h index c964906a5e8e..3d9e4748d3df 100644 --- a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h +++ b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h @@ -10,10 +10,6 @@ #ifndef liblldb_ObjectFileJIT_h_ #define liblldb_ObjectFileJIT_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Address.h" #include "lldb/Symbol/ObjectFile.h" @@ -77,7 +73,7 @@ public: void Dump(lldb_private::Stream *s) override; - bool GetArchitecture(lldb_private::ArchSpec &arch) override; + lldb_private::ArchSpec GetArchitecture() override; bool GetUUID(lldb_private::UUID *uuid) override; @@ -93,7 +89,7 @@ public: lldb_private::Address GetEntryPointAddress() override; - lldb_private::Address GetHeaderAddress() override; + lldb_private::Address GetBaseAddress() override; ObjectFile::Type CalculateType() override; diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index 91e7f3353270..06908fecf984 100644 --- a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -7,12 +7,8 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/StringRef.h" -// Project includes #include "Plugins/Process/Utility/RegisterContextDarwin_arm.h" #include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h" #include "Plugins/Process/Utility/RegisterContextDarwin_i386.h" @@ -23,7 +19,6 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/RangeMap.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/Section.h" #include "lldb/Core/StreamFile.h" #include "lldb/Host/Host.h" @@ -41,12 +36,13 @@ #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" #include "lldb/Utility/UUID.h" -#include "lldb/Utility/SafeMachO.h" +#include "lldb/Host/SafeMachO.h" #include "llvm/Support/MemoryBuffer.h" @@ -919,12 +915,10 @@ size_t ObjectFileMachO::GetModuleSpecifications( spec.SetObjectOffset(file_offset); spec.SetObjectSize(length); - if (GetArchitecture(header, data, data_offset, - spec.GetArchitecture())) { - if (spec.GetArchitecture().IsValid()) { - GetUUID(header, data, data_offset, spec.GetUUID()); - specs.Append(spec); - } + spec.GetArchitecture() = GetArchitecture(header, data, data_offset); + if (spec.GetArchitecture().IsValid()) { + GetUUID(header, data, data_offset, spec.GetUUID()); + specs.Append(spec); } } } @@ -962,6 +956,11 @@ const ConstString &ObjectFileMachO::GetSegmentNameLINKEDIT() { return g_section_name_LINKEDIT; } +const ConstString &ObjectFileMachO::GetSegmentNameDWARF() { + static ConstString g_section_name("__DWARF"); + return g_section_name; +} + const ConstString &ObjectFileMachO::GetSectionNameEHFrame() { static ConstString g_section_name_eh_frame("__eh_frame"); return g_section_name_eh_frame; @@ -1102,9 +1101,7 @@ bool ObjectFileMachO::ParseHeader() { if (can_parse) { m_data.GetU32(&offset, &m_header.cputype, 6); - ArchSpec mach_arch; - - if (GetArchitecture(mach_arch)) { + if (ArchSpec mach_arch = GetArchitecture()) { // Check if the module has a required architecture const ArchSpec &module_arch = module_sp->GetArchitecture(); if (module_arch.IsValid() && !module_arch.IsCompatibleMatch(mach_arch)) @@ -1191,21 +1188,28 @@ AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) { case eSectionTypeDebug: case eSectionTypeDWARFDebugAbbrev: + case eSectionTypeDWARFDebugAbbrevDwo: case eSectionTypeDWARFDebugAddr: case eSectionTypeDWARFDebugAranges: case eSectionTypeDWARFDebugCuIndex: case eSectionTypeDWARFDebugFrame: case eSectionTypeDWARFDebugInfo: + case eSectionTypeDWARFDebugInfoDwo: case eSectionTypeDWARFDebugLine: + case eSectionTypeDWARFDebugLineStr: case eSectionTypeDWARFDebugLoc: + case eSectionTypeDWARFDebugLocLists: case eSectionTypeDWARFDebugMacInfo: case eSectionTypeDWARFDebugMacro: case eSectionTypeDWARFDebugNames: case eSectionTypeDWARFDebugPubNames: case eSectionTypeDWARFDebugPubTypes: case eSectionTypeDWARFDebugRanges: + case eSectionTypeDWARFDebugRngLists: case eSectionTypeDWARFDebugStr: + case eSectionTypeDWARFDebugStrDwo: case eSectionTypeDWARFDebugStrOffsets: + case eSectionTypeDWARFDebugStrOffsetsDwo: case eSectionTypeDWARFDebugTypes: case eSectionTypeDWARFAppleNames: case eSectionTypeDWARFAppleTypes: @@ -1455,6 +1459,7 @@ static lldb::SectionType GetSectionType(uint32_t flags, static ConstString g_sect_name_dwarf_debug_info("__debug_info"); static ConstString g_sect_name_dwarf_debug_line("__debug_line"); static ConstString g_sect_name_dwarf_debug_loc("__debug_loc"); + static ConstString g_sect_name_dwarf_debug_loclists("__debug_loclists"); static ConstString g_sect_name_dwarf_debug_macinfo("__debug_macinfo"); static ConstString g_sect_name_dwarf_debug_names("__debug_names"); static ConstString g_sect_name_dwarf_debug_pubnames("__debug_pubnames"); @@ -1484,6 +1489,8 @@ static lldb::SectionType GetSectionType(uint32_t flags, return eSectionTypeDWARFDebugLine; if (section_name == g_sect_name_dwarf_debug_loc) return eSectionTypeDWARFDebugLoc; + if (section_name == g_sect_name_dwarf_debug_loclists) + return eSectionTypeDWARFDebugLocLists; if (section_name == g_sect_name_dwarf_debug_macinfo) return eSectionTypeDWARFDebugMacInfo; if (section_name == g_sect_name_dwarf_debug_names) @@ -1493,7 +1500,7 @@ static lldb::SectionType GetSectionType(uint32_t flags, if (section_name == g_sect_name_dwarf_debug_pubtypes) return eSectionTypeDWARFDebugPubTypes; if (section_name == g_sect_name_dwarf_debug_ranges) - return eSectionTypeDWARFDebugRanges; + return eSectionTypeDWARFDebugRanges; if (section_name == g_sect_name_dwarf_debug_str) return eSectionTypeDWARFDebugStr; if (section_name == g_sect_name_dwarf_debug_types) @@ -1668,7 +1675,7 @@ void ObjectFileMachO::ProcessSegmentCommand(const load_command &load_cmd_, } else if (unified_section_sp) { if (is_dsym && unified_section_sp->GetFileAddress() != load_cmd.vmaddr) { // Check to see if the module was read from memory? - if (module_sp->GetObjectFile()->GetHeaderAddress().IsValid()) { + if (module_sp->GetObjectFile()->GetBaseAddress().IsValid()) { // We have a module that is in memory and needs to have its file // address adjusted. We need to do this because when we load a file // from memory, its addresses will be slid already, yet the addresses @@ -2177,7 +2184,7 @@ size_t ObjectFileMachO::ParseSymtab() { uint32_t name_offset = cmd_offset + m_data.GetU32(&offset); const char *path = m_data.PeekCStr(name_offset); if (path) { - FileSpec file_spec(path, false); + FileSpec file_spec(path); // Strip the path if there is @rpath, @executable, etc so we just use // the basename if (path[0] == '@') @@ -2331,14 +2338,6 @@ size_t ObjectFileMachO::ParseSymtab() { if (nlist_data_sp) nlist_data.SetData(nlist_data_sp, 0, nlist_data_sp->GetByteSize()); - // Load strings individually from memory when loading from memory - // since shared cache string tables contain strings for all symbols - // from all shared cached libraries DataBufferSP strtab_data_sp - // (ReadMemory (process_sp, strtab_addr, - // strtab_data_byte_size)); - // if (strtab_data_sp) - // strtab_data.SetData (strtab_data_sp, 0, - // strtab_data_sp->GetByteSize()); if (m_dysymtab.nindirectsyms != 0) { const addr_t indirect_syms_addr = linkedit_load_addr + m_dysymtab.indirectsymoff - @@ -2350,8 +2349,25 @@ size_t ObjectFileMachO::ParseSymtab() { indirect_symbol_index_data.SetData( indirect_syms_data_sp, 0, indirect_syms_data_sp->GetByteSize()); + // If this binary is outside the shared cache, + // cache the string table. + // Binaries in the shared cache all share a giant string table, and + // we can't share the string tables across multiple ObjectFileMachO's, + // so we'd end up re-reading this mega-strtab for every binary + // in the shared cache - it would be a big perf problem. + // For binaries outside the shared cache, it's faster to read the + // entire strtab at once instead of piece-by-piece as we process + // the nlist records. + if ((m_header.flags & 0x80000000u) == 0) { + DataBufferSP strtab_data_sp (ReadMemory (process_sp, strtab_addr, + strtab_data_byte_size)); + if (strtab_data_sp) { + strtab_data.SetData (strtab_data_sp, 0, strtab_data_sp->GetByteSize()); + } + } } - } else if (memory_module_load_level >= + } + if (memory_module_load_level >= eMemoryModuleLoadLevelPartial) { if (function_starts_load_command.cmd) { const addr_t func_start_addr = @@ -2621,7 +2637,7 @@ size_t ObjectFileMachO::ParseSymtab() { // shared cache UUID in the development or non-development shared caches // on disk. if (process_shared_cache_uuid.IsValid()) { - if (dsc_development_filespec.Exists()) { + if (FileSystem::Instance().Exists(dsc_development_filespec)) { UUID dsc_development_uuid = GetSharedCacheUUID( dsc_development_filespec, byte_order, addr_byte_size); if (dsc_development_uuid.IsValid() && @@ -2630,7 +2646,8 @@ size_t ObjectFileMachO::ParseSymtab() { dsc_uuid = dsc_development_uuid; } } - if (!dsc_uuid.IsValid() && dsc_nondevelopment_filespec.Exists()) { + if (!dsc_uuid.IsValid() && + FileSystem::Instance().Exists(dsc_nondevelopment_filespec)) { UUID dsc_nondevelopment_uuid = GetSharedCacheUUID( dsc_nondevelopment_filespec, byte_order, addr_byte_size); if (dsc_nondevelopment_uuid.IsValid() && @@ -2643,8 +2660,8 @@ size_t ObjectFileMachO::ParseSymtab() { // Failing a UUID match, prefer the development dyld_shared cache if both // are present. - if (!dsc_filespec.Exists()) { - if (dsc_development_filespec.Exists()) { + if (!FileSystem::Instance().Exists(dsc_filespec)) { + if (FileSystem::Instance().Exists(dsc_development_filespec)) { dsc_filespec = dsc_development_filespec; } else { dsc_filespec = dsc_nondevelopment_filespec; @@ -3052,11 +3069,11 @@ size_t ObjectFileMachO::ParseSymtab() { // file so you end up with a path that looks // like "/tmp/src//tmp/src/" FileSpec so_dir(so_path, false); - if (!so_dir.Exists()) { + if (!FileSystem::Instance().Exists(so_dir)) { so_dir.SetFile( &full_so_path[double_slash_pos + 1], false); - if (so_dir.Exists()) { + if (FileSystem::Instance().Exists(so_dir)) { // Trim off the incorrect path full_so_path.erase(0, double_slash_pos + 1); @@ -4001,11 +4018,11 @@ size_t ObjectFileMachO::ParseSymtab() { // string in the DW_AT_comp_dir, and the second is the // directory for the source file so you end up with a path // that looks like "/tmp/src//tmp/src/" - FileSpec so_dir(so_path, false); - if (!so_dir.Exists()) { - so_dir.SetFile(&full_so_path[double_slash_pos + 1], false, + FileSpec so_dir(so_path); + if (!FileSystem::Instance().Exists(so_dir)) { + so_dir.SetFile(&full_so_path[double_slash_pos + 1], FileSpec::Style::native); - if (so_dir.Exists()) { + if (FileSystem::Instance().Exists(so_dir)) { // Trim off the incorrect path full_so_path.erase(0, double_slash_pos + 1); } @@ -4453,7 +4470,7 @@ size_t ObjectFileMachO::ParseSymtab() { symbol_value -= section_file_addr; } - if (is_debug == false) { + if (!is_debug) { if (type == eSymbolTypeCode) { // See if we can find a N_FUN entry for any code symbols. If we // do find a match, and the name matches, then we can merge the @@ -4600,7 +4617,7 @@ size_t ObjectFileMachO::ParseSymtab() { if (function_starts_count > 0) { uint32_t num_synthetic_function_symbols = 0; for (i = 0; i < function_starts_count; ++i) { - if (function_starts.GetEntryRef(i).data == false) + if (!function_starts.GetEntryRef(i).data) ++num_synthetic_function_symbols; } @@ -4612,7 +4629,7 @@ size_t ObjectFileMachO::ParseSymtab() { for (i = 0; i < function_starts_count; ++i) { const FunctionStarts::Entry *func_start_entry = function_starts.GetEntryAtIndex(i); - if (func_start_entry->data == false) { + if (!func_start_entry->data) { addr_t symbol_file_addr = func_start_entry->addr; uint32_t symbol_flags = 0; if (is_arm) { @@ -4817,8 +4834,7 @@ void ObjectFileMachO::Dump(Stream *s) { else s->PutCString("ObjectFileMachO32"); - ArchSpec header_arch; - GetArchitecture(header_arch); + ArchSpec header_arch = GetArchitecture(); *s << ", file = '" << m_file << "', triple = " << header_arch.GetTriple().getTriple() << "\n"; @@ -4869,25 +4885,83 @@ bool ObjectFileMachO::GetUUID(const llvm::MachO::mach_header &header, return false; } -static const char *GetOSName(uint32_t cmd) { +static llvm::StringRef GetOSName(uint32_t cmd) { switch (cmd) { case llvm::MachO::LC_VERSION_MIN_IPHONEOS: - return "ios"; + return llvm::Triple::getOSTypeName(llvm::Triple::IOS); case llvm::MachO::LC_VERSION_MIN_MACOSX: - return "macosx"; + return llvm::Triple::getOSTypeName(llvm::Triple::MacOSX); case llvm::MachO::LC_VERSION_MIN_TVOS: - return "tvos"; + return llvm::Triple::getOSTypeName(llvm::Triple::TvOS); case llvm::MachO::LC_VERSION_MIN_WATCHOS: - return "watchos"; + return llvm::Triple::getOSTypeName(llvm::Triple::WatchOS); default: llvm_unreachable("unexpected LC_VERSION load command"); } } -bool ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header, - const lldb_private::DataExtractor &data, - lldb::offset_t lc_offset, - ArchSpec &arch) { +namespace { + struct OSEnv { + llvm::StringRef os_type; + llvm::StringRef environment; + OSEnv(uint32_t cmd) { + switch (cmd) { + case PLATFORM_MACOS: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::MacOSX); + return; + case PLATFORM_IOS: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::IOS); + return; + case PLATFORM_TVOS: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::TvOS); + return; + case PLATFORM_WATCHOS: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::WatchOS); + return; +// NEED_BRIDGEOS_TRIPLE case PLATFORM_BRIDGEOS: +// NEED_BRIDGEOS_TRIPLE os_type = llvm::Triple::getOSTypeName(llvm::Triple::BridgeOS); +// NEED_BRIDGEOS_TRIPLE return; +#if defined (PLATFORM_IOSSIMULATOR) && defined (PLATFORM_TVOSSIMULATOR) && defined (PLATFORM_WATCHOSSIMULATOR) + case PLATFORM_IOSSIMULATOR: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::IOS); + environment = + llvm::Triple::getEnvironmentTypeName(llvm::Triple::Simulator); + return; + case PLATFORM_TVOSSIMULATOR: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::TvOS); + environment = + llvm::Triple::getEnvironmentTypeName(llvm::Triple::Simulator); + return; + case PLATFORM_WATCHOSSIMULATOR: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::WatchOS); + environment = + llvm::Triple::getEnvironmentTypeName(llvm::Triple::Simulator); + return; +#endif + default: { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS | + LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("unsupported platform in LC_BUILD_VERSION"); + } + } + } + }; + + struct MinOS { + uint32_t major_version, minor_version, patch_version; + MinOS(uint32_t version) + : major_version(version >> 16), + minor_version((version >> 8) & 0xffu), + patch_version(version & 0xffu) {} + }; +} // namespace + +ArchSpec +ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header, + const lldb_private::DataExtractor &data, + lldb::offset_t lc_offset) { + ArchSpec arch; arch.SetArchitecture(eArchTypeMachO, header.cputype, header.cpusubtype); if (arch.IsValid()) { @@ -4912,39 +4986,37 @@ bool ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header, triple.setVendor(llvm::Triple::UnknownVendor); triple.setVendorName(llvm::StringRef()); } - return true; + return arch; } else { struct load_command load_cmd; + llvm::SmallString<16> os_name; + llvm::raw_svector_ostream os(os_name); + // See if there is an LC_VERSION_MIN_* load command that can give + // us the OS type. lldb::offset_t offset = lc_offset; for (uint32_t i = 0; i < header.ncmds; ++i) { const lldb::offset_t cmd_offset = offset; if (data.GetU32(&offset, &load_cmd, 2) == NULL) break; - uint32_t major, minor, patch; struct version_min_command version_min; - - llvm::SmallString<16> os_name; - llvm::raw_svector_ostream os(os_name); - switch (load_cmd.cmd) { case llvm::MachO::LC_VERSION_MIN_IPHONEOS: case llvm::MachO::LC_VERSION_MIN_MACOSX: case llvm::MachO::LC_VERSION_MIN_TVOS: - case llvm::MachO::LC_VERSION_MIN_WATCHOS: + case llvm::MachO::LC_VERSION_MIN_WATCHOS: { if (load_cmd.cmdsize != sizeof(version_min)) break; - data.ExtractBytes(cmd_offset, - sizeof(version_min), data.GetByteOrder(), - &version_min); - major = version_min.version >> 16; - minor = (version_min.version >> 8) & 0xffu; - patch = version_min.version & 0xffu; - os << GetOSName(load_cmd.cmd) << major << '.' << minor << '.' - << patch; + if (data.ExtractBytes(cmd_offset, sizeof(version_min), + data.GetByteOrder(), &version_min) == 0) + break; + MinOS min_os(version_min.version); + os << GetOSName(load_cmd.cmd) << min_os.major_version << '.' + << min_os.minor_version << '.' << min_os.patch_version; triple.setOSName(os.str()); - return true; + return arch; + } default: break; } @@ -4952,6 +5024,39 @@ bool ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header, offset = cmd_offset + load_cmd.cmdsize; } + // See if there is an LC_BUILD_VERSION load command that can give + // us the OS type. + + offset = lc_offset; + for (uint32_t i = 0; i < header.ncmds; ++i) { + const lldb::offset_t cmd_offset = offset; + if (data.GetU32(&offset, &load_cmd, 2) == NULL) + break; + do { + if (load_cmd.cmd == llvm::MachO::LC_BUILD_VERSION) { + struct build_version_command build_version; + if (load_cmd.cmdsize < sizeof(build_version)) { + // Malformed load command. + break; + } + if (data.ExtractBytes(cmd_offset, sizeof(build_version), + data.GetByteOrder(), &build_version) == 0) + break; + MinOS min_os(build_version.minos); + OSEnv os_env(build_version.platform); + if (os_env.os_type.empty()) + break; + os << os_env.os_type << min_os.major_version << '.' + << min_os.minor_version << '.' << min_os.patch_version; + triple.setOSName(os.str()); + if (!os_env.environment.empty()) + triple.setEnvironmentName(os_env.environment); + return arch; + } + } while (0); + offset = cmd_offset + load_cmd.cmdsize; + } + if (header.filetype != MH_KEXT_BUNDLE) { // We didn't find a LC_VERSION_MIN load command and this isn't a KEXT // so lets not say our Vendor is Apple, leave it as an unspecified @@ -4961,7 +5066,7 @@ bool ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header, } } } - return arch.IsValid(); + return arch; } bool ObjectFileMachO::GetUUID(lldb_private::UUID *uuid) { @@ -4984,9 +5089,6 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { std::vector<std::string> rpath_paths; std::vector<std::string> rpath_relative_paths; std::vector<std::string> at_exec_relative_paths; - const bool resolve_path = false; // Don't resolve the dependent file paths - // since they may not reside on this - // system uint32_t i; for (i = 0; i < m_header.ncmds; ++i) { const uint32_t cmd_offset = offset; @@ -5015,7 +5117,7 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { at_exec_relative_paths.push_back(path + strlen("@executable_path")); } else { - FileSpec file_spec(path, resolve_path); + FileSpec file_spec(path); if (files.AppendIfUnique(file_spec)) count++; } @@ -5030,8 +5132,8 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { } FileSpec this_file_spec(m_file); - this_file_spec.ResolvePath(); - + FileSystem::Instance().Resolve(this_file_spec); + if (!rpath_paths.empty()) { // Fixup all LC_RPATH values to be absolute paths std::string loader_path("@loader_path"); @@ -5052,8 +5154,10 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { path += rpath_relative_path; // It is OK to resolve this path because we must find a file on disk // for us to accept it anyway if it is rpath relative. - FileSpec file_spec(path, true); - if (file_spec.Exists() && files.AppendIfUnique(file_spec)) { + FileSpec file_spec(path); + FileSystem::Instance().Resolve(file_spec); + if (FileSystem::Instance().Exists(file_spec) && + files.AppendIfUnique(file_spec)) { count++; break; } @@ -5070,7 +5174,8 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { for (const auto &at_exec_relative_path : at_exec_relative_paths) { FileSpec file_spec = exec_dir.CopyByAppendingPathComponent(at_exec_relative_path); - if (file_spec.Exists() && files.AppendIfUnique(file_spec)) + if (FileSystem::Instance().Exists(file_spec) && + files.AppendIfUnique(file_spec)) count++; } } @@ -5235,7 +5340,7 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() { return m_entry_point_address; } -lldb_private::Address ObjectFileMachO::GetHeaderAddress() { +lldb_private::Address ObjectFileMachO::GetBaseAddress() { lldb_private::Address header_addr; SectionList *section_list = GetSectionList(); if (section_list) { @@ -5583,14 +5688,16 @@ llvm::VersionTuple ObjectFileMachO::GetVersion() { return llvm::VersionTuple(); } -bool ObjectFileMachO::GetArchitecture(ArchSpec &arch) { +ArchSpec ObjectFileMachO::GetArchitecture() { ModuleSP module_sp(GetModule()); + ArchSpec arch; if (module_sp) { std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + return GetArchitecture(m_header, m_data, - MachHeaderSizeFromMagic(m_header.magic), arch); + MachHeaderSizeFromMagic(m_header.magic)); } - return false; + return arch; } void ObjectFileMachO::GetProcessSharedCacheUUID(Process *process, addr_t &base_addr, UUID &uuid) { @@ -5716,8 +5823,30 @@ llvm::VersionTuple ObjectFileMachO::GetMinimumOSVersion() { m_min_os_version = llvm::VersionTuple(xxxx, yy, zz); break; } + } + } else if (lc.cmd == llvm::MachO::LC_BUILD_VERSION) { + // struct build_version_command { + // uint32_t cmd; /* LC_BUILD_VERSION */ + // uint32_t cmdsize; /* sizeof(struct build_version_command) plus */ + // /* ntools * sizeof(struct build_tool_version) */ + // uint32_t platform; /* platform */ + // uint32_t minos; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ + // uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ + // uint32_t ntools; /* number of tool entries following this */ + // }; + + offset += 4; // skip platform + uint32_t minos = m_data.GetU32(&offset); + + const uint32_t xxxx = minos >> 16; + const uint32_t yy = (minos >> 8) & 0xffu; + const uint32_t zz = minos & 0xffu; + if (xxxx) { + m_min_os_version = llvm::VersionTuple(xxxx, yy, zz); + break; } } + offset = load_cmd_offset + lc.cmdsize; } @@ -5735,7 +5864,7 @@ uint32_t ObjectFileMachO::GetSDKVersion(uint32_t *versions, if (m_sdk_versions.empty()) { lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); bool success = false; - for (uint32_t i = 0; success == false && i < m_header.ncmds; ++i) { + for (uint32_t i = 0; !success && i < m_header.ncmds; ++i) { const lldb::offset_t load_cmd_offset = offset; version_min_command lc; @@ -5764,7 +5893,46 @@ uint32_t ObjectFileMachO::GetSDKVersion(uint32_t *versions, offset = load_cmd_offset + lc.cmdsize; } - if (success == false) { + if (!success) { + offset = MachHeaderSizeFromMagic(m_header.magic); + for (uint32_t i = 0; !success && i < m_header.ncmds; ++i) { + const lldb::offset_t load_cmd_offset = offset; + + version_min_command lc; + if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL) + break; + if (lc.cmd == llvm::MachO::LC_BUILD_VERSION) { + // struct build_version_command { + // uint32_t cmd; /* LC_BUILD_VERSION */ + // uint32_t cmdsize; /* sizeof(struct + // build_version_command) plus */ + // /* ntools * sizeof(struct + // build_tool_version) */ + // uint32_t platform; /* platform */ + // uint32_t minos; /* X.Y.Z is encoded in nibbles + // xxxx.yy.zz */ uint32_t sdk; /* X.Y.Z is encoded + // in nibbles xxxx.yy.zz */ uint32_t ntools; /* number + // of tool entries following this */ + // }; + + offset += 4; // skip platform + uint32_t minos = m_data.GetU32(&offset); + + const uint32_t xxxx = minos >> 16; + const uint32_t yy = (minos >> 8) & 0xffu; + const uint32_t zz = minos & 0xffu; + if (xxxx) { + m_sdk_versions.push_back(xxxx); + m_sdk_versions.push_back(yy); + m_sdk_versions.push_back(zz); + success = true; + } + } + offset = load_cmd_offset + lc.cmdsize; + } + } + + if (!success) { // Push an invalid value so we don't try to find // the version # again on the next call to this // method. @@ -5814,52 +5982,52 @@ Section *ObjectFileMachO::GetMachHeaderSection() { // the mach-o file which can be subtracted from the vmaddr of the other // segments found in memory and added to the load address ModuleSP module_sp = GetModule(); - if (module_sp) { - SectionList *section_list = GetSectionList(); - if (section_list) { - lldb::addr_t mach_base_file_addr = LLDB_INVALID_ADDRESS; - const size_t num_sections = section_list->GetSize(); - - for (size_t sect_idx = 0; sect_idx < num_sections && - mach_base_file_addr == LLDB_INVALID_ADDRESS; - ++sect_idx) { - Section *section = section_list->GetSectionAtIndex(sect_idx).get(); - if (section && section->GetFileSize() > 0 && - section->GetFileOffset() == 0 && - section->IsThreadSpecific() == false && - module_sp.get() == section->GetModule().get()) { - return section; - } - } - } + if (!module_sp) + return nullptr; + SectionList *section_list = GetSectionList(); + if (!section_list) + return nullptr; + const size_t num_sections = section_list->GetSize(); + for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + Section *section = section_list->GetSectionAtIndex(sect_idx).get(); + if (section->GetFileOffset() == 0 && SectionIsLoadable(section)) + return section; } return nullptr; } +bool ObjectFileMachO::SectionIsLoadable(const Section *section) { + if (!section) + return false; + const bool is_dsym = (m_header.filetype == MH_DSYM); + if (section->GetFileSize() == 0 && !is_dsym) + return false; + if (section->IsThreadSpecific()) + return false; + if (GetModule().get() != section->GetModule().get()) + return false; + // Be careful with __LINKEDIT and __DWARF segments + if (section->GetName() == GetSegmentNameLINKEDIT() || + section->GetName() == GetSegmentNameDWARF()) { + // Only map __LINKEDIT and __DWARF if we have an in memory image and + // this isn't a kernel binary like a kext or mach_kernel. + const bool is_memory_image = (bool)m_process_wp.lock(); + const Strata strata = GetStrata(); + if (is_memory_image == false || strata == eStrataKernel) + return false; + } + return true; +} + lldb::addr_t ObjectFileMachO::CalculateSectionLoadAddressForMemoryImage( - lldb::addr_t mach_header_load_address, const Section *mach_header_section, + lldb::addr_t header_load_address, const Section *header_section, const Section *section) { ModuleSP module_sp = GetModule(); - if (module_sp && mach_header_section && section && - mach_header_load_address != LLDB_INVALID_ADDRESS) { - lldb::addr_t mach_header_file_addr = mach_header_section->GetFileAddress(); - if (mach_header_file_addr != LLDB_INVALID_ADDRESS) { - if (section && section->GetFileSize() > 0 && - section->IsThreadSpecific() == false && - module_sp.get() == section->GetModule().get()) { - // Ignore __LINKEDIT and __DWARF segments - if (section->GetName() == GetSegmentNameLINKEDIT()) { - // Only map __LINKEDIT if we have an in memory image and this isn't a - // kernel binary like a kext or mach_kernel. - const bool is_memory_image = (bool)m_process_wp.lock(); - const Strata strata = GetStrata(); - if (is_memory_image == false || strata == eStrataKernel) - return LLDB_INVALID_ADDRESS; - } - return section->GetFileAddress() - mach_header_file_addr + - mach_header_load_address; - } - } + if (module_sp && header_section && section && + header_load_address != LLDB_INVALID_ADDRESS) { + lldb::addr_t file_addr = header_section->GetFileAddress(); + if (file_addr != LLDB_INVALID_ADDRESS && SectionIsLoadable(section)) + return section->GetFileAddress() - file_addr + header_load_address; } return LLDB_INVALID_ADDRESS; } @@ -5879,22 +6047,10 @@ bool ObjectFileMachO::SetLoadAddress(Target &target, lldb::addr_t value, // Iterate through the object file sections to find all of the // sections that size on disk (to avoid __PAGEZERO) and load them SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); - if (section_sp && section_sp->GetFileSize() > 0 && - section_sp->IsThreadSpecific() == false && - module_sp.get() == section_sp->GetModule().get()) { - // Ignore __LINKEDIT and __DWARF segments - if (section_sp->GetName() == GetSegmentNameLINKEDIT()) { - // Only map __LINKEDIT if we have an in memory image and this - // isn't a kernel binary like a kext or mach_kernel. - const bool is_memory_image = (bool)m_process_wp.lock(); - const Strata strata = GetStrata(); - if (is_memory_image == false || strata == eStrataKernel) - continue; - } + if (SectionIsLoadable(section_sp.get())) if (target.GetSectionLoadList().SetSectionLoadAddress( section_sp, section_sp->GetFileAddress() + value)) ++num_loaded_sections; - } } } else { // "value" is the new base address of the mach_header, adjust each @@ -5933,6 +6089,7 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, target_triple.getOS() == llvm::Triple::IOS || target_triple.getOS() == llvm::Triple::WatchOS || target_triple.getOS() == llvm::Triple::TvOS)) { + // NEED_BRIDGEOS_TRIPLE target_triple.getOS() == llvm::Triple::BridgeOS)) { bool make_core = false; switch (target_arch.GetMachine()) { case llvm::Triple::aarch64: @@ -6161,10 +6318,10 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, File core_file; std::string core_file_path(outfile.GetPath()); - error = core_file.Open(core_file_path.c_str(), - File::eOpenOptionWrite | - File::eOpenOptionTruncate | - File::eOpenOptionCanCreate); + error = FileSystem::Instance().Open(core_file, outfile, + File::eOpenOptionWrite | + File::eOpenOptionTruncate | + File::eOpenOptionCanCreate); if (error.Success()) { // Read 1 page at a time uint8_t bytes[0x1000]; diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h index be64518064b5..196abae807e9 100644 --- a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -10,16 +10,12 @@ #ifndef liblldb_ObjectFileMachO_h_ #define liblldb_ObjectFileMachO_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Address.h" #include "lldb/Core/FileSpecList.h" #include "lldb/Core/RangeMap.h" +#include "lldb/Host/SafeMachO.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/SafeMachO.h" #include "lldb/Utility/UUID.h" //---------------------------------------------------------------------- @@ -96,7 +92,7 @@ public: void Dump(lldb_private::Stream *s) override; - bool GetArchitecture(lldb_private::ArchSpec &arch) override; + lldb_private::ArchSpec GetArchitecture() override; bool GetUUID(lldb_private::UUID *uuid) override; @@ -108,7 +104,7 @@ public: lldb_private::Address GetEntryPointAddress() override; - lldb_private::Address GetHeaderAddress() override; + lldb_private::Address GetBaseAddress() override; uint32_t GetNumThreadContexts() override; @@ -151,10 +147,10 @@ protected: lldb::offset_t lc_offset, // Offset to the first load command lldb_private::UUID &uuid); - static bool GetArchitecture(const llvm::MachO::mach_header &header, - const lldb_private::DataExtractor &data, - lldb::offset_t lc_offset, - lldb_private::ArchSpec &arch); + static lldb_private::ArchSpec + GetArchitecture(const llvm::MachO::mach_header &header, + const lldb_private::DataExtractor &data, + lldb::offset_t lc_offset); // Intended for same-host arm device debugging where lldb needs to // detect libraries in the shared cache and augment the nlist entries @@ -196,6 +192,8 @@ protected: void SanitizeSegmentCommand(llvm::MachO::segment_command_64 &seg_cmd, uint32_t cmd_idx); + bool SectionIsLoadable(const lldb_private::Section *section); + llvm::MachO::mach_header m_header; static const lldb_private::ConstString &GetSegmentNameTEXT(); static const lldb_private::ConstString &GetSegmentNameDATA(); @@ -203,6 +201,7 @@ protected: static const lldb_private::ConstString &GetSegmentNameDATA_CONST(); static const lldb_private::ConstString &GetSegmentNameOBJC(); static const lldb_private::ConstString &GetSegmentNameLINKEDIT(); + static const lldb_private::ConstString &GetSegmentNameDWARF(); static const lldb_private::ConstString &GetSectionNameEHFrame(); llvm::MachO::dysymtab_command m_dysymtab; diff --git a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index b2967f1532ab..d18ff617521f 100644 --- a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -23,11 +23,14 @@ #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" #include "lldb/Utility/UUID.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ @@ -86,6 +89,10 @@ ObjectFile *ObjectFilePECOFF::CreateInstance(const lldb::ModuleSP &module_sp, if (!objfile_ap || !objfile_ap->ParseHeader()) return nullptr; + // Cache coff binary. + if (!objfile_ap->CreateBinary()) + return nullptr; + return objfile_ap.release(); } @@ -131,9 +138,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( specs.Append(ModuleSpec(file, spec)); spec.SetTriple("i686-pc-windows"); specs.Append(ModuleSpec(file, spec)); - } - else if (coff_header.machine == MachineArmNt) - { + } else if (coff_header.machine == MachineArmNt) { spec.SetTriple("arm-pc-windows"); specs.Append(ModuleSpec(file, spec)); } @@ -168,6 +173,40 @@ lldb::SymbolType ObjectFilePECOFF::MapSymbolType(uint16_t coff_symbol_type) { return lldb::eSymbolTypeInvalid; } +bool ObjectFilePECOFF::CreateBinary() { + if (m_owningbin) + return true; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + + auto binary = llvm::object::createBinary(m_file.GetPath()); + if (!binary) { + if (log) + log->Printf("ObjectFilePECOFF::CreateBinary() - failed to create binary " + "for file (%s): %s", + m_file ? m_file.GetPath().c_str() : "<NULL>", + errorToErrorCode(binary.takeError()).message().c_str()); + return false; + } + + // Make sure we only handle COFF format. + if (!binary->getBinary()->isCOFF() && + !binary->getBinary()->isCOFFImportFile()) + return false; + + m_owningbin = OWNBINType(std::move(*binary)); + if (log) + log->Printf("%p ObjectFilePECOFF::CreateBinary() module = %p (%s), file = " + "%s, binary = %p (Bin = %p)", + static_cast<void *>(this), + static_cast<void *>(GetModule().get()), + GetModule()->GetSpecificationDescription().c_str(), + m_file ? m_file.GetPath().c_str() : "<NULL>", + static_cast<void *>(m_owningbin.getPointer()), + static_cast<void *>(m_owningbin->getBinary())); + return true; +} + ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, lldb::offset_t data_offset, @@ -176,7 +215,7 @@ ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp, lldb::offset_t length) : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), m_dos_header(), m_coff_header(), m_coff_header_opt(), m_sect_headers(), - m_entry_point_address() { + m_entry_point_address(), m_deps_filespec(), m_owningbin() { ::memset(&m_dos_header, 0, sizeof(m_dos_header)); ::memset(&m_coff_header, 0, sizeof(m_coff_header)); ::memset(&m_coff_header_opt, 0, sizeof(m_coff_header_opt)); @@ -188,7 +227,7 @@ ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp, addr_t header_addr) : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), m_dos_header(), m_coff_header(), m_coff_header_opt(), m_sect_headers(), - m_entry_point_address() { + m_entry_point_address(), m_deps_filespec(), m_owningbin() { ::memset(&m_dos_header, 0, sizeof(m_dos_header)); ::memset(&m_coff_header, 0, sizeof(m_coff_header)); ::memset(&m_coff_header_opt, 0, sizeof(m_coff_header_opt)); @@ -431,7 +470,7 @@ bool ObjectFilePECOFF::ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr) { DataExtractor ObjectFilePECOFF::ReadImageData(uint32_t offset, size_t size) { if (m_file) { - // A bit of a hack, but we intend to write to this buffer, so we can't + // A bit of a hack, but we intend to write to this buffer, so we can't // mmap it. auto buffer_sp = MapFileData(m_file, size, offset); return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()); @@ -488,25 +527,23 @@ bool ObjectFilePECOFF::ParseSectionHeaders( } } - return m_sect_headers.empty() == false; + return !m_sect_headers.empty(); } -bool ObjectFilePECOFF::GetSectionName(std::string §_name, - const section_header_t §) { - if (sect.name[0] == '/') { - lldb::offset_t stroff = strtoul(§.name[1], NULL, 10); +llvm::StringRef ObjectFilePECOFF::GetSectionName(const section_header_t §) { + llvm::StringRef hdr_name(sect.name, llvm::array_lengthof(sect.name)); + hdr_name = hdr_name.split('\0').first; + if (hdr_name.consume_front("/")) { + lldb::offset_t stroff; + if (!to_integer(hdr_name, stroff, 10)) + return ""; lldb::offset_t string_file_offset = m_coff_header.symoff + (m_coff_header.nsyms * 18) + stroff; - const char *name = m_data.GetCStr(&string_file_offset); - if (name) { - sect_name = name; - return true; - } - - return false; + if (const char *name = m_data.GetCStr(&string_file_offset)) + return name; + return ""; } - sect_name = sect.name; - return true; + return hdr_name; } //---------------------------------------------------------------------- @@ -663,144 +700,213 @@ bool ObjectFilePECOFF::IsStripped() { } void ObjectFilePECOFF::CreateSections(SectionList &unified_section_list) { - if (!m_sections_ap.get()) { - m_sections_ap.reset(new SectionList()); + if (m_sections_ap) + return; + m_sections_ap.reset(new SectionList()); + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + const uint32_t nsects = m_sect_headers.size(); ModuleSP module_sp(GetModule()); - if (module_sp) { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - const uint32_t nsects = m_sect_headers.size(); - ModuleSP module_sp(GetModule()); - for (uint32_t idx = 0; idx < nsects; ++idx) { - std::string sect_name; - GetSectionName(sect_name, m_sect_headers[idx]); - ConstString const_sect_name(sect_name.c_str()); - static ConstString g_code_sect_name(".code"); - static ConstString g_CODE_sect_name("CODE"); - static ConstString g_data_sect_name(".data"); - static ConstString g_DATA_sect_name("DATA"); - static ConstString g_bss_sect_name(".bss"); - static ConstString g_BSS_sect_name("BSS"); - static ConstString g_debug_sect_name(".debug"); - static ConstString g_reloc_sect_name(".reloc"); - static ConstString g_stab_sect_name(".stab"); - static ConstString g_stabstr_sect_name(".stabstr"); - static ConstString g_sect_name_dwarf_debug_abbrev(".debug_abbrev"); - static ConstString g_sect_name_dwarf_debug_aranges(".debug_aranges"); - static ConstString g_sect_name_dwarf_debug_frame(".debug_frame"); - static ConstString g_sect_name_dwarf_debug_info(".debug_info"); - static ConstString g_sect_name_dwarf_debug_line(".debug_line"); - static ConstString g_sect_name_dwarf_debug_loc(".debug_loc"); - static ConstString g_sect_name_dwarf_debug_macinfo(".debug_macinfo"); - static ConstString g_sect_name_dwarf_debug_names(".debug_names"); - static ConstString g_sect_name_dwarf_debug_pubnames(".debug_pubnames"); - static ConstString g_sect_name_dwarf_debug_pubtypes(".debug_pubtypes"); - static ConstString g_sect_name_dwarf_debug_ranges(".debug_ranges"); - static ConstString g_sect_name_dwarf_debug_str(".debug_str"); - static ConstString g_sect_name_dwarf_debug_types(".debug_types"); - static ConstString g_sect_name_eh_frame(".eh_frame"); - static ConstString g_sect_name_go_symtab(".gosymtab"); - SectionType section_type = eSectionTypeOther; - if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE && - ((const_sect_name == g_code_sect_name) || - (const_sect_name == g_CODE_sect_name))) { - section_type = eSectionTypeCode; - } else if (m_sect_headers[idx].flags & - llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA && - ((const_sect_name == g_data_sect_name) || - (const_sect_name == g_DATA_sect_name))) { + for (uint32_t idx = 0; idx < nsects; ++idx) { + ConstString const_sect_name(GetSectionName(m_sect_headers[idx])); + static ConstString g_code_sect_name(".code"); + static ConstString g_CODE_sect_name("CODE"); + static ConstString g_data_sect_name(".data"); + static ConstString g_DATA_sect_name("DATA"); + static ConstString g_bss_sect_name(".bss"); + static ConstString g_BSS_sect_name("BSS"); + static ConstString g_debug_sect_name(".debug"); + static ConstString g_reloc_sect_name(".reloc"); + static ConstString g_stab_sect_name(".stab"); + static ConstString g_stabstr_sect_name(".stabstr"); + static ConstString g_sect_name_dwarf_debug_abbrev(".debug_abbrev"); + static ConstString g_sect_name_dwarf_debug_aranges(".debug_aranges"); + static ConstString g_sect_name_dwarf_debug_frame(".debug_frame"); + static ConstString g_sect_name_dwarf_debug_info(".debug_info"); + static ConstString g_sect_name_dwarf_debug_line(".debug_line"); + static ConstString g_sect_name_dwarf_debug_loc(".debug_loc"); + static ConstString g_sect_name_dwarf_debug_loclists(".debug_loclists"); + static ConstString g_sect_name_dwarf_debug_macinfo(".debug_macinfo"); + static ConstString g_sect_name_dwarf_debug_names(".debug_names"); + static ConstString g_sect_name_dwarf_debug_pubnames(".debug_pubnames"); + static ConstString g_sect_name_dwarf_debug_pubtypes(".debug_pubtypes"); + static ConstString g_sect_name_dwarf_debug_ranges(".debug_ranges"); + static ConstString g_sect_name_dwarf_debug_str(".debug_str"); + static ConstString g_sect_name_dwarf_debug_types(".debug_types"); + static ConstString g_sect_name_eh_frame(".eh_frame"); + static ConstString g_sect_name_go_symtab(".gosymtab"); + SectionType section_type = eSectionTypeOther; + if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE && + ((const_sect_name == g_code_sect_name) || + (const_sect_name == g_CODE_sect_name))) { + section_type = eSectionTypeCode; + } else if (m_sect_headers[idx].flags & + llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA && + ((const_sect_name == g_data_sect_name) || + (const_sect_name == g_DATA_sect_name))) { + if (m_sect_headers[idx].size == 0 && m_sect_headers[idx].offset == 0) + section_type = eSectionTypeZeroFill; + else section_type = eSectionTypeData; - } else if (m_sect_headers[idx].flags & - llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA && - ((const_sect_name == g_bss_sect_name) || - (const_sect_name == g_BSS_sect_name))) { - if (m_sect_headers[idx].size == 0) - section_type = eSectionTypeZeroFill; - else - section_type = eSectionTypeData; - } else if (const_sect_name == g_debug_sect_name) { - section_type = eSectionTypeDebug; - } else if (const_sect_name == g_stabstr_sect_name) { - section_type = eSectionTypeDataCString; - } else if (const_sect_name == g_reloc_sect_name) { - section_type = eSectionTypeOther; - } else if (const_sect_name == g_sect_name_dwarf_debug_abbrev) - section_type = eSectionTypeDWARFDebugAbbrev; - else if (const_sect_name == g_sect_name_dwarf_debug_aranges) - section_type = eSectionTypeDWARFDebugAranges; - else if (const_sect_name == g_sect_name_dwarf_debug_frame) - section_type = eSectionTypeDWARFDebugFrame; - else if (const_sect_name == g_sect_name_dwarf_debug_info) - section_type = eSectionTypeDWARFDebugInfo; - else if (const_sect_name == g_sect_name_dwarf_debug_line) - section_type = eSectionTypeDWARFDebugLine; - else if (const_sect_name == g_sect_name_dwarf_debug_loc) - section_type = eSectionTypeDWARFDebugLoc; - else if (const_sect_name == g_sect_name_dwarf_debug_macinfo) - section_type = eSectionTypeDWARFDebugMacInfo; - else if (const_sect_name == g_sect_name_dwarf_debug_names) - section_type = eSectionTypeDWARFDebugNames; - else if (const_sect_name == g_sect_name_dwarf_debug_pubnames) - section_type = eSectionTypeDWARFDebugPubNames; - else if (const_sect_name == g_sect_name_dwarf_debug_pubtypes) - section_type = eSectionTypeDWARFDebugPubTypes; - else if (const_sect_name == g_sect_name_dwarf_debug_ranges) - section_type = eSectionTypeDWARFDebugRanges; - else if (const_sect_name == g_sect_name_dwarf_debug_str) - section_type = eSectionTypeDWARFDebugStr; - else if (const_sect_name == g_sect_name_dwarf_debug_types) - section_type = eSectionTypeDWARFDebugTypes; - else if (const_sect_name == g_sect_name_eh_frame) - section_type = eSectionTypeEHFrame; - else if (const_sect_name == g_sect_name_go_symtab) - section_type = eSectionTypeGoSymtab; - else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE) { - section_type = eSectionTypeCode; - } else if (m_sect_headers[idx].flags & - llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) { + } else if (m_sect_headers[idx].flags & + llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA && + ((const_sect_name == g_bss_sect_name) || + (const_sect_name == g_BSS_sect_name))) { + if (m_sect_headers[idx].size == 0) + section_type = eSectionTypeZeroFill; + else + section_type = eSectionTypeData; + } else if (const_sect_name == g_debug_sect_name) { + section_type = eSectionTypeDebug; + } else if (const_sect_name == g_stabstr_sect_name) { + section_type = eSectionTypeDataCString; + } else if (const_sect_name == g_reloc_sect_name) { + section_type = eSectionTypeOther; + } else if (const_sect_name == g_sect_name_dwarf_debug_abbrev) + section_type = eSectionTypeDWARFDebugAbbrev; + else if (const_sect_name == g_sect_name_dwarf_debug_aranges) + section_type = eSectionTypeDWARFDebugAranges; + else if (const_sect_name == g_sect_name_dwarf_debug_frame) + section_type = eSectionTypeDWARFDebugFrame; + else if (const_sect_name == g_sect_name_dwarf_debug_info) + section_type = eSectionTypeDWARFDebugInfo; + else if (const_sect_name == g_sect_name_dwarf_debug_line) + section_type = eSectionTypeDWARFDebugLine; + else if (const_sect_name == g_sect_name_dwarf_debug_loc) + section_type = eSectionTypeDWARFDebugLoc; + else if (const_sect_name == g_sect_name_dwarf_debug_loclists) + section_type = eSectionTypeDWARFDebugLocLists; + else if (const_sect_name == g_sect_name_dwarf_debug_macinfo) + section_type = eSectionTypeDWARFDebugMacInfo; + else if (const_sect_name == g_sect_name_dwarf_debug_names) + section_type = eSectionTypeDWARFDebugNames; + else if (const_sect_name == g_sect_name_dwarf_debug_pubnames) + section_type = eSectionTypeDWARFDebugPubNames; + else if (const_sect_name == g_sect_name_dwarf_debug_pubtypes) + section_type = eSectionTypeDWARFDebugPubTypes; + else if (const_sect_name == g_sect_name_dwarf_debug_ranges) + section_type = eSectionTypeDWARFDebugRanges; + else if (const_sect_name == g_sect_name_dwarf_debug_str) + section_type = eSectionTypeDWARFDebugStr; + else if (const_sect_name == g_sect_name_dwarf_debug_types) + section_type = eSectionTypeDWARFDebugTypes; + else if (const_sect_name == g_sect_name_eh_frame) + section_type = eSectionTypeEHFrame; + else if (const_sect_name == g_sect_name_go_symtab) + section_type = eSectionTypeGoSymtab; + else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE) { + section_type = eSectionTypeCode; + } else if (m_sect_headers[idx].flags & + llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) { + section_type = eSectionTypeData; + } else if (m_sect_headers[idx].flags & + llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) { + if (m_sect_headers[idx].size == 0) + section_type = eSectionTypeZeroFill; + else section_type = eSectionTypeData; - } else if (m_sect_headers[idx].flags & - llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) { - if (m_sect_headers[idx].size == 0) - section_type = eSectionTypeZeroFill; - else - section_type = eSectionTypeData; - } - - // Use a segment ID of the segment index shifted left by 8 so they - // never conflict with any of the sections. - SectionSP section_sp(new Section( - module_sp, // Module to which this section belongs - this, // Object file to which this section belongs - idx + 1, // Section ID is the 1 based segment index shifted right by - // 8 bits as not to collide with any of the 256 section IDs - // that are possible - const_sect_name, // Name of this section - section_type, // This section is a container of other sections. - m_coff_header_opt.image_base + - m_sect_headers[idx].vmaddr, // File VM address == addresses as - // they are found in the object file - m_sect_headers[idx].vmsize, // VM size in bytes of this section - m_sect_headers[idx] - .offset, // Offset to the data for this section in the file - m_sect_headers[idx] - .size, // Size in bytes of this section as found in the file - m_coff_header_opt.sect_alignment, // Section alignment - m_sect_headers[idx].flags)); // Flags for this section - - // section_sp->SetIsEncrypted (segment_is_encrypted); - - unified_section_list.AddSection(section_sp); - m_sections_ap->AddSection(section_sp); } + + // Use a segment ID of the segment index shifted left by 8 so they + // never conflict with any of the sections. + SectionSP section_sp(new Section( + module_sp, // Module to which this section belongs + this, // Object file to which this section belongs + idx + 1, // Section ID is the 1 based segment index shifted right by + // 8 bits as not to collide with any of the 256 section IDs + // that are possible + const_sect_name, // Name of this section + section_type, // This section is a container of other sections. + m_coff_header_opt.image_base + + m_sect_headers[idx].vmaddr, // File VM address == addresses as + // they are found in the object file + m_sect_headers[idx].vmsize, // VM size in bytes of this section + m_sect_headers[idx] + .offset, // Offset to the data for this section in the file + m_sect_headers[idx] + .size, // Size in bytes of this section as found in the file + m_coff_header_opt.sect_alignment, // Section alignment + m_sect_headers[idx].flags)); // Flags for this section + + // section_sp->SetIsEncrypted (segment_is_encrypted); + + unified_section_list.AddSection(section_sp); + m_sections_ap->AddSection(section_sp); } } } bool ObjectFilePECOFF::GetUUID(UUID *uuid) { return false; } +uint32_t ObjectFilePECOFF::ParseDependentModules() { + ModuleSP module_sp(GetModule()); + if (!module_sp) + return 0; + + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + if (m_deps_filespec) + return m_deps_filespec->GetSize(); + + // Cache coff binary if it is not done yet. + if (!CreateBinary()) + return 0; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p ObjectFilePECOFF::ParseDependentModules() module = %p " + "(%s), binary = %p (Bin = %p)", + static_cast<void *>(this), static_cast<void *>(module_sp.get()), + module_sp->GetSpecificationDescription().c_str(), + static_cast<void *>(m_owningbin.getPointer()), + m_owningbin ? static_cast<void *>(m_owningbin->getBinary()) + : nullptr); + + auto COFFObj = + llvm::dyn_cast<llvm::object::COFFObjectFile>(m_owningbin->getBinary()); + if (!COFFObj) + return 0; + + m_deps_filespec = FileSpecList(); + + for (const auto &entry : COFFObj->import_directories()) { + llvm::StringRef dll_name; + auto ec = entry.getName(dll_name); + // Report a bogus entry. + if (ec != std::error_code()) { + if (log) + log->Printf("ObjectFilePECOFF::ParseDependentModules() - failed to get " + "import directory entry name: %s", + ec.message().c_str()); + continue; + } + + // At this moment we only have the base name of the DLL. The full path can + // only be seen after the dynamic loading. Our best guess is Try to get it + // with the help of the object file's directory. + llvm::SmallString<128> dll_fullpath; + FileSpec dll_specs(dll_name); + dll_specs.GetDirectory().SetString(m_file.GetDirectory().GetCString()); + + if (!llvm::sys::fs::real_path(dll_specs.GetPath(), dll_fullpath)) + m_deps_filespec->Append(FileSpec(dll_fullpath)); + else { + // Known DLLs or DLL not found in the object file directory. + m_deps_filespec->Append(FileSpec(dll_name)); + } + } + return m_deps_filespec->GetSize(); +} + uint32_t ObjectFilePECOFF::GetDependentModules(FileSpecList &files) { - return 0; + auto num_modules = ParseDependentModules(); + auto original_size = files.GetSize(); + + for (unsigned i = 0; i < num_modules; ++i) + files.AppendIfUnique(m_deps_filespec->GetFileSpecAtIndex(i)); + + return files.GetSize() - original_size; } lldb_private::Address ObjectFilePECOFF::GetEntryPointAddress() { @@ -811,12 +917,12 @@ lldb_private::Address ObjectFilePECOFF::GetEntryPointAddress() { return m_entry_point_address; SectionList *section_list = GetSectionList(); - addr_t offset = m_coff_header_opt.entry; + addr_t file_addr = m_coff_header_opt.entry + m_coff_header_opt.image_base; if (!section_list) - m_entry_point_address.SetOffset(offset); + m_entry_point_address.SetOffset(file_addr); else - m_entry_point_address.ResolveAddressUsingFileSections(offset, section_list); + m_entry_point_address.ResolveAddressUsingFileSections(file_addr, section_list); return m_entry_point_address; } @@ -834,8 +940,7 @@ void ObjectFilePECOFF::Dump(Stream *s) { s->Indent(); s->PutCString("ObjectFilePECOFF"); - ArchSpec header_arch; - GetArchitecture(header_arch); + ArchSpec header_arch = GetArchitecture(); *s << ", file = '" << m_file << "', arch = " << header_arch.GetArchitectureName() << "\n"; @@ -857,6 +962,9 @@ void ObjectFilePECOFF::Dump(Stream *s) { s->EOL(); DumpSectionHeaders(s); s->EOL(); + + DumpDependentModules(s); + s->EOL(); } } @@ -974,8 +1082,7 @@ void ObjectFilePECOFF::DumpOptCOFFHeader(Stream *s, //---------------------------------------------------------------------- void ObjectFilePECOFF::DumpSectionHeader(Stream *s, const section_header_t &sh) { - std::string name; - GetSectionName(name, sh); + std::string name = GetSectionName(sh); s->Printf("%-16s 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%4.4x " "0x%4.4x 0x%8.8x\n", name.c_str(), sh.vmaddr, sh.vmsize, sh.offset, sh.size, sh.reloff, @@ -1004,6 +1111,22 @@ void ObjectFilePECOFF::DumpSectionHeaders(Stream *s) { } } +//---------------------------------------------------------------------- +// DumpDependentModules +// +// Dump all of the dependent modules to the specified output stream +//---------------------------------------------------------------------- +void ObjectFilePECOFF::DumpDependentModules(lldb_private::Stream *s) { + auto num_modules = ParseDependentModules(); + if (num_modules > 0) { + s->PutCString("Dependent Modules\n"); + for (unsigned i = 0; i < num_modules; ++i) { + auto spec = m_deps_filespec->GetFileSpecAtIndex(i); + s->Printf(" %s\n", spec.GetFilename().GetCString()); + } + } +} + bool ObjectFilePECOFF::IsWindowsSubsystem() { switch (m_coff_header_opt.subsystem) { case llvm::COFF::IMAGE_SUBSYSTEM_NATIVE: @@ -1019,9 +1142,11 @@ bool ObjectFilePECOFF::IsWindowsSubsystem() { } } -bool ObjectFilePECOFF::GetArchitecture(ArchSpec &arch) { +ArchSpec ObjectFilePECOFF::GetArchitecture() { uint16_t machine = m_coff_header.machine; switch (machine) { + default: + break; case llvm::COFF::IMAGE_FILE_MACHINE_AMD64: case llvm::COFF::IMAGE_FILE_MACHINE_I386: case llvm::COFF::IMAGE_FILE_MACHINE_POWERPC: @@ -1029,14 +1154,13 @@ bool ObjectFilePECOFF::GetArchitecture(ArchSpec &arch) { case llvm::COFF::IMAGE_FILE_MACHINE_ARM: case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT: case llvm::COFF::IMAGE_FILE_MACHINE_THUMB: + ArchSpec arch; arch.SetArchitecture(eArchTypeCOFF, machine, LLDB_INVALID_CPUTYPE, IsWindowsSubsystem() ? llvm::Triple::Win32 : llvm::Triple::UnknownOS); - return true; - default: - break; + return arch; } - return false; + return ArchSpec(); } ObjectFile::Type ObjectFilePECOFF::CalculateType() { @@ -1050,6 +1174,7 @@ ObjectFile::Type ObjectFilePECOFF::CalculateType() { } ObjectFile::Strata ObjectFilePECOFF::CalculateStrata() { return eStrataUser; } + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ diff --git a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h index d8a94e19d34f..9fd313f26a0a 100644 --- a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h +++ b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h @@ -10,13 +10,10 @@ #ifndef liblldb_ObjectFilePECOFF_h_ #define liblldb_ObjectFilePECOFF_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Symbol/ObjectFile.h" +#include "llvm/Object/Binary.h" class ObjectFilePECOFF : public lldb_private::ObjectFile { public: @@ -113,7 +110,7 @@ public: void Dump(lldb_private::Stream *s) override; - bool GetArchitecture(lldb_private::ArchSpec &arch) override; + lldb_private::ArchSpec GetArchitecture() override; bool GetUUID(lldb_private::UUID *uuid) override; @@ -261,6 +258,8 @@ protected: bool ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr); bool ParseSectionHeaders(uint32_t offset); + uint32_t ParseDependentModules(); + static void DumpDOSHeader(lldb_private::Stream *s, const dos_header_t &header); static void DumpCOFFHeader(lldb_private::Stream *s, @@ -269,19 +268,27 @@ protected: const coff_opt_header_t &header); void DumpSectionHeaders(lldb_private::Stream *s); void DumpSectionHeader(lldb_private::Stream *s, const section_header_t &sh); - bool GetSectionName(std::string §_name, const section_header_t §); + void DumpDependentModules(lldb_private::Stream *s); + + llvm::StringRef GetSectionName(const section_header_t §); typedef std::vector<section_header_t> SectionHeaderColl; typedef SectionHeaderColl::iterator SectionHeaderCollIter; typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter; private: + bool CreateBinary(); + +private: dos_header_t m_dos_header; coff_header_t m_coff_header; coff_opt_header_t m_coff_header_opt; SectionHeaderColl m_sect_headers; lldb::addr_t m_image_base; lldb_private::Address m_entry_point_address; + llvm::Optional<lldb_private::FileSpecList> m_deps_filespec; + typedef llvm::object::OwningBinary<llvm::object::Binary> OWNBINType; + llvm::Optional<OWNBINType> m_owningbin; }; #endif // liblldb_ObjectFilePECOFF_h_ diff --git a/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp b/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp index d6553f6e5142..e77888c871b5 100644 --- a/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp +++ b/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp @@ -16,7 +16,7 @@ #ifdef _WIN32 #include "lldb/Host/windows/windows.h" -#include <dbghelp.h> // for MiniDumpWriteDump +#include <dbghelp.h> #endif namespace lldb_private { |