[lld] r289810 - [ELF] - Partial support of --gdb-index command line option (Part 3).
George Rimar via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 15 04:07:53 PST 2016
Author: grimar
Date: Thu Dec 15 06:07:53 2016
New Revision: 289810
URL: http://llvm.org/viewvc/llvm-project?rev=289810&view=rev
Log:
[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
Modified:
lld/trunk/ELF/GdbIndex.cpp
lld/trunk/ELF/GdbIndex.h
lld/trunk/ELF/SyntheticSections.cpp
lld/trunk/ELF/SyntheticSections.h
lld/trunk/test/ELF/gdb-index.s
Modified: lld/trunk/ELF/GdbIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/GdbIndex.cpp?rev=289810&r1=289809&r2=289810&view=diff
==============================================================================
--- lld/trunk/ELF/GdbIndex.cpp (original)
+++ lld/trunk/ELF/GdbIndex.cpp Thu Dec 15 06:07:53 2016
@@ -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"
@@ -92,6 +87,80 @@ GdbIndexBuilder<ELFT>::readCUList() {
}
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) {
for (InputSectionBase<ELFT> *S : Arr)
Modified: lld/trunk/ELF/GdbIndex.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/GdbIndex.h?rev=289810&r1=289809&r2=289810&view=diff
==============================================================================
--- lld/trunk/ELF/GdbIndex.h (original)
+++ lld/trunk/ELF/GdbIndex.h Thu Dec 15 06:07:53 2016
@@ -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
Modified: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=289810&r1=289809&r2=289810&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Thu Dec 15 06:07:53 2016
@@ -1457,7 +1457,8 @@ template <class ELFT> size_t IpltSection
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 GdbIndexSecti
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(In
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 GdbIndexSecti
// 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 GdbIndexSecti
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 {
Modified: lld/trunk/ELF/SyntheticSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.h?rev=289810&r1=289809&r2=289810&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.h (original)
+++ lld/trunk/ELF/SyntheticSections.h Thu Dec 15 06:07:53 2016
@@ -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;
};
Modified: lld/trunk/test/ELF/gdb-index.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/gdb-index.s?rev=289810&r1=289809&r2=289810&view=diff
==============================================================================
--- lld/trunk/test/ELF/gdb-index.s (original)
+++ lld/trunk/test/ELF/gdb-index.s Thu Dec 15 06:07:53 2016
@@ -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
More information about the llvm-commits
mailing list