[ELF] - Partial support of --gdb-index command line option (Part 3).

Patch continues work started in D24706 and D25821.

in this patch symbol table and constant pool areas were
added to .gdb_index section output.

This one finishes the implementation of --gdb-index functionality in LLD.

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

llvm-svn: 289810
This commit is contained in:
George Rimar
2016-12-15 12:07:53 +00:00
parent 70f090d568
commit ec02b8d4c0
5 changed files with 215 additions and 15 deletions

View File

@@ -56,11 +56,6 @@
// .debug_gnu_pubnames and .debug_gnu_pubtypes sections. Then it builds the
// hashtable in according to .gdb_index format specification.
// 6) Constant pool is populated at the same time as symbol table.
//
// 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"
@@ -91,6 +86,80 @@ GdbIndexBuilder<ELFT>::readCUList() {
return Ret;
}
template <class ELFT>
std::vector<std::pair<StringRef, uint8_t>>
GdbIndexBuilder<ELFT>::readPubNamesAndTypes() {
const bool IsLE = ELFT::TargetEndianness == llvm::support::little;
StringRef Data[] = {Dwarf->getGnuPubNamesSection(),
Dwarf->getGnuPubTypesSection()};
std::vector<std::pair<StringRef, uint8_t>> Ret;
for (StringRef D : Data) {
DataExtractor PubNames(D, IsLE, 0);
uint32_t Offset = 0;
while (PubNames.isValidOffset(Offset)) {
// Skip length, version, unit offset and size.
Offset += 14;
while (Offset < D.size()) {
uint32_t DieRef = PubNames.getU32(&Offset);
if (DieRef == 0)
break;
uint8_t Flags = PubNames.getU8(&Offset);
const char *Name = PubNames.getCStr(&Offset);
Ret.push_back({Name, Flags});
}
}
}
return Ret;
}
std::pair<bool, GdbSymbol *> GdbHashTab::add(uint32_t Hash, size_t Offset) {
if (Size * 4 / 3 >= Table.size())
expand();
GdbSymbol **Slot = findSlot(Hash, Offset);
bool New = false;
if (*Slot == nullptr) {
++Size;
*Slot = new (Alloc) GdbSymbol(Hash, Offset);
New = true;
}
return {New, *Slot};
}
void GdbHashTab::expand() {
if (Table.empty()) {
Table.resize(InitialSize);
return;
}
std::vector<GdbSymbol *> NewTable(Table.size() * 2);
NewTable.swap(Table);
for (GdbSymbol *Sym : NewTable) {
if (!Sym)
continue;
GdbSymbol **Slot = findSlot(Sym->NameHash, Sym->NameOffset);
*Slot = Sym;
}
}
// Methods finds a slot for symbol with given hash. The step size used to find
// the next candidate slot when handling a hash collision is specified in
// .gdb_index section format. The hash value for a table entry is computed by
// applying an iterative hash function to the symbol's name.
GdbSymbol **GdbHashTab::findSlot(uint32_t Hash, size_t Offset) {
uint32_t Index = Hash & (Table.size() - 1);
uint32_t Step = ((Hash * 17) & (Table.size() - 1)) | 1;
for (;;) {
GdbSymbol *S = Table[Index];
if (!S || ((S->NameOffset == Offset) && (S->NameHash == Hash)))
return &Table[Index];
Index = (Index + Step) & (Table.size() - 1);
}
}
template <class ELFT>
static InputSectionBase<ELFT> *
findSection(ArrayRef<InputSectionBase<ELFT> *> Arr, uint64_t Offset) {

View File

@@ -47,6 +47,10 @@ public:
// parsed CU.
std::vector<AddressEntry<ELFT>> readAddressArea(size_t CurrentCU);
// Method extracts public names and types. It returns list of name and
// gnu_pub* kind pairs.
std::vector<std::pair<StringRef, uint8_t>> readPubNamesAndTypes();
private:
// Method returns section file offset as a load addres for DWARF parser. That
// allows to find the target section index for address ranges.
@@ -55,6 +59,40 @@ private:
std::unique_ptr<llvm::LoadedObjectInfo> clone() const override;
};
// Element of GdbHashTab hash table.
struct GdbSymbol {
GdbSymbol(uint32_t Hash, size_t Offset)
: NameHash(Hash), NameOffset(Offset) {}
uint32_t NameHash;
size_t NameOffset;
size_t CuVectorIndex;
};
// This class manages the hashed symbol table for the .gdb_index section.
// The hash value for a table entry is computed by applying an iterative hash
// function to the symbol's name.
class GdbHashTab final {
public:
std::pair<bool, GdbSymbol *> add(uint32_t Hash, size_t Offset);
size_t getCapacity() { return Table.size(); }
GdbSymbol *getSymbol(size_t I) { return Table[I]; }
private:
void expand();
GdbSymbol **findSlot(uint32_t Hash, size_t Offset);
llvm::BumpPtrAllocator Alloc;
std::vector<GdbSymbol *> Table;
// Size keeps the amount of filled entries in Table.
size_t Size = 0;
// Initial size must be a power of 2.
static const int32_t InitialSize = 1024;
};
} // namespace elf
} // namespace lld

View File

