Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/include/llvm/DebugInfo/DWARF/DWARFListTable.h
Line
Count
Source (jump to first uncovered line)
1
//===- DWARFListTable.h -----------------------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#ifndef LLVM_DEBUGINFO_DWARFLISTTABLE_H
10
#define LLVM_DEBUGINFO_DWARFLISTTABLE_H
11
12
#include "llvm/BinaryFormat/Dwarf.h"
13
#include "llvm/DebugInfo/DIContext.h"
14
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
15
#include "llvm/Support/Errc.h"
16
#include "llvm/Support/Error.h"
17
#include "llvm/Support/Format.h"
18
#include "llvm/Support/raw_ostream.h"
19
#include <cstdint>
20
#include <map>
21
#include <vector>
22
23
namespace llvm {
24
25
/// A base class for DWARF list entries, such as range or location list
26
/// entries.
27
struct DWARFListEntryBase {
28
  /// The offset at which the entry is located in the section.
29
  uint32_t Offset;
30
  /// The DWARF encoding (DW_RLE_* or DW_LLE_*).
31
  uint8_t EntryKind;
32
  /// The index of the section this entry belongs to.
33
  uint64_t SectionIndex;
34
};
35
36
/// A base class for lists of entries that are extracted from a particular
37
/// section, such as range lists or location lists.
38
template <typename ListEntryType> class DWARFListType {
39
  using EntryType = ListEntryType;
40
  using ListEntries = std::vector<EntryType>;
41
42
protected:
43
  ListEntries Entries;
44
45
public:
46
40
  const ListEntries &getEntries() const { return Entries; }
47
  bool empty() const { return Entries.empty(); }
48
  void clear() { Entries.clear(); }
49
  Error extract(DWARFDataExtractor Data, uint32_t HeaderOffset, uint32_t End,
50
                uint32_t *OffsetPtr, StringRef SectionName,
51
                StringRef ListStringName);
52
};
53
54
/// A class representing the header of a list table such as the range list
55
/// table in the .debug_rnglists section.
56
class DWARFListTableHeader {
57
  struct Header {
58
    /// The total length of the entries for this table, not including the length
59
    /// field itself.
60
    uint32_t Length = 0;
61
    /// The DWARF version number.
62
    uint16_t Version;
63
    /// The size in bytes of an address on the target architecture. For
64
    /// segmented addressing, this is the size of the offset portion of the
65
    /// address.
66
    uint8_t AddrSize;
67
    /// The size in bytes of a segment selector on the target architecture.
68
    /// If the target system uses a flat address space, this value is 0.
69
    uint8_t SegSize;
70
    /// The number of offsets that follow the header before the range lists.
71
    uint32_t OffsetEntryCount;
72
  };
73
74
  Header HeaderData;
75
  /// The offset table, which contains offsets to the individual list entries.
76
  /// It is used by forms such as DW_FORM_rnglistx.
77
  /// FIXME: Generate the table and use the appropriate forms.
78
  std::vector<uint32_t> Offsets;
79
  /// The table's format, either DWARF32 or DWARF64.
80
  dwarf::DwarfFormat Format;
81
  /// The offset at which the header (and hence the table) is located within
82
  /// its section.
83
  uint32_t HeaderOffset;
84
  /// The name of the section the list is located in.
85
  StringRef SectionName;
86
  /// A characterization of the list for dumping purposes, e.g. "range" or
87
  /// "location".
88
  StringRef ListTypeString;
89
90
public:
91
  DWARFListTableHeader(StringRef SectionName, StringRef ListTypeString)
92
56
      : SectionName(SectionName), ListTypeString(ListTypeString) {}
93
94
37
  void clear() {
95
37
    HeaderData = {};
96
37
    Offsets.clear();
97
37
  }
98
91
  uint32_t getHeaderOffset() const { return HeaderOffset; }
99
115
  uint8_t getAddrSize() const { return HeaderData.AddrSize; }
100
0
  uint32_t getLength() const { return HeaderData.Length; }
101
4
  uint16_t getVersion() const { return HeaderData.Version; }
102
47
  StringRef getSectionName() const { return SectionName; }
103
47
  StringRef getListTypeString() const { return ListTypeString; }
104
3
  dwarf::DwarfFormat getFormat() const { return Format; }
105
106
  void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) const;
107
21
  Optional<uint32_t> getOffsetEntry(uint32_t Index) const {
108
21
    if (Index < Offsets.size())
109
21
      return Offsets[Index];
110
0
    return None;
111
0
  }
112
113
  /// Extract the table header and the array of offsets.
114
  Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr);
115
116
  /// Returns the length of the table, including the length field, or 0 if the
117
  /// length has not been determined (e.g. because the table has not yet been
118
  /// parsed, or there was a problem in parsing).
119
  uint32_t length() const;
120
};
121
122
/// A class representing a table of lists as specified in the DWARF v5
123
/// standard for location lists and range lists. The table consists of a header
124
/// followed by an array of offsets into a DWARF section, followed by zero or
125
/// more list entries. The list entries are kept in a map where the keys are
126
/// the lists' section offsets.
127
template <typename DWARFListType> class DWARFListTableBase {
128
  DWARFListTableHeader Header;
129
  /// A mapping between file offsets and lists. It is used to find a particular
130
  /// list based on an offset (obtained from DW_AT_ranges, for example).
131
  std::map<uint32_t, DWARFListType> ListMap;
132
  /// This string is displayed as a heading before the list is dumped
133
  /// (e.g. "ranges:").
134
  StringRef HeaderString;
135
136
protected:
137
  DWARFListTableBase(StringRef SectionName, StringRef HeaderString,
138
                     StringRef ListTypeString)
139
52
      : Header(SectionName, ListTypeString), HeaderString(HeaderString) {}
140
141
public:
142
37
  void clear() {
143
37
    Header.clear();
144
37
    ListMap.clear();
145
37
  }
146
  /// Extract the table header and the array of offsets.
147
52
  Error extractHeaderAndOffsets(DWARFDataExtractor Data, uint32_t *OffsetPtr) {
148
52
    return Header.extract(Data, OffsetPtr);
149
52
  }
150
  /// Extract an entire table, including all list entries.
151
  Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr);
152
  /// Look up a list based on a given offset. Extract it and enter it into the
153
  /// list map if necessary.
154
  Expected<DWARFListType> findList(DWARFDataExtractor Data, uint32_t Offset);
155
156
91
  uint32_t getHeaderOffset() const { return Header.getHeaderOffset(); }
157
83
  uint8_t getAddrSize() const { return Header.getAddrSize(); }
158
159
  void dump(raw_ostream &OS,
160
            llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
161
                LookupPooledAddress,
162
            DIDumpOptions DumpOpts = {}) const;
163
164
  /// Return the contents of the offset entry designated by a given index.
165
21
  Optional<uint32_t> getOffsetEntry(uint32_t Index) const {
166
21
    return Header.getOffsetEntry(Index);
167
21
  }
168
  /// Return the size of the table header including the length but not including
169
  /// the offsets. This is dependent on the table format, which is unambiguously
170
  /// derived from parsing the table.
171
3
  uint8_t getHeaderSize() const {
172
3
    switch (Header.getFormat()) {
173
3
    case dwarf::DwarfFormat::DWARF32:
174
3
      return 12;
175
3
    case dwarf::DwarfFormat::DWARF64:
176
0
      return 20;
177
0
    }
178
0
    llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64");
179
0
  }
180
181
15
  uint32_t length() { return Header.length(); }
