[ELF] - Make implementation of .gdb index to be more natural for futher paralleling.

This patch reimplements .gdb_index in more natural way,
that makes proccess of switching to multithreaded index building to
be trivial. 

Differential revision: https://reviews.llvm.org/D33552

llvm-svn: 304927
This commit is contained in:
George Rimar 2017-06-07 16:59:11 +00:00
parent 33e5872367
commit 8666562e89
3 changed files with 125 additions and 59 deletions

View File

@ -24,7 +24,30 @@ struct AddressEntry {
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<AddressEntry> AddressArea;
std::vector<CompilationUnitEntry> CompilationUnits;
std::vector<NameTypeEntry> NamesAndTypes;
};
// Element of GdbHashTab hash table.

View File

@ -1691,18 +1691,19 @@ static uint32_t hash(StringRef Str) {
return R;
}
static std::vector<std::pair<uint64_t, uint64_t>>
readCuList(DWARFContext &Dwarf, InputSection *Sec) {
std::vector<std::pair<uint64_t, uint64_t>> Ret;
static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf,
InputSection *Sec) {
std::vector<CompilationUnitEntry> Ret;
for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units())
Ret.push_back({Sec->OutSecOff + CU->getOffset(), CU->getLength() + 4});
return Ret;
}
static std::vector<AddressEntry>
readAddressArea(DWARFContext &Dwarf, InputSection *Sec, size_t CurrentCU) {
static std::vector<AddressEntry> readAddressArea(DWARFContext &Dwarf,
InputSection *Sec) {
std::vector<AddressEntry> Ret;
uint32_t CurrentCu = 0;
for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) {
DWARFAddressRangesVector Ranges;
CU->collectAddressRanges(Ranges);
@ -1715,19 +1716,19 @@ readAddressArea(DWARFContext &Dwarf, InputSection *Sec, size_t CurrentCU) {
// Range list with zero size has no effect.
if (R.LowPC == R.HighPC)
continue;
Ret.push_back({cast<InputSection>(S), R.LowPC, R.HighPC, CurrentCU});
Ret.push_back({cast<InputSection>(S), R.LowPC, R.HighPC, CurrentCu});
}
++CurrentCU;
++CurrentCu;
}
return Ret;
}
static std::vector<std::pair<StringRef, uint8_t>>
readPubNamesAndTypes(DWARFContext &Dwarf, bool IsLE) {
static std::vector<NameTypeEntry> readPubNamesAndTypes(DWARFContext &Dwarf,
bool IsLE) {
StringRef Data[] = {Dwarf.getGnuPubNamesSection(),
Dwarf.getGnuPubTypesSection()};
std::vector<std::pair<StringRef, uint8_t>> Ret;
std::vector<NameTypeEntry> Ret;
for (StringRef D : Data) {
DWARFDebugPubTable PubTable(D, IsLE, true);
for (const DWARFDebugPubTable::Set &Set : PubTable.getData())
@ -1737,40 +1738,77 @@ readPubNamesAndTypes(DWARFContext &Dwarf, bool IsLE) {
return Ret;
}
void GdbIndexSection::readDwarf(InputSection *Sec) {
static std::vector<InputSection *> getDebugInfoSections() {
std::vector<InputSection *> Ret;
for (InputSectionBase *S : InputSections)
if (InputSection *IS = dyn_cast<InputSection>(S))
if (IS->getParent() && IS->Name == ".debug_info")
Ret.push_back(IS);
return Ret;
}
void GdbIndexSection::buildIndex() {
std::vector<InputSection *> 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<std::unique_ptr<object::ObjectFile>> 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<uint64_t, uint64_t> &P : readCuList(Dwarf, Sec))
CompilationUnits.push_back(P);
GdbIndexChunk Ret;
Ret.CompilationUnits = readCuList(Dwarf, Sec);
Ret.AddressArea = readAddressArea(Dwarf, Sec);
Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE);
return Ret;
}
for (AddressEntry &Ent : readAddressArea(Dwarf, Sec, CuId))
AddressArea.push_back(Ent);
static size_t getCuSize(std::vector<GdbIndexChunk> &C) {
size_t Ret = 0;
for (GdbIndexChunk &D : C)
Ret += D.CompilationUnits.size();
return Ret;
}
std::vector<std::pair<StringRef, uint8_t>> NamesAndTypes =
readPubNamesAndTypes(Dwarf, Config->IsLE);
for (std::pair<StringRef, uint8_t> &Pair : NamesAndTypes) {
uint32_t Hash = hash(Pair.first);
size_t Offset = StringPool.add(Pair.first);
bool IsNew;
GdbSymbol *Sym;
std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset);
if (IsNew) {
Sym->CuVectorIndex = CuVectors.size();
CuVectors.resize(CuVectors.size() + 1);
}
CuVectors[Sym->CuVectorIndex].insert((Pair.second << 24) | (uint32_t)CuId);
}
static size_t getAddressAreaSize(std::vector<GdbIndexChunk> &C) {
size_t Ret = 0;
for (GdbIndexChunk &D : C)
Ret += D.AddressArea.size();
return Ret;
}
void GdbIndexSection::finalizeContents() {
@ -1778,17 +1816,14 @@ void GdbIndexSection::finalizeContents() {
return;
Finalized = true;
for (InputSectionBase *S : InputSections)
if (InputSection *IS = dyn_cast<InputSection>(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 @@ void GdbIndexSection::writeTo(uint8_t *Buf) {
Buf += 24;
// Write the CU list.
for (std::pair<uint64_t, uint64_t> 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.

View File

@ -509,20 +509,23 @@ public:
size_t getSize() const override;
bool empty() const override;
// Pairs of [CU Offset, CU length].
std::vector<std::pair<uint64_t, uint64_t>> 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<std::set<uint32_t>> CuVectors;
std::vector<AddressEntry> 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<GdbIndexChunk> Chunks;
private:
void readDwarf(InputSection *Sec);
GdbIndexChunk readDwarf(InputSection *Sec);
void buildIndex();
uint32_t CuTypesOffset;
uint32_t SymTabOffset;