From d13f691f41c94b8681829c85ecb7a23fcbb9caf1 Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Mon, 2 Oct 2017 14:35:07 +0000 Subject: [PATCH] Improve FreeBSD kernel debugging FreeBSD kernel modules are actually relocatable (.o) ELF files and this previously caused some issues for LLDB. This change addresses these when using lldb to symbolicate FreeBSD kernel backtraces. The major problems: - Relocations were not being applied to the DWARF debug info despite there being code to do this. Several issues prevented it from working: - Relocations are computed at the same time as the symbol table, but in the case of split debug files, symbol table parsing always redirects to the primary object file, meaning that relocations would never be applied in the debug file. - There's actually no guarantee that the symbol table has been parsed yet when trying to parse debug information. - When actually applying relocations, it will segfault because the object files are not mapped with MAP_PRIVATE and PROT_WRITE. - LLDB returned invalid results when performing ordinary address-to- symbol resolution. It turned out that the addresses specified in the section headers were all 0, so LLDB believed all the sections had overlapping "file addresses" and would sometimes return a symbol from the wrong section. Patch by Brian Koropoff Differential Revision: https://reviews.llvm.org/D38142 llvm-svn: 314672 --- lldb/include/lldb/Core/Section.h | 9 ++- lldb/include/lldb/Symbol/ArmUnwindInfo.h | 2 +- lldb/include/lldb/Symbol/ObjectFile.h | 18 +++-- lldb/source/Core/Section.cpp | 6 +- .../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 84 ++++++++++++++++------ lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h | 25 ++++--- .../Plugins/ObjectFile/JIT/ObjectFileJIT.cpp | 8 +-- lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h | 8 +-- .../Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 2 +- lldb/source/Symbol/ArmUnwindInfo.cpp | 2 +- lldb/source/Symbol/ObjectFile.cpp | 22 ++++-- 11 files changed, 126 insertions(+), 60 deletions(-) diff --git a/lldb/include/lldb/Core/Section.h b/lldb/include/lldb/Core/Section.h index 0466693..2d5d644 100644 --- a/lldb/include/lldb/Core/Section.h +++ b/lldb/include/lldb/Core/Section.h @@ -238,7 +238,7 @@ public: /// section has no data or \a offset is not a valid offset /// in this section. //------------------------------------------------------------------ - lldb::offset_t GetSectionData(DataExtractor &data) const; + lldb::offset_t GetSectionData(DataExtractor &data); uint32_t GetLog2Align() { return m_log2align; } @@ -247,6 +247,10 @@ public: // Get the number of host bytes required to hold a target byte uint32_t GetTargetByteSize() const { return m_target_byte_size; } + bool IsRelocated() const { return m_relocated; } + + void SetIsRelocated(bool b) { m_relocated = b; } + protected: ObjectFile *m_obj_file; // The object file that data for this section should // be read from @@ -274,7 +278,8 @@ protected: m_thread_specific : 1, // This section is thread specific m_readable : 1, // If this section has read permissions m_writable : 1, // If this section has write permissions - m_executable : 1; // If this section has executable permissions + m_executable : 1, // If this section has executable permissions + m_relocated : 1; // If this section has had relocations applied uint32_t m_target_byte_size; // Some architectures have non-8-bit byte size. // This is specified as // as a multiple number of a host bytes diff --git a/lldb/include/lldb/Symbol/ArmUnwindInfo.h b/lldb/include/lldb/Symbol/ArmUnwindInfo.h index ef67a31..422408b 100644 --- a/lldb/include/lldb/Symbol/ArmUnwindInfo.h +++ b/lldb/include/lldb/Symbol/ArmUnwindInfo.h @@ -31,7 +31,7 @@ namespace lldb_private { class ArmUnwindInfo { public: - ArmUnwindInfo(const ObjectFile &objfile, lldb::SectionSP &arm_exidx, + ArmUnwindInfo(ObjectFile &objfile, lldb::SectionSP &arm_exidx, lldb::SectionSP &arm_extab); ~ArmUnwindInfo(); diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index a4c7b01..60a748b 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -352,6 +352,12 @@ public: virtual Symtab *GetSymtab() = 0; //------------------------------------------------------------------ + /// Perform relocations on the section if necessary. + /// + //------------------------------------------------------------------ + virtual void RelocateSection(lldb_private::Section *section); + + //------------------------------------------------------------------ /// Appends a Symbol for the specified so_addr to the symbol table. /// /// If verify_unique is false, the symbol table is not searched @@ -792,15 +798,15 @@ public: size_t CopyData(lldb::offset_t offset, size_t length, void *dst) const; - virtual size_t ReadSectionData(const Section *section, + virtual size_t ReadSectionData(Section *section, lldb::offset_t section_offset, void *dst, - size_t dst_len) const; + size_t dst_len); - virtual size_t ReadSectionData(const Section *section, - DataExtractor §ion_data) const; + virtual size_t ReadSectionData(Section *section, + DataExtractor §ion_data); - size_t MemoryMapSectionData(const Section *section, - DataExtractor §ion_data) const; + size_t MemoryMapSectionData(Section *section, + DataExtractor §ion_data); bool IsInMemory() const { return m_memory_addr != LLDB_INVALID_ADDRESS; } diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp index 2ea497e..c9faf9f 100644 --- a/lldb/source/Core/Section.cpp +++ b/lldb/source/Core/Section.cpp @@ -135,7 +135,7 @@ Section::Section(const ModuleSP &module_sp, ObjectFile *obj_file, m_file_offset(file_offset), m_file_size(file_size), m_log2align(log2align), m_children(), m_fake(false), m_encrypted(false), m_thread_specific(false), m_readable(false), m_writable(false), - m_executable(false), m_target_byte_size(target_byte_size) { + m_executable(false), m_relocated(false), m_target_byte_size(target_byte_size) { // printf ("Section::Section(%p): module=%p, sect_id = 0x%16.16" PRIx64 ", // addr=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), file [0x%16.16" PRIx64 " // - 0x%16.16" PRIx64 "), flags = 0x%8.8x, name = %s\n", @@ -157,7 +157,7 @@ Section::Section(const lldb::SectionSP &parent_section_sp, m_file_offset(file_offset), m_file_size(file_size), m_log2align(log2align), m_children(), m_fake(false), m_encrypted(false), m_thread_specific(false), m_readable(false), m_writable(false), - m_executable(false), m_target_byte_size(target_byte_size) { + m_executable(false), m_relocated(false), m_target_byte_size(target_byte_size) { // printf ("Section::Section(%p): module=%p, sect_id = 0x%16.16" PRIx64 ", // addr=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), file [0x%16.16" PRIx64 " // - 0x%16.16" PRIx64 "), flags = 0x%8.8x, name = %s.%s\n", @@ -392,7 +392,7 @@ lldb::offset_t Section::GetSectionData(void *dst, lldb::offset_t dst_len, return 0; } -lldb::offset_t Section::GetSectionData(DataExtractor §ion_data) const { +lldb::offset_t Section::GetSectionData(DataExtractor §ion_data) { if (m_obj_file) return m_obj_file->ReadSectionData(this, section_data); return 0; diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 0f67ab5..e431d4a 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -405,7 +405,7 @@ ObjectFile *ObjectFileELF::CreateInstance(const lldb::ModuleSP &module_sp, lldb::offset_t length) { if (!data_sp) { data_sp = - DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset); + DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset, true); if (!data_sp) return nullptr; data_offset = 0; @@ -423,7 +423,7 @@ ObjectFile *ObjectFileELF::CreateInstance(const lldb::ModuleSP &module_sp, // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { data_sp = - DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset); + DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset, true); if (!data_sp) return nullptr; data_offset = 0; @@ -1818,6 +1818,12 @@ 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; @@ -1990,11 +1996,18 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { ? m_arch_spec.GetDataByteSize() : eSectionTypeCode == sect_type ? m_arch_spec.GetCodeByteSize() : 1; - const addr_t sect_file_addr = header.sh_flags & SHF_ALLOC - ? header.sh_addr - : LLDB_INVALID_ADDRESS; 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; + } + SectionSP section_sp(new Section( GetModule(), // Module to which this section belongs. this, // ObjectFile to which this section belongs and should read @@ -2002,7 +2015,7 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { SectionIndex(I), // Section ID. name, // Section name. sect_type, // Section type. - sect_file_addr, // VM address. + 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. @@ -2720,7 +2733,7 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, user_id_t start_id, rel_data, symtab_data, strtab_data); } -unsigned ObjectFileELF::RelocateSection( +unsigned ObjectFileELF::ApplyRelocations( Symtab *symtab, const ELFHeader *hdr, const ELFSectionHeader *rel_hdr, const ELFSectionHeader *symtab_hdr, const ELFSectionHeader *debug_hdr, DataExtractor &rel_data, DataExtractor &symtab_data, @@ -2797,7 +2810,8 @@ unsigned ObjectFileELF::RelocateSection( } unsigned ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, - user_id_t rel_id) { + user_id_t rel_id, + lldb_private::Symtab *thetab) { assert(rel_hdr->sh_type == SHT_RELA || rel_hdr->sh_type == SHT_REL); // Parse in the section list if needed. @@ -2833,10 +2847,11 @@ unsigned ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, DataExtractor symtab_data; DataExtractor debug_data; - if (ReadSectionData(rel, rel_data) && ReadSectionData(symtab, symtab_data) && - ReadSectionData(debug, debug_data)) { - RelocateSection(m_symtab_ap.get(), &m_header, rel_hdr, symtab_hdr, - debug_hdr, rel_data, symtab_data, debug_data, debug); + if (GetData(rel->GetFileOffset(), rel->GetFileSize(), rel_data) && + GetData(symtab->GetFileOffset(), symtab->GetFileSize(), symtab_data) && + GetData(debug->GetFileOffset(), debug->GetFileSize(), debug_data)) { + ApplyRelocations(thetab, &m_header, rel_hdr, symtab_hdr, debug_hdr, + rel_data, symtab_data, debug_data, debug); } return 0; @@ -2930,21 +2945,48 @@ Symtab *ObjectFileELF::GetSymtab() { m_symtab_ap->CalculateSymbolSizes(); } + return m_symtab_ap.get(); +} + +void ObjectFileELF::RelocateSection(lldb_private::Section *section) +{ + static const char *debug_prefix = ".debug"; + + // Set relocated bit so we stop getting called, regardless of + // whether we actually relocate. + section->SetIsRelocated(true); + + // We only relocate in ELF relocatable files + if (CalculateType() != eTypeObjectFile) + return; + + const char *section_name = section->GetName().GetCString(); + // Can't relocate that which can't be named + if (section_name == nullptr) + return; + + // We don't relocate non-debug sections at the moment + if (strncmp(section_name, debug_prefix, strlen(debug_prefix))) + return; + + // Relocation section names to look for + std::string needle = std::string(".rel") + section_name; + std::string needlea = std::string(".rela") + section_name; + for (SectionHeaderCollIter I = m_section_headers.begin(); I != m_section_headers.end(); ++I) { if (I->sh_type == SHT_RELA || I->sh_type == SHT_REL) { - if (CalculateType() == eTypeObjectFile) { - const char *section_name = I->section_name.AsCString(""); - if (strstr(section_name, ".rela.debug") || - strstr(section_name, ".rel.debug")) { - const ELFSectionHeader &reloc_header = *I; - user_id_t reloc_id = SectionIndex(I); - RelocateDebugSections(&reloc_header, reloc_id); - } + const char *hay_name = I->section_name.GetCString(); + if (hay_name == nullptr) + continue; + if (needle == hay_name || needlea == hay_name) { + const ELFSectionHeader &reloc_header = *I; + user_id_t reloc_id = SectionIndex(I); + RelocateDebugSections(&reloc_header, reloc_id, GetSymtab()); + break; } } } - return m_symtab_ap.get(); } void ObjectFileELF::ParseUnwindSymbols(Symtab *symbol_table, diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 6d8717b..e0478cc 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -154,6 +154,8 @@ public: llvm::StringRef StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override; + void RelocateSection(lldb_private::Section *section) override; + private: ObjectFileELF(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, const lldb_private::FileSpec *file, @@ -296,17 +298,18 @@ private: /// Relocates debug sections unsigned RelocateDebugSections(const elf::ELFSectionHeader *rel_hdr, - lldb::user_id_t rel_id); - - unsigned RelocateSection(lldb_private::Symtab *symtab, - const elf::ELFHeader *hdr, - const elf::ELFSectionHeader *rel_hdr, - const elf::ELFSectionHeader *symtab_hdr, - const elf::ELFSectionHeader *debug_hdr, - lldb_private::DataExtractor &rel_data, - lldb_private::DataExtractor &symtab_data, - lldb_private::DataExtractor &debug_data, - lldb_private::Section *rel_section); + lldb::user_id_t rel_id, + lldb_private::Symtab *thetab); + + unsigned ApplyRelocations(lldb_private::Symtab *symtab, + const elf::ELFHeader *hdr, + const elf::ELFSectionHeader *rel_hdr, + const elf::ELFSectionHeader *symtab_hdr, + const elf::ELFSectionHeader *debug_hdr, + lldb_private::DataExtractor &rel_data, + lldb_private::DataExtractor &symtab_data, + lldb_private::DataExtractor &debug_data, + lldb_private::Section *rel_section); /// Loads the section name string table into m_shstr_data. Returns the /// number of bytes constituting the table. diff --git a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp index 06406c6..90982e8 100644 --- a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp +++ b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp @@ -230,9 +230,9 @@ bool ObjectFileJIT::SetLoadAddress(Target &target, lldb::addr_t value, return num_loaded_sections > 0; } -size_t ObjectFileJIT::ReadSectionData(const lldb_private::Section *section, +size_t ObjectFileJIT::ReadSectionData(lldb_private::Section *section, lldb::offset_t section_offset, void *dst, - size_t dst_len) const { + size_t dst_len) { lldb::offset_t file_size = section->GetFileSize(); if (section_offset < file_size) { size_t src_len = file_size - section_offset; @@ -248,8 +248,8 @@ size_t ObjectFileJIT::ReadSectionData(const lldb_private::Section *section, } size_t ObjectFileJIT::ReadSectionData( - const lldb_private::Section *section, - lldb_private::DataExtractor §ion_data) const { + lldb_private::Section *section, + lldb_private::DataExtractor §ion_data) { if (section->GetFileSize()) { const void *src = (void *)(uintptr_t)section->GetFileOffset(); diff --git a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h index a211645..c964906 100644 --- a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h +++ b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h @@ -83,13 +83,13 @@ public: uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; - size_t ReadSectionData(const lldb_private::Section *section, + size_t ReadSectionData(lldb_private::Section *section, lldb::offset_t section_offset, void *dst, - size_t dst_len) const override; + size_t dst_len) override; size_t - ReadSectionData(const lldb_private::Section *section, - lldb_private::DataExtractor §ion_data) const override; + ReadSectionData(lldb_private::Section *section, + lldb_private::DataExtractor §ion_data) override; lldb_private::Address GetEntryPointAddress() override; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 4642c2e..27752da 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -436,7 +436,7 @@ void SymbolFileDWARF::InitializeObject() { ModuleSP module_sp(m_obj_file->GetModule()); if (module_sp) { const SectionList *section_list = module_sp->GetSectionList(); - const Section *section = + Section *section = section_list->FindSectionByName(GetDWARFMachOSegmentName()).get(); // Memory map the DWARF mach-o segment so we have everything mmap'ed diff --git a/lldb/source/Symbol/ArmUnwindInfo.cpp b/lldb/source/Symbol/ArmUnwindInfo.cpp index 742c057..4da307b 100644 --- a/lldb/source/Symbol/ArmUnwindInfo.cpp +++ b/lldb/source/Symbol/ArmUnwindInfo.cpp @@ -46,7 +46,7 @@ bool ArmUnwindInfo::ArmExidxEntry::operator<(const ArmExidxEntry &other) const { return address < other.address; } -ArmUnwindInfo::ArmUnwindInfo(const ObjectFile &objfile, SectionSP &arm_exidx, +ArmUnwindInfo::ArmUnwindInfo(ObjectFile &objfile, SectionSP &arm_exidx, SectionSP &arm_extab) : m_byte_order(objfile.GetByteOrder()), m_arm_exidx_sp(arm_exidx), m_arm_extab_sp(arm_extab) { diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp index c2e2be9..39593bc 100644 --- a/lldb/source/Symbol/ObjectFile.cpp +++ b/lldb/source/Symbol/ObjectFile.cpp @@ -483,9 +483,9 @@ size_t ObjectFile::CopyData(lldb::offset_t offset, size_t length, return m_data.CopyData(offset, length, dst); } -size_t ObjectFile::ReadSectionData(const Section *section, +size_t ObjectFile::ReadSectionData(Section *section, lldb::offset_t section_offset, void *dst, - size_t dst_len) const { + size_t dst_len) { assert(section); section_offset *= section->GetTargetByteSize(); @@ -505,6 +505,9 @@ size_t ObjectFile::ReadSectionData(const Section *section, dst_len, error); } } else { + if (!section->IsRelocated()) + RelocateSection(section); + const lldb::offset_t section_file_size = section->GetFileSize(); if (section_offset < section_file_size) { const size_t section_bytes_left = section_file_size - section_offset; @@ -531,8 +534,8 @@ size_t ObjectFile::ReadSectionData(const Section *section, //---------------------------------------------------------------------- // Get the section data the file on disk //---------------------------------------------------------------------- -size_t ObjectFile::ReadSectionData(const Section *section, - DataExtractor §ion_data) const { +size_t ObjectFile::ReadSectionData(Section *section, + DataExtractor §ion_data) { // If some other objectfile owns this data, pass this to them. if (section->GetObjectFile() != this) return section->GetObjectFile()->ReadSectionData(section, section_data); @@ -562,8 +565,8 @@ size_t ObjectFile::ReadSectionData(const Section *section, } } -size_t ObjectFile::MemoryMapSectionData(const Section *section, - DataExtractor §ion_data) const { +size_t ObjectFile::MemoryMapSectionData(Section *section, + DataExtractor §ion_data) { // If some other objectfile owns this data, pass this to them. if (section->GetObjectFile() != this) return section->GetObjectFile()->MemoryMapSectionData(section, @@ -572,6 +575,9 @@ size_t ObjectFile::MemoryMapSectionData(const Section *section, if (IsInMemory()) { return ReadSectionData(section, section_data); } else { + if (!section->IsRelocated()) + RelocateSection(section); + // The object file now contains a full mmap'ed copy of the object file data, // so just use this return GetData(section->GetFileOffset(), section->GetFileSize(), @@ -694,3 +700,7 @@ Status ObjectFile::LoadInMemory(Target &target, bool set_pc) { } return error; } + +void ObjectFile::RelocateSection(lldb_private::Section *section) +{ +} -- 2.7.4