182
};
183
184
template <typename DWARFListType>
185
Error DWARFListTableBase<DWARFListType>::extract(DWARFDataExtractor Data,
186
37
                                                 uint32_t *OffsetPtr) {
187
37
  clear();
188
37
  if (Error E = extractHeaderAndOffsets(Data, OffsetPtr))
189
9
    return E;
190
28
191
28
  Data.setAddressSize(Header.getAddrSize());
192
28
  uint32_t End = getHeaderOffset() + Header.length();
193
53
  while (*OffsetPtr < End) {
194
31
    DWARFListType CurrentList;
195
31
    uint32_t Off = *OffsetPtr;
196
31
    if (Error E = CurrentList.extract(Data, getHeaderOffset(), End, OffsetPtr,
197
6
                                      Header.getSectionName(),
198
6
                                      Header.getListTypeString()))
199
6
      return E;
200
25
    ListMap[Off] = CurrentList;
201
25
  }
202
28
203
28
  assert(*OffsetPtr == End &&
204
22
         "mismatch between expected length of table and length "
205
22
         "of extracted data");
206
22
  return Error::success();
207
28
}
208
209
template <typename ListEntryType>
210
Error DWARFListType<ListEntryType>::extract(DWARFDataExtractor Data,
211
                                            uint32_t HeaderOffset, uint32_t End,
212
                                            uint32_t *OffsetPtr,
213
                                            StringRef SectionName,
214
47
                                            StringRef ListTypeString) {
215
47
  if (*OffsetPtr < HeaderOffset || *OffsetPtr >= End)
216
2
    return createStringError(errc::invalid_argument,
217
2
                       "invalid %s list offset 0x%" PRIx32,
218
2
                       ListTypeString.data(), *OffsetPtr);
219
45
  Entries.clear();
220
120
  while (*OffsetPtr < End) {
221
119
    ListEntryType Entry;
222
119
    if (Error E = Entry.extract(Data, End, OffsetPtr))
223
5
      return E;
224
114
    Entries.push_back(Entry);
225
114
    if (Entry.isSentinel())
226
39
      return Error::success();
227
114
  }
228
45
  return createStringError(errc::illegal_byte_sequence,
229
1
                     "no end of list marker detected at end of %s table "
230
1
                     "starting at offset 0x%" PRIx32,
231
1
                     SectionName.data(), HeaderOffset);
232
45
}
233
234
template <typename DWARFListType>
235
void DWARFListTableBase<DWARFListType>::dump(
236
    raw_ostream &OS,
237
    llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
238
        LookupPooledAddress,
239
22
    DIDumpOptions DumpOpts) const {
240
22
  Header.dump(OS, DumpOpts);
241
22
  OS << HeaderString << "\n";
242
22
243
22
  // Determine the length of the longest encoding string we have in the table,
244
22
  // so we can align the output properly. We only need this in verbose mode.
245
22
  size_t MaxEncodingStringLength = 0;
246
22
  if (DumpOpts.Verbose) {
247
13
    for (const auto &List : ListMap)
248
15
      for (const auto &Entry : List.second.getEntries())
249
44
        MaxEncodingStringLength =
250
44
            std::max(MaxEncodingStringLength,
251
44
                     dwarf::RangeListEncodingString(Entry.EntryKind).size());
252
13
  }
253
22
254
22
  uint64_t CurrentBase = 0;
255
22
  for (const auto &List : ListMap)
256
25
    for (const auto &Entry : List.second.getEntries())
257
67
      Entry.dump(OS, getAddrSize(), MaxEncodingStringLength, CurrentBase,
258
67
                 DumpOpts, LookupPooledAddress);
259
22
}
260
261
template <typename DWARFListType>
262
Expected<DWARFListType>
263
DWARFListTableBase<DWARFListType>::findList(DWARFDataExtractor Data,
264
16
                                            uint32_t Offset) {
265
16
  auto Entry = ListMap.find(Offset);
266
16
  if (Entry != ListMap.end())
267
0
    return Entry->second;
268
16
269
16
  // Extract the list from the section and enter it into the list map.
270
16
  DWARFListType List;
271
16
  uint32_t End = getHeaderOffset() + Header.length();
272
16
  uint32_t StartingOffset = Offset;
273
16
  if (Error E =
274
2
          List.extract(Data, getHeaderOffset(), End, &Offset,
275
2
                       Header.getSectionName(), Header.getListTypeString()))
276
2
    return std::move(E);
277
14
  ListMap[StartingOffset] = List;
278
14
  return List;
279
14
}
280
281
} // end namespace llvm
282
283
#endif // LLVM_DEBUGINFO_DWARFLISTTABLE_H