Index: lld/trunk/ELF/GdbIndex.h =================================================================== --- lld/trunk/ELF/GdbIndex.h +++ lld/trunk/ELF/GdbIndex.h @@ -24,7 +24,30 @@ InputSection *Section; uint64_t LowAddress; uint64_t HighAddress; - size_t CuIndex; + uint32_t CuIndex; +}; + +// Struct represents single entry of compilation units list area of gdb index. +// It consist of CU offset in .debug_info section and it's size. +struct CompilationUnitEntry { + uint64_t CuOffset; + uint64_t CuLength; +}; + +// Represents data about symbol and type names which are used +// to build symbol table and constant pool area of gdb index. +struct NameTypeEntry { + StringRef Name; + uint8_t Type; +}; + +// We fill one GdbIndexDataChunk for each object where scan of +// debug information performed. That information futher used +// for filling gdb index section areas. +struct GdbIndexChunk { + std::vector AddressArea; + std::vector CompilationUnits; + std::vector NamesAndTypes; }; // Element of GdbHashTab hash table. Index: lld/trunk/ELF/SyntheticSections.h =================================================================== --- lld/trunk/ELF/SyntheticSections.h +++ lld/trunk/ELF/SyntheticSections.h @@ -509,20 +509,23 @@ size_t getSize() const override; bool empty() const override; - // Pairs of [CU Offset, CU length]. - std::vector> CompilationUnits; - - llvm::StringTableBuilder StringPool; - + // Symbol table is a hash table for types and names. + // It is the area of gdb index. GdbHashTab SymbolTable; - // The CU vector portion of the constant pool. + // CU vector is a part of constant pool area of section. std::vector> CuVectors; - std::vector AddressArea; + // String pool is also a part of constant pool, it follows CU vectors. + llvm::StringTableBuilder StringPool; + + // Each chunk contains information gathered from a debug sections of single + // object and used to build different areas of gdb index. + std::vector Chunks; private: - void readDwarf(InputSection *Sec); + GdbIndexChunk readDwarf(InputSection *Sec); + void buildIndex(); uint32_t CuTypesOffset; uint32_t SymTabOffset; Index: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -1691,18 +1691,19 @@ return R; } -static std::vector> -readCuList(DWARFContext &Dwarf, InputSection *Sec) { - std::vector> Ret; +static std::vector readCuList(DWARFContext &Dwarf, + InputSection *Sec) { + std::vector Ret; for (std::unique_ptr &CU : Dwarf.compile_units()) Ret.push_back({Sec->OutSecOff + CU->getOffset(), CU->getLength() + 4}); return Ret; } -static std::vector -readAddressArea(DWARFContext &Dwarf, InputSection *Sec, size_t CurrentCU) { +static std::vector readAddressArea(DWARFContext &Dwarf, + InputSection *Sec) { std::vector Ret; + uint32_t CurrentCu = 0; for (std::unique_ptr &CU : Dwarf.compile_units()) { DWARFAddressRangesVector Ranges; CU->collectAddressRanges(Ranges); @@ -1715,19 +1716,19 @@ // Range list with zero size has no effect. if (R.LowPC == R.HighPC) continue; - Ret.push_back({cast(S), R.LowPC, R.HighPC, CurrentCU}); + Ret.push_back({cast(S), R.LowPC, R.HighPC, CurrentCu}); } - ++CurrentCU; + ++CurrentCu; } return Ret; } -static std::vector> -readPubNamesAndTypes(DWARFContext &Dwarf, bool IsLE) { +static std::vector readPubNamesAndTypes(DWARFContext &Dwarf, + bool IsLE) { StringRef Data[] = {Dwarf.getGnuPubNamesSection(), Dwarf.getGnuPubTypesSection()}; - std::vector> Ret; + std::vector Ret; for (StringRef D : Data) { DWARFDebugPubTable PubTable(D, IsLE, true); for (const DWARFDebugPubTable::Set &Set : PubTable.getData()) @@ -1737,40 +1738,77 @@ return Ret; } -void GdbIndexSection::readDwarf(InputSection *Sec) { +static std::vector getDebugInfoSections() { + std::vector Ret; + for (InputSectionBase *S : InputSections) + if (InputSection *IS = dyn_cast(S)) + if (IS->getParent() && IS->Name == ".debug_info") + Ret.push_back(IS); + return Ret; +} + +void GdbIndexSection::buildIndex() { + std::vector V = getDebugInfoSections(); + if (V.empty()) + return; + + for (InputSection *Sec : V) + Chunks.push_back(readDwarf(Sec)); + + uint32_t CuId = 0; + for (GdbIndexChunk &D : Chunks) { + for (AddressEntry &E : D.AddressArea) + E.CuIndex += CuId; + + // Populate constant pool area. + for (NameTypeEntry &NameType : D.NamesAndTypes) { + uint32_t Hash = hash(NameType.Name); + size_t Offset = StringPool.add(NameType.Name); + + bool IsNew; + GdbSymbol *Sym; + std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset); + if (IsNew) { + Sym->CuVectorIndex = CuVectors.size(); + CuVectors.push_back({}); + } + + CuVectors[Sym->CuVectorIndex].insert(CuId | (NameType.Type << 24)); + } + + CuId += D.CompilationUnits.size(); + } +} + +GdbIndexChunk GdbIndexSection::readDwarf(InputSection *Sec) { Expected> Obj = object::ObjectFile::createObjectFile(Sec->File->MB); if (!Obj) { error(toString(Sec->File) + ": error creating DWARF context"); - return; + return {}; } DWARFContextInMemory Dwarf(*Obj.get()); - size_t CuId = CompilationUnits.size(); - for (std::pair &P : readCuList(Dwarf, Sec)) - CompilationUnits.push_back(P); - - for (AddressEntry &Ent : readAddressArea(Dwarf, Sec, CuId)) - AddressArea.push_back(Ent); - - std::vector> NamesAndTypes = - readPubNamesAndTypes(Dwarf, Config->IsLE); - - for (std::pair &Pair : NamesAndTypes) { - uint32_t Hash = hash(Pair.first); - size_t Offset = StringPool.add(Pair.first); + GdbIndexChunk Ret; + Ret.CompilationUnits = readCuList(Dwarf, Sec); + Ret.AddressArea = readAddressArea(Dwarf, Sec); + Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE); + return Ret; +} - bool IsNew; - GdbSymbol *Sym; - std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset); - if (IsNew) { - Sym->CuVectorIndex = CuVectors.size(); - CuVectors.resize(CuVectors.size() + 1); - } +static size_t getCuSize(std::vector &C) { + size_t Ret = 0; + for (GdbIndexChunk &D : C) + Ret += D.CompilationUnits.size(); + return Ret; +} - CuVectors[Sym->CuVectorIndex].insert((Pair.second << 24) | (uint32_t)CuId); - } +static size_t getAddressAreaSize(std::vector &C) { + size_t Ret = 0; + for (GdbIndexChunk &D : C) + Ret += D.AddressArea.size(); + return Ret; } void GdbIndexSection::finalizeContents() { @@ -1778,17 +1816,14 @@ return; Finalized = true; - for (InputSectionBase *S : InputSections) - if (InputSection *IS = dyn_cast(S)) - if (IS->getParent() && IS->Name == ".debug_info") - readDwarf(IS); + buildIndex(); SymbolTable.finalizeContents(); // 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; + CuTypesOffset = CuListOffset + getCuSize(Chunks) * CompilationUnitSize; + SymTabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * AddressEntrySize; ConstantPoolOffset = SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize; @@ -1817,19 +1852,24 @@ Buf += 24; // Write the CU list. - for (std::pair CU : CompilationUnits) { - write64le(Buf, CU.first); - write64le(Buf + 8, CU.second); - Buf += 16; + for (GdbIndexChunk &D : Chunks) { + for (CompilationUnitEntry &Cu : D.CompilationUnits) { + write64le(Buf, Cu.CuOffset); + write64le(Buf + 8, Cu.CuLength); + Buf += 16; + } } // Write the address area. - for (AddressEntry &E : AddressArea) { - uint64_t BaseAddr = E.Section->getParent()->Addr + E.Section->getOffset(0); - write64le(Buf, BaseAddr + E.LowAddress); - write64le(Buf + 8, BaseAddr + E.HighAddress); - write32le(Buf + 16, E.CuIndex); - Buf += 20; + for (GdbIndexChunk &D : Chunks) { + for (AddressEntry &E : D.AddressArea) { + uint64_t BaseAddr = + E.Section->getParent()->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 symbol table.