summaryrefslogtreecommitdiffstats
path: root/lld/ELF/GdbIndex.cpp
blob: 74ebcf92400d333fd77ce886cef09851e962be49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
//===- GdbIndex.cpp -------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// File contains classes for implementation of --gdb-index command line option.
//
// 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 "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
#include "llvm/Object/ELFObjectFile.h"

using namespace llvm;
using namespace llvm::object;
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;
  }
  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;
}

template <class ELFT>
uint64_t GdbIndexBuilder<ELFT>::getSectionLoadAddress(
    const object::SectionRef &Sec) const {
  return static_cast<const ELFSectionRef &>(Sec).getOffset();
}

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>;
}
}
OpenPOWER on IntegriCloud