Index: ELF/GdbIndex.h =================================================================== --- ELF/GdbIndex.h +++ ELF/GdbIndex.h @@ -19,14 +19,6 @@ class InputSection; -// Struct represents single entry of address area of gdb index. -struct AddressEntry { - InputSectionBase *Section; - uint64_t LowAddress; - uint64_t HighAddress; - size_t CuIndex; -}; - // Element of GdbHashTab hash table. struct GdbSymbol { GdbSymbol(uint32_t Hash, size_t Offset) Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -99,6 +99,10 @@ static uint8_t *OpdBuf; static PhdrEntry *TlsPhdr; static OutputSection *DebugInfo; + static OutputSection *DebugAbbrev; + static OutputSection *DebugGnuPubNames; + static OutputSection *DebugGnuPubTypes; + static OutputSection *DebugRanges; static OutputSection *ElfHeader; static OutputSection *ProgramHeaders; static OutputSection *PreinitArray; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -35,6 +35,10 @@ uint8_t *Out::OpdBuf; PhdrEntry *Out::TlsPhdr; OutputSection *Out::DebugInfo; +OutputSection *Out::DebugAbbrev; +OutputSection *Out::DebugGnuPubNames; +OutputSection *Out::DebugGnuPubTypes; +OutputSection *Out::DebugRanges; OutputSection *Out::ElfHeader; OutputSection *Out::ProgramHeaders; OutputSection *Out::PreinitArray; Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -521,7 +521,7 @@ // The CU vector portion of the constant pool. std::vector>> CuVectors; - std::vector AddressArea; + uint64_t AddressRangesAmount = 0; private: void readDwarf(InputSection *Sec); Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -1697,30 +1697,12 @@ return Ret; } -static InputSectionBase *findSection(ArrayRef Arr, - uint64_t Offset) { - for (InputSectionBase *S : Arr) - if (S && S != &InputSection::Discarded) - if (Offset >= S->getOffsetInFile() && - Offset < S->getOffsetInFile() + S->getSize()) - return S; - return nullptr; -} - -static std::vector -readAddressArea(DWARFContext &Dwarf, InputSection *Sec, size_t CurrentCU) { - std::vector Ret; - +static std::vector readRanges(DWARFContext &Dwarf) { + std::vector Ret; for (std::unique_ptr &CU : Dwarf.compile_units()) { DWARFAddressRangesVector Ranges; CU->collectAddressRanges(Ranges); - - ArrayRef Sections = Sec->File->getSections(); - for (std::pair &R : Ranges) - if (InputSectionBase *S = findSection(Sections, R.first)) - Ret.push_back({S, R.first - S->getOffsetInFile(), - R.second - S->getOffsetInFile(), CurrentCU}); - ++CurrentCU; + Ret.push_back(std::move(Ranges)); } return Ret; } @@ -1740,37 +1722,109 @@ return Ret; } -class ObjInfoTy : public llvm::LoadedObjectInfo { - uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override { - auto &S = static_cast(Sec); - if (S.getFlags() & ELF::SHF_ALLOC) - return S.getOffset(); +// Returns amount of address ranges in a DIE. +static uint64_t getDieRangesCount(DWARFContext &Dwarf, DWARFCompileUnit *CU, + const DWARFDie &Die) { + if (!Die || Die.isNULL()) return 0; + // DIE may have DW_AT_low_pc and DW_AT_high_pc pair of attributes for a single + // contiguous range of addresses. + if (Die.find(DW_AT_low_pc) && Die.find(DW_AT_high_pc)) + return 1; + // Range list is indecated by DW_AT_ranges attribute. Whose value is + // represented as an offset from the beginning of the .debug_ranges section to + // the beginning of the range list. + // The end of any given range list is marked by an end of list entry, which + // consists of a 0 for the beginning address offset and a 0 for the ending + // address offset. We assume here that whole section data starting from offset + // is a range, terminated with null entry. + if (Optional Offset = toSectionOffset(Die.find(DW_AT_ranges))) { + uint8_t AddrSize = CU->getAddressByteSize(); + return (Dwarf.getRangeSection().size() - *Offset) / (2 * AddrSize) - 1; + } + return 0; +} + +// Returns amount of address ranges for all compilation units in a DWARF +// context. +static uint64_t getAddressRangesCount(DWARFContext &Dwarf) { + uint64_t Ret = 0; + for (std::unique_ptr &CU : Dwarf.compile_units()) + Ret += getDieRangesCount(Dwarf, CU.get(), CU->getUnitDIE()); + return Ret; +} + +// Returns vector of debug sections in a file. Vector contains +// only sections that are required for building .gdb_index section. +static std::vector getDebugSections(InputFile *File) { + std::vector Ret; + for (InputSectionBase *Sec : File->getSections()) { + if (!Sec || Sec == &InputSection::Discarded) + continue; + if (StringSwitch(Sec->Name) + .Case(".debug_info", true) + .Case(".debug_abbrev", true) + .Case(".debug_gnu_pubnames", true) + .Case(".debug_gnu_pubtypes", true) + .Case(".debug_ranges", true) + .Default(false)) + Ret.push_back(Sec); } + return Ret; +} - std::unique_ptr clone() const override { return {}; } -}; +// Given the array of debug sections for a file, created the +// DWARF context for parsing and futher generating of .gdb_index. +static DWARFContextInMemory * +createDwarfContext(ArrayRef V) { + StringMap> *Map = + make>>(); + + for (InputSectionBase *Sec : V) { + StringRef Name = Sec->Name.drop_front(); + StringRef Data((const char *)Sec->Data.begin(), Sec->getSize()); + Map->insert({Name, llvm::MemoryBuffer::getMemBuffer(Data, Name, false)}); + } + return make(*Map, Config->Wordsize, Config->IsLE); +} + +// Function uses relocated output sections content to create DWARF parser +// instance. We use it to retrive the correct values for address ranges. +static DWARFContextInMemory *createRelocatedDwarfContext() { + StringMap> *Map = + make>>(); + + OutputSection *Sections[] = {Out::DebugInfo, Out::DebugAbbrev, + Out::DebugGnuPubNames, Out::DebugGnuPubTypes, + Out::DebugRanges}; + for (OutputSection *Sec : Sections) { + if (!Sec) + continue; -void GdbIndexSection::readDwarf(InputSection *Sec) { - Expected> Obj = - object::ObjectFile::createObjectFile(Sec->File->MB); - if (!Obj) { - error(toString(Sec->File) + ": error creating DWARF context"); - return; + StringRef Key = Sec->Name.drop_front(); + std::unique_ptr Buf = llvm::MemoryBuffer::getMemBuffer( + {(const char *)Sec->Loc, Sec->Size}, Key, false); + Map->insert({Key, std::move(Buf)}); } + return make(*Map, Config->Wordsize, Config->IsLE); +} - ObjInfoTy ObjInfo; - DWARFContextInMemory Dwarf(*Obj.get(), &ObjInfo); +void GdbIndexSection::readDwarf(InputSection *DebugInfo) { + DWARFContextInMemory *Dwarf = + createDwarfContext(getDebugSections(DebugInfo->File)); size_t CuId = CompilationUnits.size(); - for (std::pair &P : readCuList(Dwarf, Sec)) + for (std::pair &P : readCuList(*Dwarf, DebugInfo)) CompilationUnits.push_back(P); - for (AddressEntry &Ent : readAddressArea(Dwarf, Sec, CuId)) - AddressArea.push_back(Ent); + // We do not scan and remember address ranges here because .debug_ranges + // section is not relocated yet. We calculate the amount of ranges only here. + // That gives us enough information to calculate .gdb_index section size + // early. We will parse ranges later, after performing the relocations. + AddressRangesAmount += getAddressRangesCount(*Dwarf); std::vector> NamesAndTypes = - readPubNamesAndTypes(Dwarf, Config->IsLE); + readPubNamesAndTypes(*Dwarf, Config->IsLE); for (std::pair &Pair : NamesAndTypes) { uint32_t Hash = hash(Pair.first); @@ -1804,7 +1858,7 @@ // GdbIndex header consist from version fields // and 5 more fields with different kinds of offsets. CuTypesOffset = CuListOffset + CompilationUnits.size() * CompilationUnitSize; - SymTabOffset = CuTypesOffset + AddressArea.size() * AddressEntrySize; + SymTabOffset = CuTypesOffset + AddressRangesAmount * AddressEntrySize; ConstantPoolOffset = SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize; @@ -1839,13 +1893,21 @@ Buf += 16; } - // Write the address area. - for (AddressEntry &E : AddressArea) { - uint64_t BaseAddr = E.Section->OutSec->Addr + E.Section->getOffset(0); - write64le(Buf, BaseAddr + E.LowAddress); - write64le(Buf + 8, BaseAddr + E.HighAddress); - write32le(Buf + 16, E.CuIndex); - Buf += 20; + // Write the address area. Here we use relocated data written + // to output file. We feed this data to DWARF parser, it + // uses relocated .debug_ranges section content to + // obtain correct (relocated) address ranges. + size_t CuID = 0; + DWARFContextInMemory *Dwarf = createRelocatedDwarfContext(); + std::vector V = readRanges(*Dwarf); + for (DWARFAddressRangesVector &Ranges : V) { + for (std::pair &R : Ranges) { + write64le(Buf, R.first); + write64le(Buf + 8, R.second); + write32le(Buf + 16, CuID); + Buf += 20; + } + ++CuID; } // Write the symbol table. Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1066,6 +1066,11 @@ // Create output section objects and add them to OutputSections. template void Writer::finalizeSections() { Out::DebugInfo = findSection(".debug_info"); + Out::DebugAbbrev = findSection(".debug_abbrev"); + Out::DebugGnuPubNames = findSection(".debug_gnu_pubnames"); + Out::DebugGnuPubTypes = findSection(".debug_gnu_pubtypes"); + Out::DebugRanges = findSection(".debug_ranges"); + Out::PreinitArray = findSection(".preinit_array"); Out::InitArray = findSection(".init_array"); Out::FiniArray = findSection(".fini_array"); Index: test/ELF/Inputs/gdb-index-ranges.s =================================================================== --- test/ELF/Inputs/gdb-index-ranges.s +++ test/ELF/Inputs/gdb-index-ranges.s @@ -0,0 +1,83 @@ +## Code below is a simplified output from next invocation: +## clang temp.cpp -ffunction-sections -gsplit-dwarf -S -o out.s +## +## Where temp.cpp is: +## void ccc() { } +## float ddd() { return 0.0f; } +## + +.text +.section .text._Z3cccv,"ax",@progbits +.globl _Z3cccv +.type _Z3cccv,@function +_Z3cccv: +.Lfunc_begin0: +nop +.Lfunc_end0: + +.section .text._Z3dddv,"ax",@progbits +.globl _Z3dddv +.type _Z3dddv,@function +_Z3dddv: +.Lfunc_begin1: +nop +.Lfunc_end1: + + +.section .debug_str,"MS",@progbits,1 +.Lskel_string0: + .asciz "1.dwo" +.Lskel_string1: + .asciz "testcase2" + +.section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .ascii "\260B" # DW_AT_GNU_dwo_name + .byte 14 # DW_FORM_strp + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .ascii "\261B" # DW_AT_GNU_dwo_id + .byte 7 # DW_FORM_data8 + .ascii "\263B" # DW_AT_GNU_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + +.section .debug_info,"",@progbits +.Lcu_begin0: + .long 44 # Length of Unit + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x25 DW_TAG_compile_unit + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Lskel_string0 # DW_AT_GNU_dwo_name + .long .Lskel_string1 # DW_AT_comp_dir + .quad -943190174132613613 # DW_AT_GNU_dwo_id + .long .debug_addr # DW_AT_GNU_addr_base + .quad 0 # DW_AT_low_pc + .long .Ldebug_ranges0 # DW_AT_ranges + +.section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad .Lfunc_begin0 + .quad .Lfunc_end0 + .quad .Lfunc_begin1 + .quad .Lfunc_end1 + .quad 0 + .quad 0 + +.section .debug_addr,"",@progbits + .quad .Lfunc_begin0 + .quad .Lfunc_begin1 + +.Lline_table_start0: Index: test/ELF/gdb-index-ranges.s =================================================================== --- test/ELF/gdb-index-ranges.s +++ test/ELF/gdb-index-ranges.s @@ -0,0 +1,110 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gdb-index-ranges.s -o %t2.o + +# RUN: ld.lld --gdb-index %t1.o %t2.o -o %t +# RUN: llvm-dwarfdump -debug-dump=gdb_index %t | FileCheck %s +# RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=DISASM + +# CHECK: CU list offset = 0x18, has 2 entries: +# CHECK-NEXT: 0: Offset = 0x0, Length = 0x30 +# CHECK-NEXT: 1: Offset = 0x30, Length = 0x30 +# CHECK: Address area offset = 0x38, has 4 entries: +# CHECK-NEXT: Low address = 0x201000, High address = 0x201001, CU index = 0 +# CHECK-NEXT: Low address = 0x201001, High address = 0x201002, CU index = 0 +# CHECK-NEXT: Low address = 0x201004, High address = 0x201005, CU index = 1 +# CHECK-NEXT: Low address = 0x201005, High address = 0x201006, CU index = 1 + +# DISASM: Disassembly of section .text: +# DISASM-NEXT: _Z3aaav: +# DISASM-NEXT: 201000 +# DISASM: _Z3bbbv: +# DISASM-NEXT: 201001 +# DISASM: _Z3cccv: +# DISASM-NEXT: 201004 +# DISASM: _Z3dddv: +# DISASM-NEXT: 201005 + +## Code below is a simplified output from next invocation: +## clang temp.cpp -ffunction-sections -gsplit-dwarf -S -o out.s +## +## Where temp.cpp is: +## void aaa() { } +## float bbb() { return 0.0f; } +## + +.text +.section .text._Z3aaav,"ax",@progbits +.globl _Z3aaav +.type _Z3aaav,@function +_Z3aaav: +.Lfunc_begin0: +nop +.Lfunc_end0: + +.section .text._Z3bbbv,"ax",@progbits +.globl _Z3bbbv +.type _Z3bbbv,@function +_Z3bbbv: +.Lfunc_begin1: +nop +.Lfunc_end1: + + +.section .debug_str,"MS",@progbits,1 +.Lskel_string0: + .asciz "1.dwo" +.Lskel_string1: + .asciz "testcase" + +.section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .ascii "\260B" # DW_AT_GNU_dwo_name + .byte 14 # DW_FORM_strp + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .ascii "\261B" # DW_AT_GNU_dwo_id + .byte 7 # DW_FORM_data8 + .ascii "\263B" # DW_AT_GNU_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + +.section .debug_info,"",@progbits +.Lcu_begin0: + .long 44 # Length of Unit + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x25 DW_TAG_compile_unit + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Lskel_string0 # DW_AT_GNU_dwo_name + .long .Lskel_string1 # DW_AT_comp_dir + .quad -943190174132613613 # DW_AT_GNU_dwo_id + .long .debug_addr # DW_AT_GNU_addr_base + .quad 0 # DW_AT_low_pc + .long .Ldebug_ranges0 # DW_AT_ranges + +.section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad .Lfunc_begin0 + .quad .Lfunc_end0 + .quad .Lfunc_begin1 + .quad .Lfunc_end1 + .quad 0 + .quad 0 + +.section .debug_addr,"",@progbits + .quad .Lfunc_begin0 + .quad .Lfunc_begin1 + +.Lline_table_start0: