1 //===- DWARFListTable.h -----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #ifndef LLVM_DEBUGINFO_DWARFLISTTABLE_H
11 #define LLVM_DEBUGINFO_DWARFLISTTABLE_H
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"
26 /// A base class for DWARF list entries, such as range or location list
28 struct DWARFListEntryBase {
29 /// The offset at which the entry is located in the section.
31 /// The DWARF encoding (DW_RLE_* or DW_LLE_*).
33 /// The index of the section this entry belongs to.
34 uint64_t SectionIndex;
37 /// A base class for lists of entries that are extracted from a particular
38 /// section, such as range lists or location lists.
39 template <typename ListEntryType> class DWARFListType {
40 using EntryType = ListEntryType;
41 using ListEntries = std::vector<EntryType>;
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);
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 {
59 /// The total length of the entries for this table, not including the length
62 /// The DWARF version number.
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
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.
71 /// The number of offsets that follow the header before the range lists.
72 uint32_t OffsetEntryCount;
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
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
89 StringRef ListTypeString;
92 DWARFListTableHeader(StringRef SectionName, StringRef ListTypeString)
93 : SectionName(SectionName), ListTypeString(ListTypeString) {}
99 uint32_t getHeaderOffset() const { return HeaderOffset; }
100 uint8_t getAddrSize() const { return HeaderData.AddrSize; }
101 uint32_t getLength() const { return HeaderData.Length; }
102 uint16_t getVersion() const { return HeaderData.Version; }
103 StringRef getSectionName() const { return SectionName; }
104 StringRef getListTypeString() const { return ListTypeString; }
105 dwarf::DwarfFormat getFormat() const { return Format; }
107 void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) const;
108 Optional<uint32_t> getOffsetEntry(uint32_t Index) const {
109 if (Index < Offsets.size())
110 return Offsets[Index];
114 /// Extract the table header and the array of offsets.
115 Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr);
117 /// Returns the length of the table, including the length field, or 0 if the
118 /// length has not been determined (e.g. because the table has not yet been
119 /// parsed, or there was a problem in parsing).
120 uint32_t length() const;
123 /// A class representing a table of lists as specified in the DWARF v5
124 /// standard for location lists and range lists. The table consists of a header
125 /// followed by an array of offsets into a DWARF section, followed by zero or
126 /// more list entries. The list entries are kept in a map where the keys are
127 /// the lists' section offsets.
128 template <typename DWARFListType> class DWARFListTableBase {
129 DWARFListTableHeader Header;
130 /// A mapping between file offsets and lists. It is used to find a particular
131 /// list based on an offset (obtained from DW_AT_ranges, for example).
132 std::map<uint32_t, DWARFListType> ListMap;
133 /// This string is displayed as a heading before the list is dumped
134 /// (e.g. "ranges:").
135 StringRef HeaderString;
138 DWARFListTableBase(StringRef SectionName, StringRef HeaderString,
139 StringRef ListTypeString)
140 : Header(SectionName, ListTypeString), HeaderString(HeaderString) {}
147 /// Extract the table header and the array of offsets.
148 Error extractHeaderAndOffsets(DWARFDataExtractor Data, uint32_t *OffsetPtr) {
149 return Header.extract(Data, OffsetPtr);
151 /// Extract an entire table, including all list entries.
152 Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr);
153 /// Look up a list based on a given offset. Extract it and enter it into the
154 /// list map if necessary.
155 Expected<DWARFListType> findList(DWARFDataExtractor Data, uint32_t Offset);
157 uint32_t getHeaderOffset() const { return Header.getHeaderOffset(); }
158 uint8_t getAddrSize() const { return Header.getAddrSize(); }
160 void dump(raw_ostream &OS,
161 llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
163 DIDumpOptions DumpOpts = {}) const;
165 /// Return the contents of the offset entry designated by a given index.
166 Optional<uint32_t> getOffsetEntry(uint32_t Index) const {
167 return Header.getOffsetEntry(Index);
169 /// Return the size of the table header including the length but not including
170 /// the offsets. This is dependent on the table format, which is unambiguously
171 /// derived from parsing the table.
172 uint8_t getHeaderSize() const {
173 switch (Header.getFormat()) {
174 case dwarf::DwarfFormat::DWARF32:
176 case dwarf::DwarfFormat::DWARF64:
179 llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64");
182 uint32_t length() { return Header.length(); }
185 template <typename DWARFListType>
186 Error DWARFListTableBase<DWARFListType>::extract(DWARFDataExtractor Data,
187 uint32_t *OffsetPtr) {
189 if (Error E = extractHeaderAndOffsets(Data, OffsetPtr))
192 Data.setAddressSize(Header.getAddrSize());
193 uint32_t End = getHeaderOffset() + Header.length();
194 while (*OffsetPtr < End) {
195 DWARFListType CurrentList;
196 uint32_t Off = *OffsetPtr;
197 if (Error E = CurrentList.extract(Data, getHeaderOffset(), End, OffsetPtr,
198 Header.getSectionName(),
199 Header.getListTypeString()))
201 ListMap[Off] = CurrentList;
204 assert(*OffsetPtr == End &&
205 "mismatch between expected length of table and length "
206 "of extracted data");
207 return Error::success();
210 template <typename ListEntryType>
211 Error DWARFListType<ListEntryType>::extract(DWARFDataExtractor Data,
212 uint32_t HeaderOffset, uint32_t End,
214 StringRef SectionName,
215 StringRef ListTypeString) {
216 if (*OffsetPtr < HeaderOffset || *OffsetPtr >= End)
217 return createStringError(errc::invalid_argument,
218 "invalid %s list offset 0x%" PRIx32,
219 ListTypeString.data(), *OffsetPtr);
221 while (*OffsetPtr < End) {
223 if (Error E = Entry.extract(Data, End, OffsetPtr))
225 Entries.push_back(Entry);
226 if (Entry.isSentinel())
227 return Error::success();
229 return createStringError(errc::illegal_byte_sequence,
230 "no end of list marker detected at end of %s table "
231 "starting at offset 0x%" PRIx32,
232 SectionName.data(), HeaderOffset);
235 template <typename DWARFListType>
236 void DWARFListTableBase<DWARFListType>::dump(
238 llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
240 DIDumpOptions DumpOpts) const {
241 Header.dump(OS, DumpOpts);
242 OS << HeaderString << "\n";
244 // Determine the length of the longest encoding string we have in the table,
245 // so we can align the output properly. We only need this in verbose mode.
246 size_t MaxEncodingStringLength = 0;
247 if (DumpOpts.Verbose) {
248 for (const auto &List : ListMap)
249 for (const auto &Entry : List.second.getEntries())
250 MaxEncodingStringLength =
251 std::max(MaxEncodingStringLength,
252 dwarf::RangeListEncodingString(Entry.EntryKind).size());
255 uint64_t CurrentBase = 0;
256 for (const auto &List : ListMap)
257 for (const auto &Entry : List.second.getEntries())
258 Entry.dump(OS, getAddrSize(), MaxEncodingStringLength, CurrentBase,
259 DumpOpts, LookupPooledAddress);
262 template <typename DWARFListType>
263 Expected<DWARFListType>
264 DWARFListTableBase<DWARFListType>::findList(DWARFDataExtractor Data,
266 auto Entry = ListMap.find(Offset);
267 if (Entry != ListMap.end())
268 return Entry->second;
270 // Extract the list from the section and enter it into the list map.
272 uint32_t End = getHeaderOffset() + Header.length();
273 uint32_t StartingOffset = Offset;
275 List.extract(Data, getHeaderOffset(), End, &Offset,
276 Header.getSectionName(), Header.getListTypeString()))
278 ListMap[StartingOffset] = List;
282 } // end namespace llvm
284 #endif // LLVM_DEBUGINFO_DWARFLISTTABLE_H