@@ -1457,7 +1457,8 @@ template <class ELFT> size_t IpltSection<ELFT>::getSize() const {
template <class ELFT>
GdbIndexSection<ELFT>::GdbIndexSection()
: SyntheticSection<ELFT>(0, SHT_PROGBITS, 1, ".gdb_index") {}
: SyntheticSection<ELFT>(0, SHT_PROGBITS, 1, ".gdb_index"),
StringPool(llvm::StringTableBuilder::ELF) {}
template <class ELFT> void GdbIndexSection<ELFT>::parseDebugSections() {
for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections)
@@ -1466,6 +1467,16 @@ template <class ELFT> void GdbIndexSection<ELFT>::parseDebugSections() {
readDwarf(IS);
}
// Iterative hash function for symbol's name is described in .gdb_index format
// specification. Note that we use one for version 5 to 7 here, it is different
// for version 4.
static uint32_t hash(StringRef Str) {
uint32_t R = 0;
for (uint8_t C : Str)
R = R * 67 + tolower(C) - 113;
return R;
}
template <class ELFT>
void GdbIndexSection<ELFT>::readDwarf(InputSection<ELFT> *I) {
GdbIndexBuilder<ELFT> Builder(I);
@@ -1478,6 +1489,27 @@ void GdbIndexSection<ELFT>::readDwarf(InputSection<ELFT> *I) {
std::vector<AddressEntry<ELFT>> AddrArea = Builder.readAddressArea(CuId);
AddressArea.insert(AddressArea.end(), AddrArea.begin(), AddrArea.end());
std::vector<std::pair<StringRef, uint8_t>> NamesAndTypes =
Builder.readPubNamesAndTypes();
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.push_back({{CuId, Pair.second}});
continue;
}
std::vector<std::pair<uint32_t, uint8_t>> &CuVec =
CuVectors[Sym->CuVectorIndex];
CuVec.push_back({CuId, Pair.second});
}
}
template <class ELFT> void GdbIndexSection<ELFT>::finalize() {
@@ -1491,20 +1523,31 @@ template <class ELFT> void GdbIndexSection<ELFT>::finalize() {
// and 5 more fields with different kinds of offsets.
CuTypesOffset = CuListOffset + CompilationUnits.size() * CompilationUnitSize;
SymTabOffset = CuTypesOffset + AddressArea.size() * AddressEntrySize;
ConstantPoolOffset =
SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize;
for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) {
CuVectorsOffset.push_back(CuVectorsSize);
CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1);
}
StringPoolOffset = ConstantPoolOffset + CuVectorsSize;
StringPool.finalizeInOrder();
}
template <class ELFT> size_t GdbIndexSection<ELFT>::getSize() const {
const_cast<GdbIndexSection<ELFT> *>(this)->finalize();
return SymTabOffset;
return StringPoolOffset + StringPool.getSize();
}
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, SymTabOffset); // Symbol table offset.
write32le(Buf + 20, SymTabOffset); // 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, ConstantPoolOffset); // Constant pool offset.
Buf += 24;
// Write the CU list.
@@ -1522,6 +1565,34 @@ template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
write32le(Buf + 16, E.CuIndex);
Buf += 20;
}
// Write the symbol table.
for (size_t I = 0; I < SymbolTable.getCapacity(); ++I) {
GdbSymbol *Sym = SymbolTable.getSymbol(I);
if (Sym) {
size_t NameOffset =
Sym->NameOffset + StringPoolOffset - ConstantPoolOffset;
size_t CuVectorOffset = CuVectorsOffset[Sym->CuVectorIndex];
write32le(Buf, NameOffset);
write32le(Buf + 4, CuVectorOffset);
}
Buf += 8;
}
// Write the CU vectors into the constant pool.
for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) {
write32le(Buf, CuVec.size());
Buf += 4;
for (std::pair<uint32_t, uint8_t> &P : CuVec) {
uint32_t Index = P.first;
uint8_t Flags = P.second;
Index |= Flags << 24;
write32le(Buf, Index);
Buf += 4;
}
}
StringPool.write(Buf);
}
template <class ELFT> bool GdbIndexSection<ELFT>::empty() const {

View File

@@ -13,6 +13,7 @@
#include "GdbIndex.h"
#include "InputSection.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/MC/StringTableBuilder.h"
namespace lld {
namespace elf {
@@ -485,6 +486,13 @@ public:
// Pairs of [CU Offset, CU length].
std::vector<std::pair<uintX_t, uintX_t>> CompilationUnits;
llvm::StringTableBuilder StringPool;
GdbHashTab SymbolTable;
// The CU vector portion of the constant pool.
std::vector<std::vector<std::pair<uint32_t, uint8_t>>> CuVectors;
std::vector<AddressEntry<ELFT>> AddressArea;
private:
@@ -493,6 +501,11 @@ private:
uint32_t CuTypesOffset;
uint32_t SymTabOffset;
uint32_t ConstantPoolOffset;
uint32_t StringPoolOffset;
size_t CuVectorsSize = 0;
std::vector<size_t> CuVectorsOffset;
bool Finalized = false;
};

View File

@@ -36,5 +36,14 @@
# 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:
# CHECK: Symbol table offset = 0x60, size = 1024, filled slots:
# CHECK-NEXT: 489: Name offset = 0x1d, CU vector offset = 0x0
# CHECK-NEXT: String name: main, CU vector index: 0
# CHECK-NEXT: 754: Name offset = 0x22, CU vector offset = 0x8
# CHECK-NEXT: String name: int, CU vector index: 1
# CHECK-NEXT: 956: Name offset = 0x26, CU vector offset = 0x14
# CHECK-NEXT: String name: main2, CU vector index: 2
# CHECK: Constant pool offset = 0x2060, has 3 CU vectors:
# CHECK-NEXT: 0(0x0): 0x30000000
# CHECK-NEXT: 1(0x8): 0x90000000 0x90000001
# CHECK-NEXT: 2(0x14): 0x30000001