summaryrefslogtreecommitdiff
path: root/ELF/GdbIndex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/GdbIndex.cpp')
-rw-r--r--ELF/GdbIndex.cpp208
1 files changed, 26 insertions, 182 deletions
diff --git a/ELF/GdbIndex.cpp b/ELF/GdbIndex.cpp
index 762144dd0a96b..99e02d0025b0e 100644
--- a/ELF/GdbIndex.cpp
+++ b/ELF/GdbIndex.cpp
@@ -7,199 +7,43 @@
//
//===----------------------------------------------------------------------===//
//
-// File contains classes for implementation of --gdb-index command line option.
+// The -gdb-index option instructs the linker to emit a .gdb_index section.
+// The section contains information to make gdb startup faster.
+// The format of the section is described at
+// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html.
//
-// If that option is used, linker should emit a .gdb_index section that allows
-// debugger to locate and read .dwo files, containing neccessary debug
-// information.
-// More information about implementation can be found in DWARF specification,
-// latest version is available at http://dwarfstd.org.
-//
-// .gdb_index section format:
-// (Information is based on/taken from
-// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html (*))
-//
-// A mapped index consists of several areas, laid out in order:
-// 1) The file header.
-// 2) "The CU (compilation unit) list. This is a sequence of pairs of 64-bit
-// little-endian values, sorted by the CU offset. The first element in each
-// pair is the offset of a CU in the .debug_info section. The second element
-// in each pair is the length of that CU. References to a CU elsewhere in the
-// map are done using a CU index, which is just the 0-based index into this
-// table. Note that if there are type CUs, then conceptually CUs and type CUs
-// form a single list for the purposes of CU indices."(*)
-// 3) The types CU list. Depricated as .debug_types does not appear in the DWARF
-// v5 specification.
-// 4) The address area. The address area is a sequence of address
-// entries, where each entrie contains low address, high address and CU
-// index.
-// 5) "The symbol table. This is an open-addressed hash table. The size of the
-// hash table is always a power of 2. Each slot in the hash table consists of
-// a pair of offset_type values. The first value is the offset of the
-// symbol's name in the constant pool. The second value is the offset of the
-// CU vector in the constant pool."(*)
-// 6) "The constant pool. This is simply a bunch of bytes. It is organized so
-// that alignment is correct: CU vectors are stored first, followed by
-// strings." (*)
-//
-// For constructing the .gdb_index section following steps should be performed:
-// 1) For file header nothing special should be done. It contains the offsets to
-// the areas below.
-// 2) Scan the compilation unit headers of the .debug_info sections to build a
-// list of compilation units.
-// 3) CU Types are no longer needed as DWARF skeleton type units never made it
-// into the standard. lld does nothing to support parsing of .debug_types
-// and generates empty types CU area in .gdb_index section.
-// 4) Address area entries are extracted from DW_TAG_compile_unit DIEs of
-// .debug_info sections.
-// 5) For building the symbol table linker extracts the public names from the
-// .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.
//===----------------------------------------------------------------------===//
#include "GdbIndex.h"
+#include "Memory.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
#include "llvm/Object/ELFObjectFile.h"
using namespace llvm;
using namespace llvm::object;
+using namespace lld;
using namespace lld::elf;
-template <class ELFT>
-GdbIndexBuilder<ELFT>::GdbIndexBuilder(InputSection<ELFT> *DebugInfoSec)
- : DebugInfoSec(DebugInfoSec) {
- if (Expected<std::unique_ptr<object::ObjectFile>> Obj =
- object::ObjectFile::createObjectFile(DebugInfoSec->getFile()->MB))
- Dwarf.reset(new DWARFContextInMemory(*Obj.get(), this));
- else
- error(toString(DebugInfoSec->getFile()) + ": error creating DWARF context");
-}
-
-template <class ELFT>
-std::vector<std::pair<typename ELFT::uint, typename ELFT::uint>>
-GdbIndexBuilder<ELFT>::readCUList() {
- std::vector<std::pair<uintX_t, uintX_t>> Ret;
- for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units())
- Ret.push_back(
- {DebugInfoSec->OutSecOff + CU->getOffset(), CU->getLength() + 4});
- 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) {
- DWARFDebugPubTable PubTable(D, IsLE, true);
- for (const DWARFDebugPubTable::Set &S : PubTable.getData())
- for (const DWARFDebugPubTable::Entry &E : S.Entries)
- Ret.push_back({E.Name, E.Descriptor.toBits()});
- }
- 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;
+ GdbSymbol *&Sym = Map[Offset];
+ if (Sym)
+ return {false, Sym};
+ Sym = make<GdbSymbol>(Hash, Offset);
+ return {true, Sym};
+}
+
+void GdbHashTab::finalizeContents() {
+ uint32_t Size = std::max<uint32_t>(1024, NextPowerOf2(Map.size() * 4 / 3));
+ uint32_t Mask = Size - 1;
+ Table.resize(Size);
+
+ for (auto &P : Map) {
+ GdbSymbol *Sym = P.second;
+ uint32_t I = Sym->NameHash & Mask;
+ uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1;
+
+ while (Table[I])
+ I = (I + Step) & Mask;
+ Table[I] = Sym;
}
- 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)
- if (S && S != &InputSection<ELFT>::Discarded)
- if (Offset >= S->Offset && Offset < S->Offset + S->getSize())
- return S;
- return nullptr;
-}
-
-template <class ELFT>
-std::vector<AddressEntry<ELFT>>
-GdbIndexBuilder<ELFT>::readAddressArea(size_t CurrentCU) {
- std::vector<AddressEntry<ELFT>> Ret;
- for (const auto &CU : Dwarf->compile_units()) {
- DWARFAddressRangesVector Ranges;
- CU->collectAddressRanges(Ranges);
-
- ArrayRef<InputSectionBase<ELFT> *> Sections =
- DebugInfoSec->getFile()->getSections();
-
- for (std::pair<uint64_t, uint64_t> &R : Ranges)
- if (InputSectionBase<ELFT> *S = findSection(Sections, R.first))
- Ret.push_back(
- {S, R.first - S->Offset, R.second - S->Offset, CurrentCU});
- ++CurrentCU;
- }
- return Ret;
-}
-
-// We return file offset as load address for allocatable sections. That is
-// currently used for collecting address ranges in readAddressArea(). We are
-// able then to find section index that range belongs to.
-template <class ELFT>
-uint64_t GdbIndexBuilder<ELFT>::getSectionLoadAddress(
- const object::SectionRef &Sec) const {
- if (static_cast<const ELFSectionRef &>(Sec).getFlags() & ELF::SHF_ALLOC)
- return static_cast<const ELFSectionRef &>(Sec).getOffset();
- return 0;
-}
-
-template <class ELFT>
-std::unique_ptr<LoadedObjectInfo> GdbIndexBuilder<ELFT>::clone() const {
- return {};
-}
-
-namespace lld {
-namespace elf {
-template class GdbIndexBuilder<ELF32LE>;
-template class GdbIndexBuilder<ELF32BE>;
-template class GdbIndexBuilder<ELF64LE>;
-template class GdbIndexBuilder<ELF64BE>;
-}
}