Index: lld/trunk/ELF/GdbIndex.h =================================================================== --- lld/trunk/ELF/GdbIndex.h +++ lld/trunk/ELF/GdbIndex.h @@ -12,15 +12,48 @@ #include "InputFiles.h" #include "llvm/Object/ELF.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" namespace lld { namespace elf { template <class ELFT> class InputSection; -template <class ELFT> -std::vector<std::pair<typename ELFT::uint, typename ELFT::uint>> -readCuList(InputSection<ELFT> *Sec); +// Struct represents single entry of address area of gdb index. +template <class ELFT> struct AddressEntry { + InputSectionBase<ELFT> *Section; + uint64_t LowAddress; + uint64_t HighAddress; + uint32_t CuIndex; +}; + +// GdbIndexBuilder is a helper class used for extracting data required +// for building .gdb_index section from objects. +template <class ELFT> class GdbIndexBuilder : public LoadedObjectInfo { + typedef typename ELFT::uint uintX_t; + + InputSection<ELFT> *DebugInfoSec; + + std::unique_ptr<llvm::DWARFContext> Dwarf; + +public: + GdbIndexBuilder(InputSection<ELFT> *DebugInfoSec); + + // Extracts the compilation units. Each first element of pair is a offset of a + // CU in the .debug_info section and second is the length of that CU. + std::vector<std::pair<uintX_t, uintX_t>> readCUList(); + + // Extracts the vector of address area entries. Accepts global index of last + // parsed CU. + std::vector<AddressEntry<ELFT>> readAddressArea(size_t CurrentCU); + +private: + // Method returns section file offset as a load addres for DWARF parser. That + // allows to find the target section index for address ranges. + uint64_t + getSectionLoadAddress(const llvm::object::SectionRef &Sec) const override; + std::unique_ptr<llvm::LoadedObjectInfo> clone() const override; +}; } // namespace elf } // namespace lld Index: lld/trunk/ELF/GdbIndex.cpp =================================================================== --- lld/trunk/ELF/GdbIndex.cpp +++ lld/trunk/ELF/GdbIndex.cpp @@ -57,34 +57,33 @@ // hashtable in according to .gdb_index format specification. // 6) Constant pool is populated at the same time as symbol table. // -// Current version of implementation has 1, 2, 3 steps. So it writes .gdb_index -// header and list of compilation units. Since we so not plan to support types -// CU list area, it is also empty and so far is "implemented". +// Current version implements steps 1-4. So it writes .gdb_index +// header, list of compilation units and address area. Since we so not plan to +// support types CU list area, it is also empty and so far is "implemented". // Other data areas are not yet implemented. //===----------------------------------------------------------------------===// #include "GdbIndex.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Object/ELFObjectFile.h" using namespace llvm; using namespace llvm::object; +using namespace lld::elf; template <class ELFT> -std::vector<std::pair<typename ELFT::uint, typename ELFT::uint>> -lld::elf::readCuList(InputSection<ELFT> *DebugInfoSec) { - typedef typename ELFT::uint uintX_t; - - std::unique_ptr<DWARFContext> Dwarf; +GdbIndexBuilder<ELFT>::GdbIndexBuilder(InputSection<ELFT> *DebugInfoSec) + : DebugInfoSec(DebugInfoSec) { if (Expected<std::unique_ptr<object::ObjectFile>> Obj = object::ObjectFile::createObjectFile(DebugInfoSec->getFile()->MB)) - Dwarf.reset(new DWARFContextInMemory(*Obj.get())); - - if (!Dwarf) { + Dwarf.reset(new DWARFContextInMemory(*Obj.get(), this)); + else error(toString(DebugInfoSec->getFile()) + ": error creating DWARF context"); - return {}; - } +} +template <class ELFT> +std::vector<std::pair<typename ELFT::uint, typename ELFT::uint>> +GdbIndexBuilder<ELFT>::readCUList() { std::vector<std::pair<uintX_t, uintX_t>> Ret; for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units()) Ret.push_back( @@ -92,11 +91,52 @@ return Ret; } -template std::vector<std::pair<uint32_t, uint32_t>> -lld::elf::readCuList<ELF32LE>(InputSection<ELF32LE> *); -template std::vector<std::pair<uint32_t, uint32_t>> -lld::elf::readCuList<ELF32BE>(InputSection<ELF32BE> *); -template std::vector<std::pair<uint64_t, uint64_t>> -lld::elf::readCuList<ELF64LE>(InputSection<ELF64LE> *); -template std::vector<std::pair<uint64_t, uint64_t>> -lld::elf::readCuList<ELF64BE>(InputSection<ELF64BE> *); +template <class ELFT> +static InputSectionBase<ELFT> * +findSection(ArrayRef<InputSectionBase<ELFT> *> Arr, uint64_t Offset) { + for (InputSectionBase<ELFT> *S : Arr) + if (S && S != &InputSection<ELFT>::Discarded) + if (Offset >= S->Offset && Offset < S->Offset + S->getSize()) + return S; + return nullptr; +} + +template <class ELFT> +std::vector<AddressEntry<ELFT>> +GdbIndexBuilder<ELFT>::readAddressArea(size_t CurrentCU) { + std::vector<AddressEntry<ELFT>> Ret; + for (const auto &CU : Dwarf->compile_units()) { + DWARFAddressRangesVector Ranges; + CU->collectAddressRanges(Ranges); + + ArrayRef<InputSectionBase<ELFT> *> Sections = + DebugInfoSec->getFile()->getSections(); + + for (std::pair<uint64_t, uint64_t> &R : Ranges) + if (InputSectionBase<ELFT> *S = findSection(Sections, R.first)) + Ret.push_back( + {S, R.first - S->Offset, R.second - S->Offset, CurrentCU}); + ++CurrentCU; + } + return Ret; +} + +template <class ELFT> +uint64_t GdbIndexBuilder<ELFT>::getSectionLoadAddress( + const object::SectionRef &Sec) const { + return static_cast<const ELFSectionRef &>(Sec).getOffset(); +} + +template <class ELFT> +std::unique_ptr<LoadedObjectInfo> GdbIndexBuilder<ELFT>::clone() const { + return {}; +} + +namespace lld { +namespace elf { +template class GdbIndexBuilder<ELF32LE>; +template class GdbIndexBuilder<ELF32BE>; +template class GdbIndexBuilder<ELF64LE>; +template class GdbIndexBuilder<ELF64BE>; +} +} Index: lld/trunk/ELF/SyntheticSections.h =================================================================== --- lld/trunk/ELF/SyntheticSections.h +++ lld/trunk/ELF/SyntheticSections.h @@ -479,17 +479,22 @@ GdbIndexSection(); void finalize() override; void writeTo(uint8_t *Buf) override; - size_t getSize() const override { return CuTypesOffset; } + size_t getSize() const override; bool empty() const override; // Pairs of [CU Offset, CU length]. std::vector<std::pair<uintX_t, uintX_t>> CompilationUnits; + std::vector<AddressEntry<ELFT>> AddressArea; + private: void parseDebugSections(); void readDwarf(InputSection<ELFT> *I); uint32_t CuTypesOffset; + uint32_t SymTabOffset; + + bool Finalized = false; }; // --eh-frame-hdr option tells linker to construct a header for all the Index: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -1460,34 +1460,51 @@ : SyntheticSection<ELFT>(0, SHT_PROGBITS, 1, ".gdb_index") {} template <class ELFT> void GdbIndexSection<ELFT>::parseDebugSections() { - std::vector<InputSection<ELFT> *> &IS = - static_cast<OutputSection<ELFT> *>(Out<ELFT>::DebugInfo)->Sections; - - for (InputSection<ELFT> *I : IS) - readDwarf(I); + for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections) + if (InputSection<ELFT> *IS = dyn_cast<InputSection<ELFT>>(S)) + if (IS->OutSec && IS->Name == ".debug_info") + readDwarf(IS); } template <class ELFT> void GdbIndexSection<ELFT>::readDwarf(InputSection<ELFT> *I) { - std::vector<std::pair<uintX_t, uintX_t>> CuList = readCuList(I); + GdbIndexBuilder<ELFT> Builder(I); + if (ErrorCount) + return; + + size_t CuId = CompilationUnits.size(); + std::vector<std::pair<uintX_t, uintX_t>> CuList = Builder.readCUList(); CompilationUnits.insert(CompilationUnits.end(), CuList.begin(), CuList.end()); + + std::vector<AddressEntry<ELFT>> AddrArea = Builder.readAddressArea(CuId); + AddressArea.insert(AddressArea.end(), AddrArea.begin(), AddrArea.end()); } template <class ELFT> void GdbIndexSection<ELFT>::finalize() { + if (Finalized) + return; + Finalized = true; + parseDebugSections(); // 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; +} + +template <class ELFT> size_t GdbIndexSection<ELFT>::getSize() const { + const_cast<GdbIndexSection<ELFT> *>(this)->finalize(); + return SymTabOffset; } template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) { - write32le(Buf, 7); // Write Version - write32le(Buf + 4, CuListOffset); // CU list offset - write32le(Buf + 8, CuTypesOffset); // Types CU list offset - write32le(Buf + 12, CuTypesOffset); // Address area offset - write32le(Buf + 16, CuTypesOffset); // Symbol table offset - write32le(Buf + 20, CuTypesOffset); // Constant pool offset + write32le(Buf, 7); // Write version. + write32le(Buf + 4, CuListOffset); // CU list offset. + write32le(Buf + 8, CuTypesOffset); // Types CU list offset. + write32le(Buf + 12, CuTypesOffset); // Address area offset. + write32le(Buf + 16, SymTabOffset); // Symbol table offset. + write32le(Buf + 20, SymTabOffset); // Constant pool offset. Buf += 24; // Write the CU list. @@ -1496,6 +1513,15 @@ write64le(Buf + 8, CU.second); Buf += 16; } + + // Write the address area. + for (AddressEntry<ELFT> &E : AddressArea) { + uintX_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; + } } template <class ELFT> bool GdbIndexSection<ELFT>::empty() const { Index: lld/trunk/test/ELF/gdb-index.s =================================================================== --- lld/trunk/test/ELF/gdb-index.s +++ lld/trunk/test/ELF/gdb-index.s @@ -31,8 +31,10 @@ # CHECK: .gnu_index contents: # CHECK-NEXT: Version = 7 # CHECK: CU list offset = 0x18, has 2 entries: -# CHECK-NEXT: 0: Offset = 0x0, Length = 0x34 -# CHECK-NEXT: 1: Offset = 0x34, Length = 0x34 -# CHECK: Address area offset = 0x38, has 0 entries: -# CHECK: Symbol table offset = 0x38, size = 0, filled slots: -# CHECK: Constant pool offset = 0x38, has 0 CU vectors: +# CHECK-NEXT: 0: Offset = 0x0, Length = 0x34 +# CHECK-NEXT: 1: Offset = 0x34, Length = 0x34 +# CHECK: Address area offset = 0x38, has 2 entries: +# CHECK-NEXT: Low address = 0x201000, High address = 0x20100b, CU index = 0 +# CHECK-NEXT: Low address = 0x20100b, High address = 0x201016, CU index = 1 +# CHECK: Symbol table offset = 0x60, size = 0, filled slots: +# CHECK: Constant pool offset = 0x60, has 0 CU vectors: