diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h @@ -107,6 +107,9 @@ uint64_t GetAttributeValueAsUnsigned(const dw_attr_t attr, uint64_t fail_value) const; + llvm::Optional + GetAttributeValueAsOptionalUnsigned(const dw_attr_t attr) const; + uint64_t GetAttributeValueAsAddress(const dw_attr_t attr, uint64_t fail_value) const; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp @@ -53,6 +53,13 @@ return fail_value; } +llvm::Optional +DWARFBaseDIE::GetAttributeValueAsOptionalUnsigned(const dw_attr_t attr) const { + if (IsValid()) + return m_die->GetAttributeValueAsOptionalUnsigned(GetCU(), attr); + return llvm::None; +} + uint64_t DWARFBaseDIE::GetAttributeValueAsAddress(const dw_attr_t attr, uint64_t fail_value) const { if (IsValid()) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -67,6 +67,10 @@ const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, bool check_specification_or_abstract_origin = false) const; + llvm::Optional GetAttributeValueAsOptionalUnsigned( + const DWARFUnit *cu, const dw_attr_t attr, + bool check_specification_or_abstract_origin = false) const; + DWARFDIE GetAttributeValueAsReference( const DWARFUnit *cu, const dw_attr_t attr, bool check_specification_or_abstract_origin = false) const; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -547,6 +547,17 @@ return fail_value; } +llvm::Optional +DWARFDebugInfoEntry::GetAttributeValueAsOptionalUnsigned( + const DWARFUnit *cu, const dw_attr_t attr, + bool check_specification_or_abstract_origin) const { + DWARFFormValue form_value; + if (GetAttributeValue(cu, attr, form_value, nullptr, + check_specification_or_abstract_origin)) + return form_value.Unsigned(); + return llvm::None; +} + // GetAttributeValueAsReference // // Get the value of an attribute as reference and fix up and compile unit diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -51,7 +51,7 @@ uint64_t m_type_hash = 0; uint32_t m_type_offset = 0; - uint64_t m_dwo_id = 0; + llvm::Optional m_dwo_id; DWARFUnitHeader() = default; @@ -67,7 +67,7 @@ } uint64_t GetTypeHash() const { return m_type_hash; } dw_offset_t GetTypeOffset() const { return m_type_offset; } - uint64_t GetDWOId() const { return m_dwo_id; } + llvm::Optional GetDWOId() const { return m_dwo_id; } bool IsTypeUnit() const { return m_unit_type == llvm::dwarf::DW_UT_type || m_unit_type == llvm::dwarf::DW_UT_split_type; @@ -92,7 +92,7 @@ virtual ~DWARFUnit(); bool IsDWOUnit() { return m_is_dwo; } - uint64_t GetDWOId(); + llvm::Optional GetDWOId(); void ExtractUnitDIEIfNeeded(); void ExtractUnitDIENoDwoIfNeeded(); @@ -336,7 +336,7 @@ bool m_is_dwo; bool m_has_parsed_non_skeleton_unit; /// Value of DW_AT_GNU_dwo_id (v4) or dwo_id from CU header (v5). - uint64_t m_dwo_id; + llvm::Optional m_dwo_id; private: void ParseProducerInfo(); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -77,12 +77,15 @@ m_has_parsed_non_skeleton_unit = true; + if (!m_dwo_id) + return; // No DWO file. + std::shared_ptr dwo_symbol_file = m_dwarf.GetDwoSymbolFileForCompileUnit(*this, m_first_die); if (!dwo_symbol_file) return; - DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(m_dwo_id); + DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(*m_dwo_id); if (!dwo_cu) return; // Can't fetch the compile unit from the dwo file. @@ -345,7 +348,7 @@ SetStrOffsetsBase(baseOffset); } -uint64_t DWARFUnit::GetDWOId() { +llvm::Optional DWARFUnit::GetDWOId() { ExtractUnitDIENoDwoIfNeeded(); return m_dwo_id; } @@ -467,7 +470,7 @@ GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( "Failed to find location list contribution for CU with DWO Id " "0x%" PRIx64, - this->GetDWOId()); + *GetDWOId()); return; } offset += contribution->Offset; @@ -889,8 +892,8 @@ header.m_index_entry = Index->getFromHash(header.m_type_hash); } else { Index = &context.GetAsLLVM().getCUIndex(); - if (*Index && header.m_version >= 5) - header.m_index_entry = Index->getFromHash(header.m_dwo_id); + if (*Index && header.m_version >= 5 && header.m_dwo_id) + header.m_index_entry = Index->getFromHash(*header.m_dwo_id); } if (!header.m_index_entry) header.m_index_entry = Index->getFromOffset(header.m_offset); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -148,19 +148,36 @@ const LanguageType cu_language = SymbolFileDWARF::GetLanguage(unit); - IndexUnitImpl(unit, cu_language, set); - - if (SymbolFileDWARFDwo *dwo_symbol_file = unit.GetDwoSymbolFile()) { - // Type units in a dwp file are indexed separately, so we just need to - // process the split unit here. However, if the split unit is in a dwo file, - // then we need to process type units here. - if (dwo_symbol_file == dwp) { - IndexUnitImpl(unit.GetNonSkeletonUnit(), cu_language, set); - } else { - DWARFDebugInfo &dwo_info = dwo_symbol_file->DebugInfo(); - for (size_t i = 0; i < dwo_info.GetNumUnits(); ++i) - IndexUnitImpl(*dwo_info.GetUnitAtIndex(i), cu_language, set); + // First check if the unit has a DWO ID. If it does then we only want to index + // the .dwo file or nothing at all. If we have a compile unit where we can't + // locate the .dwo/.dwp file we don't want to index anything from the skeleton + // compile unit because it is usally has no children unless + // -fsplit-dwarf-inlining was used at compile time. This option will add a + // copy of all DW_TAG_subprogram and any contained DW_TAG_inline_subroutine + // DIEs so that symbolication will still work in the absence of the .dwo/.dwp + // file, but the functions have no return types and all arguments and locals + // have been removed. So we don't want to index any of these hacked up + // function types. Types can still exist in the skeleton compile unit DWARF + // though as some functions have template parameter types and other things + // that cause extra copies of types to be included, but we should find these + // types in the .dwo file only as methods could have return types removed and + // we don't have to index incomplete types from the skeletone compile unit. + if (unit.GetDWOId()) { + if (SymbolFileDWARFDwo *dwo_symbol_file = unit.GetDwoSymbolFile()) { + // Type units in a dwp file are indexed separately, so we just need to + // process the split unit here. However, if the split unit is in a dwo file, + // then we need to process type units here. + if (dwo_symbol_file == dwp) { + IndexUnitImpl(unit.GetNonSkeletonUnit(), cu_language, set); + } else { + DWARFDebugInfo &dwo_info = dwo_symbol_file->DebugInfo(); + for (size_t i = 0; i < dwo_info.GetNumUnits(); ++i) + IndexUnitImpl(*dwo_info.GetUnitAtIndex(i), cu_language, set); + } } + } else { + // We either have a normal compile unit which we want to index. + IndexUnitImpl(unit, cu_language, set); } } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1701,14 +1701,13 @@ } /// Return the DW_AT_(GNU_)dwo_id. -/// FIXME: Technically 0 is a valid hash. -static uint64_t GetDWOId(DWARFCompileUnit &dwarf_cu, +static llvm::Optional GetDWOId(DWARFCompileUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die) { - uint64_t dwo_id = - cu_die.GetAttributeValueAsUnsigned(&dwarf_cu, DW_AT_GNU_dwo_id, 0); - if (!dwo_id) - dwo_id = cu_die.GetAttributeValueAsUnsigned(&dwarf_cu, DW_AT_dwo_id, 0); - return dwo_id; + llvm::Optional dwo_id = + cu_die.GetAttributeValueAsOptionalUnsigned(&dwarf_cu, DW_AT_GNU_dwo_id); + if (dwo_id) + return dwo_id; + return cu_die.GetAttributeValueAsOptionalUnsigned(&dwarf_cu, DW_AT_dwo_id); } llvm::Optional SymbolFileDWARF::GetDWOId() { @@ -1716,8 +1715,7 @@ if (auto comp_unit = GetCompileUnitAtIndex(0)) if (DWARFCompileUnit *cu = GetDWARFCompileUnit(comp_unit.get())) if (DWARFDebugInfoEntry *cu_die = cu->DIE().GetDIE()) - if (uint64_t dwo_id = ::GetDWOId(*cu, *cu_die)) - return dwo_id; + return ::GetDWOId(*cu, *cu_die); } return {}; } @@ -1867,7 +1865,7 @@ // Verify the DWO hash. // FIXME: Technically "0" is a valid hash. - uint64_t dwo_id = ::GetDWOId(*dwarf_cu, *die.GetDIE()); + llvm::Optional dwo_id = ::GetDWOId(*dwarf_cu, *die.GetDIE()); if (!dwo_id) continue; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -49,7 +49,8 @@ DWARFCompileUnit *cu = FindSingleCompileUnit(); if (!cu) return nullptr; - if (hash != cu->GetDWOId()) + llvm::Optional dwo_id = cu->GetDWOId(); + if (!dwo_id || hash != *dwo_id) return nullptr; return cu; } diff --git a/lldb/test/API/functionalities/dwo/TestZeroDwoId.py b/lldb/test/API/functionalities/dwo/TestZeroDwoId.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/dwo/TestZeroDwoId.py @@ -0,0 +1,49 @@ +""" +Test things related to the fission debug information style where the main object +file contains a skeleton compile unit and the main debug info is in .dwo files. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import os + +class ExecTestCase(TestBase): + + NO_DEBUG_INFO_TESTCASE = True + + def test_zero_dwo_id (self): + ''' + Test that we can load a .o file that has a skeleton compile unit + with a DWO ID of zero. We do this by hacking up the yaml to emit + zero as a DWO ID is both the .o file and .dwo file. Then we make + sure we can resolve something in the debug information to verify + that we were able to load the .dwo file corrrectly since that is + the only place that has this information. + ''' + src_dir = self.getSourceDir() + dwo_yaml_path = os.path.join(src_dir, "main.dwo.yaml") + obj_yaml_path = os.path.join(src_dir, "main.o.yaml") + dwo_path = self.getBuildArtifact("main.dwo") + obj_path = self.getBuildArtifact("main.o") + self.yaml2obj(dwo_yaml_path, dwo_path) + self.yaml2obj(obj_yaml_path, obj_path) + + # We need the current working directory to be set to the build directory + os.chdir(self.getBuildDir()) + # Create a target with the object file we just created from YAML + target = self.dbg.CreateTarget(obj_path) + self.assertTrue(target, VALID_TARGET) + + # Set a breakpoint by file and line, this doesn't require anything from + # the .dwo file. + bp = target.BreakpointCreateByLocation('main.cpp', 6) + self.assertTrue(bp.GetNumLocations() == 1) + bp_loc = bp.GetLocationAtIndex(0) + self.assertTrue(bp_loc.IsValid()) + + # We will use the address of the location to resolve the function "main" + # to make sure we were able to open the .dwo file since this is the only + # place that contains debug info for the function. + self.assertTrue(bp_loc.GetAddress().GetFunction().IsValid()) diff --git a/lldb/test/API/functionalities/dwo/main.dwo.yaml b/lldb/test/API/functionalities/dwo/main.dwo.yaml new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/dwo/main.dwo.yaml @@ -0,0 +1,37 @@ +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + SectionHeaderStringTable: .strtab +Sections: + - Name: .debug_str.dwo + Type: SHT_PROGBITS + Flags: [ SHF_EXCLUDE, SHF_MERGE, SHF_STRINGS ] + AddressAlign: 0x1 + EntSize: 0x1 + Content: 5F5A33666F6F7600666F6F00696E74006D61696E00617267630061726776006368617200636C616E672076657273696F6E2031362E302E30202868747470733A2F2F6769746875622E636F6D2F6C6C766D2F6C6C766D2D70726F6A656374206138366135376130336638316233623235613238393137373732356466623337333031643838363829006D61696E2E637070006D61696E2E64776F00 + - Name: .debug_str_offsets.dwo + Type: SHT_PROGBITS + Flags: [ SHF_EXCLUDE ] + AddressAlign: 0x1 + Content: 00000000080000000C00000010000000150000001A0000001F000000240000008900000092000000 + - Name: .debug_info.dwo + Type: SHT_PROGBITS + Flags: [ SHF_EXCLUDE ] + AddressAlign: 0x1 + Content: 630000000400000000000801072100080900000000000000000200080000000156000101014F00000003012100000001560301054F000000040291780401054F000000040291700501055300000000050205040658000000065D00000007620000000506060100 + - Name: .debug_abbrev.dwo + Type: SHT_PROGBITS + Flags: [ SHF_EXCLUDE ] + AddressAlign: 0x1 + Content: 01110125823E130503823EB042823EB142070000022E0011813E120640186E823E03823E3A0B3B0B49133F190000032E0111813E1206401803823E3A0B3B0B49133F190000040500021803823E3A0B3B0B4913000005240003823E3E0B0B0B0000060F00491300000726004913000000 + - Type: SectionHeaderTable + Sections: + - Name: .strtab + - Name: .debug_str.dwo + - Name: .debug_str_offsets.dwo + - Name: .debug_info.dwo + - Name: .debug_abbrev.dwo +... diff --git a/lldb/test/API/functionalities/dwo/main.o.yaml b/lldb/test/API/functionalities/dwo/main.o.yaml new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/dwo/main.o.yaml @@ -0,0 +1,212 @@ +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + SectionHeaderStringTable: .strtab +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x10 + Content: 554889E531C05DC30F1F840000000000554889E54883EC10C745FC00000000897DF8488975F0E8000000004883C4105DC3 + - Name: .debug_abbrev + Type: SHT_PROGBITS + AddressAlign: 0x1 + Content: 01110010171B0EB44219B0420EB1420711011206B34217000000 + - Name: .debug_info + Type: SHT_PROGBITS + AddressAlign: 0x1 + Content: 2C0000000400000000000801000000000000000000000000000000000000000000000000000000003100000000000000 + - Name: .debug_addr + Type: SHT_PROGBITS + AddressAlign: 0x1 + Content: '00000000000000000000000000000000' + - Name: .debug_gnu_pubnames + Type: SHT_PROGBITS + AddressAlign: 0x1 + Content: 21000000020000000000300000001900000030666F6F0029000000306D61696E0000000000 + - Name: .debug_gnu_pubtypes + Type: SHT_PROGBITS + AddressAlign: 0x1 + Content: 21000000020000000000300000004F00000090696E74006200000090636861720000000000 + - Name: .comment + Type: SHT_PROGBITS + Flags: [ SHF_MERGE, SHF_STRINGS ] + AddressAlign: 0x1 + EntSize: 0x1 + Content: 00636C616E672076657273696F6E2031362E302E30202868747470733A2F2F6769746875622E636F6D2F6C6C766D2F6C6C766D2D70726F6A65637420613836613537613033663831623362323561323839313737373235646662333733303164383836382900 + - Name: .note.GNU-stack + Type: SHT_PROGBITS + AddressAlign: 0x1 + - Name: .eh_frame + Type: SHT_X86_64_UNWIND + Flags: [ SHF_ALLOC ] + AddressAlign: 0x8 + Content: 1400000000000000017A5200017810011B0C0708900100001C0000001C000000000000000800000000410E108602430D06430C07080000001C0000003C000000000000002100000000410E108602430D065C0C0708000000 + - Name: .debug_line + Type: SHT_PROGBITS + AddressAlign: 0x1 + Content: 47000000040020000000010101FB0E0D000101010100000001000001006D61696E2E637070000000000000090200000000000000000105030A4B0500BD050A0A0859050306580206000101 + - Name: .rela.text + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .text + Relocations: + - Offset: 0x27 + Symbol: _Z3foov + Type: R_X86_64_PLT32 + Addend: -4 + - Name: .rela.debug_info + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .debug_info + Relocations: + - Offset: 0x6 + Symbol: .debug_abbrev + Type: R_X86_64_32 + - Offset: 0xC + Symbol: .debug_line + Type: R_X86_64_32 + - Offset: 0x10 + Symbol: .debug_str + Type: R_X86_64_32 + - Offset: 0x14 + Symbol: .debug_str + Type: R_X86_64_32 + Addend: 58 + - Offset: 0x20 + Symbol: .text + Type: R_X86_64_64 + - Offset: 0x2C + Symbol: .debug_addr + Type: R_X86_64_32 + - Name: .rela.debug_addr + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .debug_addr + Relocations: + - Symbol: .text + Type: R_X86_64_64 + - Offset: 0x8 + Symbol: .text + Type: R_X86_64_64 + Addend: 16 + - Name: .rela.debug_gnu_pubnames + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .debug_gnu_pubnames + Relocations: + - Offset: 0x6 + Symbol: .debug_info + Type: R_X86_64_32 + - Name: .rela.debug_gnu_pubtypes + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .debug_gnu_pubtypes + Relocations: + - Offset: 0x6 + Symbol: .debug_info + Type: R_X86_64_32 + - Name: .rela.eh_frame + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .eh_frame + Relocations: + - Offset: 0x20 + Symbol: .text + Type: R_X86_64_PC32 + - Offset: 0x40 + Symbol: .text + Type: R_X86_64_PC32 + Addend: 16 + - Name: .rela.debug_line + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .debug_line + Relocations: + - Offset: 0x2D + Symbol: .text + Type: R_X86_64_64 + - Name: .llvm_addrsig + Type: SHT_LLVM_ADDRSIG + Flags: [ SHF_EXCLUDE ] + Link: .symtab + AddressAlign: 0x1 + Symbols: [ _Z3foov ] + - Type: SectionHeaderTable + Sections: + - Name: .strtab + - Name: .text + - Name: .rela.text + - Name: .debug_abbrev + - Name: .debug_info + - Name: .rela.debug_info + - Name: .debug_str + - Name: .debug_addr + - Name: .rela.debug_addr + - Name: .debug_gnu_pubnames + - Name: .rela.debug_gnu_pubnames + - Name: .debug_gnu_pubtypes + - Name: .rela.debug_gnu_pubtypes + - Name: .comment + - Name: .note.GNU-stack + - Name: .eh_frame + - Name: .rela.eh_frame + - Name: .debug_line + - Name: .rela.debug_line + - Name: .llvm_addrsig + - Name: .symtab +Symbols: + - Name: main.cpp + Type: STT_FILE + Index: SHN_ABS + - Name: .text + Type: STT_SECTION + Section: .text + - Name: .debug_abbrev + Type: STT_SECTION + Section: .debug_abbrev + - Name: .debug_info + Type: STT_SECTION + Section: .debug_info + - Name: .debug_str + Type: STT_SECTION + Section: .debug_str + - Name: .debug_addr + Type: STT_SECTION + Section: .debug_addr + - Name: .debug_line + Type: STT_SECTION + Section: .debug_line + - Name: _Z3foov + Type: STT_FUNC + Section: .text + Binding: STB_GLOBAL + Size: 0x8 + - Name: main + Type: STT_FUNC + Section: .text + Binding: STB_GLOBAL + Value: 0x10 + Size: 0x21 +DWARF: + debug_str: + - '/Users/gclayton/Documents/objfiles/fission/split-inlining' + - main.dwo +...