Greetings. I'm submitting a few patches that resolve issues I encountered when using lldb to symbolicate FreeBSD kernel backtraces. The problems mostly centered around FreeBSD kernel modules actually being relocatable (.o) ELF Files.
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. I rearranged some of the symbol table parsing code to ensure relocations would get applied consistently and added manual calls to make sure it happens before trying to use DWARF info, but it feels kind of hacky. I'm open to suggestions for refactoring it. I solved the file address problem by computing synthetic addresses for the sections in object files so that they would not overlap in LLDB's lookup maps. With all these changes I'm able to successfully symbolicate backtraces that pass through FreeBSD kernel modules. Let me know if there is a better/cleaner way to achieve any of these fixes. -- Brian Koropoff Dell EMC
From d923e9ff178c10f2b0c8747d09e8d13aa950df72 Mon Sep 17 00:00:00 2001 From: Brian Koropoff <brian.korop...@isilon.com> Date: Wed, 20 Sep 2017 10:44:08 -0700 Subject: [PATCH 1/4] ObjectFile:ELF: use private memory mappings This is necessary to be able to apply relocations to DWARF info. --- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 0f67ab5..e2f986b 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/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; -- 2.7.5
From 698b13b8fc43036e9df034363fa8a61b4707718e Mon Sep 17 00:00:00 2001 From: Brian Koropoff <brian.korop...@isilon.com> Date: Wed, 30 Aug 2017 18:49:16 -0700 Subject: [PATCH 2/4] ObjectFile:ELF: ensure relocations are done for split debug symbols --- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 27 ++++++++++++++++++------- source/Plugins/ObjectFile/ELF/ObjectFileELF.h | 7 ++++++- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index e2f986b..f6ea67e 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -815,7 +815,8 @@ ObjectFileELF::ObjectFileELF(const lldb::ModuleSP &module_sp, : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), m_header(), m_uuid(), m_gnu_debuglink_file(), m_gnu_debuglink_crc(0), m_program_headers(), m_section_headers(), m_dynamic_symbols(), - m_filespec_ap(), m_entry_point_address(), m_arch_spec() { + m_filespec_ap(), m_entry_point_address(), m_arch_spec(), + m_did_relocations(false) { if (file) m_file = *file; ::memset(&m_header, 0, sizeof(m_header)); @@ -2797,7 +2798,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. @@ -2835,7 +2837,7 @@ unsigned ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, if (ReadSectionData(rel, rel_data) && ReadSectionData(symtab, symtab_data) && ReadSectionData(debug, debug_data)) { - RelocateSection(m_symtab_ap.get(), &m_header, rel_hdr, symtab_hdr, + RelocateSection(thetab, &m_header, rel_hdr, symtab_hdr, debug_hdr, rel_data, symtab_data, debug_data, debug); } @@ -2851,8 +2853,11 @@ Symtab *ObjectFileELF::GetSymtab() { // cached copy // of our symtab, dynamic sections, etc. ObjectFile *module_obj_file = module_sp->GetObjectFile(); - if (module_obj_file && module_obj_file != this) - return module_obj_file->GetSymtab(); + if (module_obj_file && module_obj_file != this) { + Symtab *thetab = module_obj_file->GetSymtab(); + PerformRelocations(thetab); + return thetab; + } if (m_symtab_ap.get() == NULL) { SectionList *section_list = module_sp->GetSectionList(); @@ -2930,6 +2935,14 @@ Symtab *ObjectFileELF::GetSymtab() { m_symtab_ap->CalculateSymbolSizes(); } + PerformRelocations(m_symtab_ap.get()); + return m_symtab_ap.get(); +} + +void ObjectFileELF::PerformRelocations(lldb_private::Symtab *thetab) +{ + if (m_did_relocations) + return; for (SectionHeaderCollIter I = m_section_headers.begin(); I != m_section_headers.end(); ++I) { if (I->sh_type == SHT_RELA || I->sh_type == SHT_REL) { @@ -2939,12 +2952,12 @@ Symtab *ObjectFileELF::GetSymtab() { strstr(section_name, ".rel.debug")) { const ELFSectionHeader &reloc_header = *I; user_id_t reloc_id = SectionIndex(I); - RelocateDebugSections(&reloc_header, reloc_id); + RelocateDebugSections(&reloc_header, reloc_id, thetab); } } } } - return m_symtab_ap.get(); + m_did_relocations = true; } void ObjectFileELF::ParseUnwindSymbols(Symtab *symbol_table, diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 6d8717b..fa72e09 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -218,6 +218,8 @@ private: /// The address class for each symbol in the elf file FileAddressToAddressClassMap m_address_class_map; + bool m_did_relocations; + /// Returns a 1 based index of the given section header. size_t SectionIndex(const SectionHeaderCollIter &I); @@ -294,9 +296,12 @@ private: void ParseUnwindSymbols(lldb_private::Symtab *symbol_table, lldb_private::DWARFCallFrameInfo *eh_frame); + void PerformRelocations(lldb_private::Symtab *thetab); + /// Relocates debug sections unsigned RelocateDebugSections(const elf::ELFSectionHeader *rel_hdr, - lldb::user_id_t rel_id); + lldb::user_id_t rel_id, + lldb_private::Symtab *thetab); unsigned RelocateSection(lldb_private::Symtab *symtab, const elf::ELFHeader *hdr, -- 2.7.5
From 1fa65662aa9abf82652a257f08a5ba422ddd3b53 Mon Sep 17 00:00:00 2001 From: Brian Koropoff <brian.korop...@isilon.com> Date: Wed, 30 Aug 2017 18:50:07 -0700 Subject: [PATCH 3/4] SymbolFile:DWARF: force application of relocations Since ObjectFileELF performs relocations when lazily computing the symbol table, force it to do so before attempting to read debug info. --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 4642c2e..fb00e3e 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -632,6 +632,8 @@ const DWARFDataExtractor &SymbolFileDWARF::get_debug_frame_data() { } const DWARFDataExtractor &SymbolFileDWARF::get_debug_info_data() { + // Force application of relocations + (void) m_obj_file->GetSymtab(); return GetCachedSectionData(eSectionTypeDWARFDebugInfo, m_data_debug_info); } -- 2.7.5
From 47e4817b7be36c4ebdf7b3520260be81ca37b865 Mon Sep 17 00:00:00 2001 From: Brian Koropoff <brian.korop...@isilon.com> Date: Thu, 31 Aug 2017 16:43:03 -0700 Subject: [PATCH 4/4] ObjectFile:ELF: create synthetic file addresses for reloc objects Relocatable objects can have 0 in the section address fields, causing address-to-symbol resolution to return incorrect results because all sections have the same "file address" according to lldb. Detect this case and generate synthetic file addresses instead. --- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 47 ++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index f6ea67e..87d7fdf 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1815,10 +1815,38 @@ lldb::user_id_t ObjectFileELF::GetSectionIndexByName(const char *name) { return 0; } +static bool IsDebugSection(SectionType Type) { + switch (Type) { + case eSectionTypeDWARFDebugAbbrev: + case eSectionTypeDWARFDebugAddr: + case eSectionTypeDWARFDebugAranges: + case eSectionTypeDWARFDebugFrame: + case eSectionTypeDWARFDebugInfo: + case eSectionTypeDWARFDebugLine: + case eSectionTypeDWARFDebugLoc: + case eSectionTypeDWARFDebugMacInfo: + case eSectionTypeDWARFDebugMacro: + case eSectionTypeDWARFDebugPubNames: + case eSectionTypeDWARFDebugPubTypes: + case eSectionTypeDWARFDebugRanges: + case eSectionTypeDWARFDebugStr: + case eSectionTypeDWARFDebugStrOffsets: + return true; + default: + return false; + } +} + 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; @@ -1996,6 +2024,23 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { : LLDB_INVALID_ADDRESS; elf::elf_xword log2align = (header.sh_addralign == 0) ? 0 : llvm::Log2_64(header.sh_addralign); + + uint64_t addr = header.sh_addr; + + bool is_loaded = + (header.sh_type == SHT_NOBITS || header.sh_type == SHT_PROGBITS || + header.sh_type == SHT_X86_64_UNWIND) && + !IsDebugSection(sect_type); + + // Sections expected to be loaded at runtime from a relocatable + // object might need synthetic file addresses + if (synthaddrs && is_loaded && addr == 0) { + 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 @@ -2003,7 +2048,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. -- 2.7.5
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits