return (HeaderSize == 0) ? InX::Plt->getSize() : 0;
}
-// The hash function used for .gdb_index version 5 or above.
-static uint32_t gdbHash(StringRef Str) {
- uint32_t R = 0;
- for (uint8_t C : Str)
- R = R * 67 + tolower(C) - 113;
- return R;
-}
-
-static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf) {
- std::vector<CompilationUnitEntry> Ret;
- for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units())
- Ret.push_back({CU->getOffset(), CU->getLength() + 4});
+// The string hash function for .gdb_index.
+static uint32_t computeGdbHash(StringRef S) {
+ uint32_t H = 0;
+ for (uint8_t C : S)
+ H = H * 67 + tolower(C) - 113;
+ return H;
+}
+
+static std::vector<GdbIndexChunk::CuEntry> readCuList(DWARFContext &Dwarf) {
+ std::vector<GdbIndexChunk::CuEntry> Ret;
+ for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units())
+ Ret.push_back({Cu->getOffset(), Cu->getLength() + 4});
return Ret;
}
-static std::vector<AddressEntry> readAddressArea(DWARFContext &Dwarf,
- InputSection *Sec) {
- std::vector<AddressEntry> Ret;
+static std::vector<GdbIndexChunk::AddressEntry>
+readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
+ std::vector<GdbIndexChunk::AddressEntry> Ret;
- uint32_t CurrentCu = 0;
- for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) {
+ uint32_t CuIdx = 0;
+ for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units()) {
DWARFAddressRangesVector Ranges;
- CU->collectAddressRanges(Ranges);
+ Cu->collectAddressRanges(Ranges);
ArrayRef<InputSectionBase *> Sections = Sec->File->getSections();
for (DWARFAddressRange &R : Ranges) {
continue;
auto *IS = cast<InputSection>(S);
uint64_t Offset = IS->getOffsetInFile();
- Ret.push_back({IS, R.LowPC - Offset, R.HighPC - Offset, CurrentCu});
+ Ret.push_back({IS, R.LowPC - Offset, R.HighPC - Offset, CuIdx});
}
- ++CurrentCu;
+ ++CuIdx;
}
return Ret;
}
-static std::vector<NameTypeEntry> readPubNamesAndTypes(DWARFContext &Dwarf,
- bool IsLE) {
- StringRef Data[] = {Dwarf.getDWARFObj().getGnuPubNamesSection(),
- Dwarf.getDWARFObj().getGnuPubTypesSection()};
+static std::vector<GdbIndexChunk::NameTypeEntry>
+readPubNamesAndTypes(DWARFContext &Dwarf) {
+ StringRef Sec1 = Dwarf.getDWARFObj().getGnuPubNamesSection();
+ StringRef Sec2 = Dwarf.getDWARFObj().getGnuPubTypesSection();
- std::vector<NameTypeEntry> Ret;
- for (StringRef D : Data) {
- DWARFDebugPubTable PubTable(D, IsLE, true);
- for (const DWARFDebugPubTable::Set &Set : PubTable.getData())
+ std::vector<GdbIndexChunk::NameTypeEntry> Ret;
+ for (StringRef Sec : {Sec1, Sec2}) {
+ DWARFDebugPubTable Table(Sec, Config->IsLE, true);
+ for (const DWARFDebugPubTable::Set &Set : Table.getData())
for (const DWARFDebugPubTable::Entry &Ent : Set.Entries)
Ret.push_back({Ent.Name, Ent.Descriptor.toBits()});
}
return Ret;
}
-void GdbIndexSection::buildIndex() {
- if (Chunks.empty())
- return;
+void GdbIndexSection::fixCuIndex() {
+ uint32_t Idx = 0;
+ for (GdbIndexChunk &Chunk : Chunks) {
+ for (GdbIndexChunk::AddressEntry &Ent : Chunk.AddressAreas)
+ Ent.CuIndex += Idx;
+ Idx += Chunk.CompilationUnits.size();
+ }
+}
- 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 = gdbHash(NameType.Name);
- size_t Offset = StringPool.add(NameType.Name);
-
- bool IsNew;
- GdbSymbol *Sym;
- std::tie(IsNew, Sym) = HashTab.add(Hash, Offset);
- if (IsNew) {
- Sym->CuVectorIndex = CuVectors.size();
- CuVectors.resize(CuVectors.size() + 1);
- }
+std::vector<std::set<uint32_t>> GdbIndexSection::createCuVectors() {
+ std::vector<std::set<uint32_t>> Ret;
+ uint32_t Idx = 0;
- CuVectors[Sym->CuVectorIndex].insert(CuId | (NameType.Type << 24));
- }
+ for (GdbIndexChunk &Chunk : Chunks) {
+ for (GdbIndexChunk::NameTypeEntry &Ent : Chunk.NamesAndTypes) {
+ uint32_t Hash = computeGdbHash(Ent.Name);
+ size_t Offset = StringPool.add(Ent.Name);
- CuId += D.CompilationUnits.size();
+ GdbSymbol *&Sym = SymbolMap[Offset];
+ if (!Sym) {
+ Sym = make<GdbSymbol>(GdbSymbol{Hash, Offset, Ret.size()});
+ Ret.resize(Ret.size() + 1);
+ }
+ Ret[Sym->CuVectorIndex].insert((Ent.Type << 24) | Idx);
+ }
+ Idx += Chunk.CompilationUnits.size();
}
-}
-
-static GdbIndexChunk readDwarf(DWARFContext &Dwarf, InputSection *Sec) {
- GdbIndexChunk Ret;
- Ret.DebugInfoSec = Sec;
- Ret.CompilationUnits = readCuList(Dwarf);
- Ret.AddressArea = readAddressArea(Dwarf, Sec);
- Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE);
return Ret;
}
template <class ELFT> GdbIndexSection *elf::createGdbIndex() {
std::vector<InputSection *> Sections = getDebugInfoSections();
std::vector<GdbIndexChunk> Chunks(Sections.size());
+
parallelForEachN(0, Chunks.size(), [&](size_t I) {
- ObjFile<ELFT> *F = Sections[I]->getFile<ELFT>();
- DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(F));
- Chunks[I] = readDwarf(Dwarf, Sections[I]);
+ ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>();
+ DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File));
+
+ Chunks[I].DebugInfoSec = Sections[I];
+ Chunks[I].CompilationUnits = readCuList(Dwarf);
+ Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]);
+ Chunks[I].NamesAndTypes = readPubNamesAndTypes(Dwarf);
});
+
return make<GdbIndexSection>(std::move(Chunks));
}
static size_t getAddressAreaSize(ArrayRef<GdbIndexChunk> Arr) {
size_t Ret = 0;
for (const GdbIndexChunk &D : Arr)
- Ret += D.AddressArea.size();
+ Ret += D.AddressAreas.size();
+ return Ret;
+}
+
+std::vector<GdbSymbol *> GdbIndexSection::createGdbSymtab() {
+ uint32_t Size =
+ std::max<uint32_t>(1024, NextPowerOf2(SymbolMap.size() * 4 / 3));
+ uint32_t Mask = Size - 1;
+ std::vector<GdbSymbol *> Ret(Size);
+
+ for (auto &KV : SymbolMap) {
+ GdbSymbol *Sym = KV.second;
+ uint32_t I = Sym->NameHash & Mask;
+ uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1;
+
+ while (Ret[I])
+ I = (I + Step) & Mask;
+ Ret[I] = Sym;
+ }
return Ret;
}
GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&C)
: SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"),
StringPool(llvm::StringTableBuilder::ELF), Chunks(std::move(C)) {
- buildIndex();
- HashTab.finalizeContents();
+ fixCuIndex();
+ CuVectors = createCuVectors();
+ GdbSymtab = createGdbSymtab();
- // GdbIndex header consist from version fields
- // and 5 more fields with different kinds of offsets.
- CuTypesOffset = CuListOffset + getCuSize(Chunks) * CompilationUnitSize;
- SymTabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * AddressEntrySize;
- ConstantPoolOffset = SymTabOffset + HashTab.getCapacity() * SymTabEntrySize;
+ // Compute offsets early to know the section size.
+ // Each chunk size needs to be in sync with what we write in writeTo.
+ CuTypesOffset = CuListOffset + getCuSize(Chunks) * 16;
+ SymtabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * 20;
+ ConstantPoolOffset = SymtabOffset + GdbSymtab.size() * 8;
+ size_t Off = 0;
for (std::set<uint32_t> &CuVec : CuVectors) {
- CuVectorsOffset.push_back(CuVectorsSize);
- CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1);
+ CuVectorOffsets.push_back(Off);
+ Off += (CuVec.size() + 1) * 4;
}
- StringPoolOffset = ConstantPoolOffset + CuVectorsSize;
+ StringPoolOffset = ConstantPoolOffset + Off;
StringPool.finalizeInOrder();
}
}
void GdbIndexSection::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, SymTabOffset); // Symbol table offset
- write32le(Buf + 20, ConstantPoolOffset); // Constant pool offset
+ // Write the section header.
+ write32le(Buf, 7);
+ write32le(Buf + 4, CuListOffset);
+ write32le(Buf + 8, CuTypesOffset);
+ write32le(Buf + 12, CuTypesOffset);
+ write32le(Buf + 16, SymtabOffset);
+ write32le(Buf + 20, ConstantPoolOffset);
Buf += 24;
// Write the CU list.
for (GdbIndexChunk &D : Chunks) {
- for (CompilationUnitEntry &Cu : D.CompilationUnits) {
+ for (GdbIndexChunk::CuEntry &Cu : D.CompilationUnits) {
write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset);
write64le(Buf + 8, Cu.CuLength);
Buf += 16;
// Write the address area.
for (GdbIndexChunk &D : Chunks) {
- for (AddressEntry &E : D.AddressArea) {
+ for (GdbIndexChunk::AddressEntry &E : D.AddressAreas) {
uint64_t BaseAddr =
E.Section->getParent()->Addr + E.Section->getOffset(0);
write64le(Buf, BaseAddr + E.LowAddress);
}
// Write the symbol table.
- for (size_t I = 0; I < HashTab.getCapacity(); ++I) {
- GdbSymbol *Sym = HashTab.getSymbol(I);
+ for (GdbSymbol *Sym : GdbSymtab) {
if (Sym) {
- size_t NameOffset =
- Sym->NameOffset + StringPoolOffset - ConstantPoolOffset;
- size_t CuVectorOffset = CuVectorsOffset[Sym->CuVectorIndex];
- write32le(Buf, NameOffset);
- write32le(Buf + 4, CuVectorOffset);
+ write32le(Buf, Sym->NameOffset + StringPoolOffset - ConstantPoolOffset);
+ write32le(Buf + 4, CuVectorOffsets[Sym->CuVectorIndex]);
}
Buf += 8;
}
- // Write the CU vectors into the constant pool.
+ // Write the CU vectors.
for (std::set<uint32_t> &CuVec : CuVectors) {
write32le(Buf, CuVec.size());
Buf += 4;
}
}
+ // Write the string pool.
StringPool.write(Buf);
}