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