blob: 3a273f802e24a7055fe2ac54a0f16f295f58aad1 [file] [log] [blame]
James Hendersonc2dfd502018-02-02 12:45:57 +00001//===- DWARFDebugRnglists.cpp ---------------------------------------------===//
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#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
11
12#include "llvm/BinaryFormat/Dwarf.h"
13#include "llvm/Support/Error.h"
14#include "llvm/Support/Format.h"
15#include "llvm/Support/raw_ostream.h"
16
17using namespace llvm;
18
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +000019void DWARFDebugRnglistTable::clear() {
James Hendersonc2dfd502018-02-02 12:45:57 +000020 HeaderData = {};
21 Offsets.clear();
22 Ranges.clear();
23}
24
25template <typename... Ts>
26static Error createError(char const *Fmt, const Ts &... Vals) {
27 std::string Buffer;
28 raw_string_ostream Stream(Buffer);
29 Stream << format(Fmt, Vals...);
30 return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
31}
32
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +000033Error DWARFDebugRnglistTable::extractHeaderAndOffsets(DWARFDataExtractor Data,
34 uint32_t *OffsetPtr) {
Wolfgang Pieba0729d42018-03-08 20:52:35 +000035 HeaderOffset = *OffsetPtr;
James Hendersonc2dfd502018-02-02 12:45:57 +000036 // Read and verify the length field.
37 if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t)))
38 return createError("section is not large enough to contain a "
39 ".debug_rnglists table length at offset 0x%" PRIx32,
40 *OffsetPtr);
41 // TODO: Add support for DWARF64.
42 HeaderData.Length = Data.getU32(OffsetPtr);
Wolfgang Pieba0729d42018-03-08 20:52:35 +000043 if (HeaderData.Length == 0xffffffffu)
44 return createError(
45 "DWARF64 is not supported in .debug_rnglists at offset 0x%" PRIx32,
46 HeaderOffset);
James Hendersonc2dfd502018-02-02 12:45:57 +000047 if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header))
48 return createError(".debug_rnglists table at offset 0x%" PRIx32
49 " has too small length (0x%" PRIx32
50 ") to contain a complete header",
Wolfgang Pieba0729d42018-03-08 20:52:35 +000051 HeaderOffset, length());
52 uint32_t End = HeaderOffset + length();
53 if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset))
James Hendersonc2dfd502018-02-02 12:45:57 +000054 return createError(
55 "section is not large enough to contain a .debug_rnglists table "
56 "of length 0x%" PRIx32 " at offset 0x%" PRIx32,
Wolfgang Pieba0729d42018-03-08 20:52:35 +000057 length(), HeaderOffset);
James Hendersonc2dfd502018-02-02 12:45:57 +000058
59 HeaderData.Version = Data.getU16(OffsetPtr);
60 HeaderData.AddrSize = Data.getU8(OffsetPtr);
61 HeaderData.SegSize = Data.getU8(OffsetPtr);
62 HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr);
63
64 // Perform basic validation of the remaining header fields.
65 if (HeaderData.Version != 5)
66 return createError("unrecognised .debug_rnglists table version %" PRIu16
67 " in table at offset 0x%" PRIx32,
Wolfgang Pieba0729d42018-03-08 20:52:35 +000068 HeaderData.Version, HeaderOffset);
James Hendersonc2dfd502018-02-02 12:45:57 +000069 if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
70 return createError(".debug_rnglists table at offset 0x%" PRIx32
71 " has unsupported address size %hhu",
Wolfgang Pieba0729d42018-03-08 20:52:35 +000072 HeaderOffset, HeaderData.AddrSize);
James Hendersonc2dfd502018-02-02 12:45:57 +000073 if (HeaderData.SegSize != 0)
74 return createError(".debug_rnglists table at offset 0x%" PRIx32
75 " has unsupported segment selector size %" PRIu8,
Wolfgang Pieba0729d42018-03-08 20:52:35 +000076 HeaderOffset, HeaderData.SegSize);
77 if (End < HeaderOffset + sizeof(HeaderData) +
James Hendersonc2dfd502018-02-02 12:45:57 +000078 HeaderData.OffsetEntryCount * sizeof(uint32_t))
79 return createError(".debug_rnglists table at offset 0x%" PRIx32
80 " has more offset entries (%" PRIu32
81 ") than there is space for",
Wolfgang Pieba0729d42018-03-08 20:52:35 +000082 HeaderOffset, HeaderData.OffsetEntryCount);
James Hendersonc2dfd502018-02-02 12:45:57 +000083 Data.setAddressSize(HeaderData.AddrSize);
James Hendersonc2dfd502018-02-02 12:45:57 +000084 for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I)
85 Offsets.push_back(Data.getU32(OffsetPtr));
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +000086 return Error::success();
87}
James Hendersonc2dfd502018-02-02 12:45:57 +000088
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +000089Error DWARFDebugRnglist::RangeListEntry::extract(DWARFDataExtractor Data,
90 uint32_t End,
91 uint32_t *OffsetPtr) {
92 Offset = *OffsetPtr;
93 // The caller should guarantee that we have at least 1 byte available, so
94 // we just assert instead of revalidate.
95 assert(*OffsetPtr < End &&
96 "not enough space to extract a rangelist encoding");
97 uint8_t Encoding = Data.getU8(OffsetPtr);
98
99 switch (Encoding) {
100 case dwarf::DW_RLE_end_of_list:
101 Value0 = Value1 = 0;
102 break;
103 // TODO: Support other encodings.
104 case dwarf::DW_RLE_base_addressx:
105 return createError("unsupported rnglists encoding DW_RLE_base_addressx "
106 "at offset 0x%" PRIx32,
107 *OffsetPtr - 1);
108 case dwarf::DW_RLE_startx_endx:
109 return createError("unsupported rnglists encoding DW_RLE_startx_endx at "
110 "offset 0x%" PRIx32,
111 *OffsetPtr - 1);
112 case dwarf::DW_RLE_startx_length:
113 return createError("unsupported rnglists encoding DW_RLE_startx_length "
114 "at offset 0x%" PRIx32,
115 *OffsetPtr - 1);
116 case dwarf::DW_RLE_offset_pair: {
117 uint32_t PreviousOffset = *OffsetPtr - 1;
118 Value0 = Data.getULEB128(OffsetPtr);
119 Value1 = Data.getULEB128(OffsetPtr);
120 if (End < *OffsetPtr)
121 return createError("read past end of table when reading "
122 "DW_RLE_offset_pair encoding at offset 0x%" PRIx32,
123 PreviousOffset);
124 break;
125 }
126 case dwarf::DW_RLE_base_address: {
127 if ((End - *OffsetPtr) < Data.getAddressSize())
128 return createError("insufficient space remaining in table for "
129 "DW_RLE_base_address encoding at offset 0x%" PRIx32,
130 *OffsetPtr - 1);
131 Value0 = Data.getAddress(OffsetPtr);
132 break;
133 }
134 case dwarf::DW_RLE_start_end: {
135 if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2))
136 return createError("insufficient space remaining in table for "
137 "DW_RLE_start_end encoding "
James Hendersonc2dfd502018-02-02 12:45:57 +0000138 "at offset 0x%" PRIx32,
139 *OffsetPtr - 1);
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000140 Value0 = Data.getAddress(OffsetPtr);
141 Value1 = Data.getAddress(OffsetPtr);
142 break;
143 }
144 case dwarf::DW_RLE_start_length: {
145 uint32_t PreviousOffset = *OffsetPtr - 1;
146 Value0 = Data.getAddress(OffsetPtr);
147 Value1 = Data.getULEB128(OffsetPtr);
148 if (End < *OffsetPtr)
149 return createError("read past end of table when reading "
150 "DW_RLE_start_length encoding at offset 0x%" PRIx32,
151 PreviousOffset);
152 break;
153 }
154 default:
155 return createError("unknown rnglists encoding 0x%" PRIx32
156 " at offset 0x%" PRIx32,
157 uint32_t(Encoding), *OffsetPtr - 1);
James Hendersonc2dfd502018-02-02 12:45:57 +0000158 }
159
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000160 EntryKind = Encoding;
161 return Error::success();
162}
James Hendersonc2dfd502018-02-02 12:45:57 +0000163
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000164Error DWARFDebugRnglist::extract(DWARFDataExtractor Data, uint32_t HeaderOffset,
165 uint32_t End, uint32_t *OffsetPtr) {
166 Entries.clear();
167 while (*OffsetPtr < End) {
168 RangeListEntry Entry{0, 0, 0, 0};
169 if (Error E = Entry.extract(Data, End, OffsetPtr))
170 return E;
171 Entries.push_back(Entry);
172 if (Entry.EntryKind == dwarf::DW_RLE_end_of_list)
173 return Error::success();
174 }
175 return createError(
176 "no end of list marker detected at end of .debug_rnglists table "
177 "starting at offset 0x%" PRIx32,
178 HeaderOffset);
179}
180
181Error DWARFDebugRnglistTable::extract(DWARFDataExtractor Data,
182 uint32_t *OffsetPtr) {
183 clear();
184 if (Error E = extractHeaderAndOffsets(Data, OffsetPtr))
185 return E;
186
187 Data.setAddressSize(HeaderData.AddrSize);
188 uint32_t End = HeaderOffset + length();
189 while (*OffsetPtr < End) {
190 DWARFDebugRnglist CurrentRangeList;
191 uint32_t Off = *OffsetPtr;
192 if (Error E = CurrentRangeList.extract(Data, HeaderOffset, End, OffsetPtr))
193 return E;
194 Ranges[Off] = CurrentRangeList;
195 }
196
197 assert(*OffsetPtr == End &&
198 "mismatch between expected length of .debug_rnglists table and length "
199 "of extracted data");
James Hendersonc2dfd502018-02-02 12:45:57 +0000200 return Error::success();
201}
202
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000203static void dumpRangeEntry(raw_ostream &OS,
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000204 DWARFDebugRnglist::RangeListEntry Entry,
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000205 uint8_t AddrSize, uint8_t MaxEncodingStringLength,
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000206 uint64_t &CurrentBase, DIDumpOptions DumpOpts) {
207 auto PrintRawEntry = [](raw_ostream &OS,
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000208 DWARFDebugRnglist::RangeListEntry Entry,
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000209 uint8_t AddrSize, DIDumpOptions DumpOpts) {
210 if (DumpOpts.Verbose) {
211 DumpOpts.DisplayRawContents = true;
212 DWARFAddressRange(Entry.Value0, Entry.Value1)
213 .dump(OS, AddrSize, DumpOpts);
214 OS << " => ";
215 }
216 };
217
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000218 if (DumpOpts.Verbose) {
219 // Print the section offset in verbose mode.
220 OS << format("0x%8.8" PRIx32 ":", Entry.Offset);
221 auto EncodingString = dwarf::RangeListEncodingString(Entry.EntryKind);
222 // Unsupported encodings should have been reported during parsing.
223 assert(!EncodingString.empty() && "Unknown range entry encoding");
224 OS << format(" [%s%*c", EncodingString.data(),
225 MaxEncodingStringLength - EncodingString.size() + 1, ']');
226 if (Entry.EntryKind != dwarf::DW_RLE_end_of_list)
227 OS << ": ";
228 }
229
230 switch (Entry.EntryKind) {
231 case dwarf::DW_RLE_end_of_list:
232 OS << (DumpOpts.Verbose ? "" : "<End of list>");
233 break;
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000234 case dwarf::DW_RLE_base_address:
235 // In non-verbose mode we do not print anything for this entry.
236 CurrentBase = Entry.Value0;
237 if (!DumpOpts.Verbose)
238 return;
239 OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Entry.Value0);
240 break;
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000241 case dwarf::DW_RLE_start_length:
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000242 PrintRawEntry(OS, Entry, AddrSize, DumpOpts);
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000243 DWARFAddressRange(Entry.Value0, Entry.Value0 + Entry.Value1)
244 .dump(OS, AddrSize, DumpOpts);
245 break;
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000246 case dwarf::DW_RLE_offset_pair:
247 PrintRawEntry(OS, Entry, AddrSize, DumpOpts);
248 DWARFAddressRange(Entry.Value0 + CurrentBase, Entry.Value1 + CurrentBase)
249 .dump(OS, AddrSize, DumpOpts);
250 break;
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000251 case dwarf::DW_RLE_start_end:
252 DWARFAddressRange(Entry.Value0, Entry.Value1).dump(OS, AddrSize, DumpOpts);
253 break;
254 default:
255 llvm_unreachable("Unsupported range list encoding");
256 }
257 OS << "\n";
258}
259
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000260void DWARFDebugRnglistTable::dump(raw_ostream &OS,
261 DIDumpOptions DumpOpts) const {
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000262 if (DumpOpts.Verbose)
263 OS << format("0x%8.8" PRIx32 ": ", HeaderOffset);
James Henderson10392cd2018-02-05 10:47:13 +0000264 OS << format("Range List Header: length = 0x%8.8" PRIx32
265 ", version = 0x%4.4" PRIx16 ", "
266 "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8
267 ", offset_entry_count = "
268 "0x%8.8" PRIx32 "\n",
James Hendersonc2dfd502018-02-02 12:45:57 +0000269 HeaderData.Length, HeaderData.Version, HeaderData.AddrSize,
270 HeaderData.SegSize, HeaderData.OffsetEntryCount);
271
272 if (HeaderData.OffsetEntryCount > 0) {
273 OS << "Offsets: [";
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000274 for (const auto &Off : Offsets) {
James Henderson10392cd2018-02-05 10:47:13 +0000275 OS << format("\n0x%8.8" PRIx32, Off);
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000276 if (DumpOpts.Verbose)
277 OS << format(" => 0x%8.8" PRIx32,
278 Off + HeaderOffset + sizeof(HeaderData));
279 }
James Hendersonc2dfd502018-02-02 12:45:57 +0000280 OS << "\n]\n";
281 }
282 OS << "Ranges:\n";
283
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000284 // Determine the length of the longest encoding string we have in the table,
285 // so we can align the output properly. We only need this in verbose mode.
286 size_t MaxEncodingStringLength = 0;
287 if (DumpOpts.Verbose) {
288 for (const auto &List : Ranges)
289 for (const auto &Entry : List.second.getEntries())
290 MaxEncodingStringLength =
291 std::max(MaxEncodingStringLength,
292 dwarf::RangeListEncodingString(Entry.EntryKind).size());
293 }
294
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000295 uint64_t CurrentBase = 0;
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000296 for (const auto &List : Ranges)
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000297 for (const auto &Entry : List.second.getEntries())
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000298 dumpRangeEntry(OS, Entry, HeaderData.AddrSize, MaxEncodingStringLength,
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000299 CurrentBase, DumpOpts);
James Hendersonc2dfd502018-02-02 12:45:57 +0000300}
301
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000302uint32_t DWARFDebugRnglistTable::length() const {
James Hendersonc2dfd502018-02-02 12:45:57 +0000303 if (HeaderData.Length == 0)
304 return 0;
305 // TODO: DWARF64 support.
306 return HeaderData.Length + sizeof(uint32_t);
307}