blob: 533b0922c1d126bc6e75505e2963034c4956fe23 [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"
James Hendersonc2dfd502018-02-02 12:45:57 +000011#include "llvm/BinaryFormat/Dwarf.h"
Wolfgang Piebad605592018-05-18 20:12:54 +000012#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
James Hendersonc2dfd502018-02-02 12:45:57 +000013#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);
Wolfgang Piebad605592018-05-18 20:12:54 +000047 Format = dwarf::DwarfFormat::DWARF32;
James Hendersonc2dfd502018-02-02 12:45:57 +000048 if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header))
49 return createError(".debug_rnglists table at offset 0x%" PRIx32
50 " has too small length (0x%" PRIx32
51 ") to contain a complete header",
Wolfgang Pieba0729d42018-03-08 20:52:35 +000052 HeaderOffset, length());
53 uint32_t End = HeaderOffset + length();
54 if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset))
James Hendersonc2dfd502018-02-02 12:45:57 +000055 return createError(
56 "section is not large enough to contain a .debug_rnglists table "
57 "of length 0x%" PRIx32 " at offset 0x%" PRIx32,
Wolfgang Pieba0729d42018-03-08 20:52:35 +000058 length(), HeaderOffset);
James Hendersonc2dfd502018-02-02 12:45:57 +000059
60 HeaderData.Version = Data.getU16(OffsetPtr);
61 HeaderData.AddrSize = Data.getU8(OffsetPtr);
62 HeaderData.SegSize = Data.getU8(OffsetPtr);
63 HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr);
64
65 // Perform basic validation of the remaining header fields.
66 if (HeaderData.Version != 5)
67 return createError("unrecognised .debug_rnglists table version %" PRIu16
68 " in table at offset 0x%" PRIx32,
Wolfgang Pieba0729d42018-03-08 20:52:35 +000069 HeaderData.Version, HeaderOffset);
James Hendersonc2dfd502018-02-02 12:45:57 +000070 if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
71 return createError(".debug_rnglists table at offset 0x%" PRIx32
72 " has unsupported address size %hhu",
Wolfgang Pieba0729d42018-03-08 20:52:35 +000073 HeaderOffset, HeaderData.AddrSize);
James Hendersonc2dfd502018-02-02 12:45:57 +000074 if (HeaderData.SegSize != 0)
75 return createError(".debug_rnglists table at offset 0x%" PRIx32
76 " has unsupported segment selector size %" PRIu8,
Wolfgang Pieba0729d42018-03-08 20:52:35 +000077 HeaderOffset, HeaderData.SegSize);
78 if (End < HeaderOffset + sizeof(HeaderData) +
James Hendersonc2dfd502018-02-02 12:45:57 +000079 HeaderData.OffsetEntryCount * sizeof(uint32_t))
80 return createError(".debug_rnglists table at offset 0x%" PRIx32
81 " has more offset entries (%" PRIu32
82 ") than there is space for",
Wolfgang Pieba0729d42018-03-08 20:52:35 +000083 HeaderOffset, HeaderData.OffsetEntryCount);
James Hendersonc2dfd502018-02-02 12:45:57 +000084 Data.setAddressSize(HeaderData.AddrSize);
James Hendersonc2dfd502018-02-02 12:45:57 +000085 for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I)
86 Offsets.push_back(Data.getU32(OffsetPtr));
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +000087 return Error::success();
88}
James Hendersonc2dfd502018-02-02 12:45:57 +000089
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +000090Error DWARFDebugRnglist::RangeListEntry::extract(DWARFDataExtractor Data,
91 uint32_t End,
92 uint32_t *OffsetPtr) {
93 Offset = *OffsetPtr;
Wolfgang Piebad605592018-05-18 20:12:54 +000094 SectionIndex = -1ULL;
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +000095 // The caller should guarantee that we have at least 1 byte available, so
96 // we just assert instead of revalidate.
97 assert(*OffsetPtr < End &&
98 "not enough space to extract a rangelist encoding");
99 uint8_t Encoding = Data.getU8(OffsetPtr);
100
101 switch (Encoding) {
102 case dwarf::DW_RLE_end_of_list:
103 Value0 = Value1 = 0;
104 break;
105 // TODO: Support other encodings.
106 case dwarf::DW_RLE_base_addressx:
107 return createError("unsupported rnglists encoding DW_RLE_base_addressx "
108 "at offset 0x%" PRIx32,
109 *OffsetPtr - 1);
110 case dwarf::DW_RLE_startx_endx:
111 return createError("unsupported rnglists encoding DW_RLE_startx_endx at "
112 "offset 0x%" PRIx32,
113 *OffsetPtr - 1);
114 case dwarf::DW_RLE_startx_length:
115 return createError("unsupported rnglists encoding DW_RLE_startx_length "
116 "at offset 0x%" PRIx32,
117 *OffsetPtr - 1);
118 case dwarf::DW_RLE_offset_pair: {
119 uint32_t PreviousOffset = *OffsetPtr - 1;
120 Value0 = Data.getULEB128(OffsetPtr);
121 Value1 = Data.getULEB128(OffsetPtr);
122 if (End < *OffsetPtr)
123 return createError("read past end of table when reading "
124 "DW_RLE_offset_pair encoding at offset 0x%" PRIx32,
125 PreviousOffset);
126 break;
127 }
128 case dwarf::DW_RLE_base_address: {
129 if ((End - *OffsetPtr) < Data.getAddressSize())
130 return createError("insufficient space remaining in table for "
131 "DW_RLE_base_address encoding at offset 0x%" PRIx32,
132 *OffsetPtr - 1);
Wolfgang Piebad605592018-05-18 20:12:54 +0000133 Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000134 break;
135 }
136 case dwarf::DW_RLE_start_end: {
137 if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2))
138 return createError("insufficient space remaining in table for "
139 "DW_RLE_start_end encoding "
James Hendersonc2dfd502018-02-02 12:45:57 +0000140 "at offset 0x%" PRIx32,
141 *OffsetPtr - 1);
Wolfgang Piebad605592018-05-18 20:12:54 +0000142 Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
143 Value1 = Data.getRelocatedAddress(OffsetPtr);
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000144 break;
145 }
146 case dwarf::DW_RLE_start_length: {
147 uint32_t PreviousOffset = *OffsetPtr - 1;
Wolfgang Piebad605592018-05-18 20:12:54 +0000148 Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000149 Value1 = Data.getULEB128(OffsetPtr);
150 if (End < *OffsetPtr)
151 return createError("read past end of table when reading "
152 "DW_RLE_start_length encoding at offset 0x%" PRIx32,
153 PreviousOffset);
154 break;
155 }
156 default:
157 return createError("unknown rnglists encoding 0x%" PRIx32
158 " at offset 0x%" PRIx32,
159 uint32_t(Encoding), *OffsetPtr - 1);
James Hendersonc2dfd502018-02-02 12:45:57 +0000160 }
161
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000162 EntryKind = Encoding;
163 return Error::success();
164}
James Hendersonc2dfd502018-02-02 12:45:57 +0000165
Wolfgang Piebad605592018-05-18 20:12:54 +0000166DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
167 llvm::Optional<BaseAddress> BaseAddr) const {
168 DWARFAddressRangesVector Res;
169 for (const RangeListEntry &RLE : Entries) {
170 if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
171 break;
172 if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
173 BaseAddr = {RLE.Value0, RLE.SectionIndex};
174 continue;
175 }
176
177 DWARFAddressRange E;
178 E.SectionIndex = RLE.SectionIndex;
179 if (BaseAddr && E.SectionIndex == -1ULL)
180 E.SectionIndex = BaseAddr->SectionIndex;
181
182 switch (RLE.EntryKind) {
183 case dwarf::DW_RLE_offset_pair:
184 E.LowPC = RLE.Value0;
185 E.HighPC = RLE.Value1;
186 if (BaseAddr) {
187 E.LowPC += BaseAddr->Address;
188 E.HighPC += BaseAddr->Address;
189 }
190 break;
191 case dwarf::DW_RLE_start_end:
192 E.LowPC = RLE.Value0;
193 E.HighPC = RLE.Value1;
194 break;
195 case dwarf::DW_RLE_start_length:
196 E.LowPC = RLE.Value0;
197 E.HighPC = E.LowPC + RLE.Value1;
198 break;
199 default:
200 // Unsupported encodings should have been reported during extraction,
201 // so we should not run into any here.
202 llvm_unreachable("Unsupported range list encoding");
203 }
204 Res.push_back(E);
205 }
206 return Res;
207}
208
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000209Error DWARFDebugRnglist::extract(DWARFDataExtractor Data, uint32_t HeaderOffset,
210 uint32_t End, uint32_t *OffsetPtr) {
Wolfgang Pieb61d8c8d2018-06-20 22:56:37 +0000211 if (*OffsetPtr < HeaderOffset || *OffsetPtr >= End)
212 return createError("invalid range list offset 0x%" PRIx32, *OffsetPtr);
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000213 Entries.clear();
214 while (*OffsetPtr < End) {
Wolfgang Pieb20e15462018-05-18 21:44:28 +0000215 RangeListEntry Entry{0, 0, 0, 0, 0};
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000216 if (Error E = Entry.extract(Data, End, OffsetPtr))
217 return E;
218 Entries.push_back(Entry);
219 if (Entry.EntryKind == dwarf::DW_RLE_end_of_list)
220 return Error::success();
221 }
222 return createError(
223 "no end of list marker detected at end of .debug_rnglists table "
224 "starting at offset 0x%" PRIx32,
225 HeaderOffset);
226}
227
228Error DWARFDebugRnglistTable::extract(DWARFDataExtractor Data,
229 uint32_t *OffsetPtr) {
230 clear();
231 if (Error E = extractHeaderAndOffsets(Data, OffsetPtr))
232 return E;
233
234 Data.setAddressSize(HeaderData.AddrSize);
235 uint32_t End = HeaderOffset + length();
236 while (*OffsetPtr < End) {
237 DWARFDebugRnglist CurrentRangeList;
238 uint32_t Off = *OffsetPtr;
239 if (Error E = CurrentRangeList.extract(Data, HeaderOffset, End, OffsetPtr))
240 return E;
241 Ranges[Off] = CurrentRangeList;
242 }
243
244 assert(*OffsetPtr == End &&
245 "mismatch between expected length of .debug_rnglists table and length "
246 "of extracted data");
James Hendersonc2dfd502018-02-02 12:45:57 +0000247 return Error::success();
248}
249
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000250static void dumpRangeEntry(raw_ostream &OS,
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000251 DWARFDebugRnglist::RangeListEntry Entry,
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000252 uint8_t AddrSize, uint8_t MaxEncodingStringLength,
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000253 uint64_t &CurrentBase, DIDumpOptions DumpOpts) {
254 auto PrintRawEntry = [](raw_ostream &OS,
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000255 DWARFDebugRnglist::RangeListEntry Entry,
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000256 uint8_t AddrSize, DIDumpOptions DumpOpts) {
257 if (DumpOpts.Verbose) {
258 DumpOpts.DisplayRawContents = true;
259 DWARFAddressRange(Entry.Value0, Entry.Value1)
260 .dump(OS, AddrSize, DumpOpts);
261 OS << " => ";
262 }
263 };
264
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000265 if (DumpOpts.Verbose) {
266 // Print the section offset in verbose mode.
267 OS << format("0x%8.8" PRIx32 ":", Entry.Offset);
268 auto EncodingString = dwarf::RangeListEncodingString(Entry.EntryKind);
269 // Unsupported encodings should have been reported during parsing.
270 assert(!EncodingString.empty() && "Unknown range entry encoding");
271 OS << format(" [%s%*c", EncodingString.data(),
272 MaxEncodingStringLength - EncodingString.size() + 1, ']');
273 if (Entry.EntryKind != dwarf::DW_RLE_end_of_list)
274 OS << ": ";
275 }
276
277 switch (Entry.EntryKind) {
278 case dwarf::DW_RLE_end_of_list:
279 OS << (DumpOpts.Verbose ? "" : "<End of list>");
280 break;
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000281 case dwarf::DW_RLE_base_address:
282 // In non-verbose mode we do not print anything for this entry.
283 CurrentBase = Entry.Value0;
284 if (!DumpOpts.Verbose)
285 return;
286 OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Entry.Value0);
287 break;
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000288 case dwarf::DW_RLE_start_length:
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000289 PrintRawEntry(OS, Entry, AddrSize, DumpOpts);
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000290 DWARFAddressRange(Entry.Value0, Entry.Value0 + Entry.Value1)
291 .dump(OS, AddrSize, DumpOpts);
292 break;
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000293 case dwarf::DW_RLE_offset_pair:
294 PrintRawEntry(OS, Entry, AddrSize, DumpOpts);
295 DWARFAddressRange(Entry.Value0 + CurrentBase, Entry.Value1 + CurrentBase)
296 .dump(OS, AddrSize, DumpOpts);
297 break;
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000298 case dwarf::DW_RLE_start_end:
299 DWARFAddressRange(Entry.Value0, Entry.Value1).dump(OS, AddrSize, DumpOpts);
300 break;
301 default:
302 llvm_unreachable("Unsupported range list encoding");
303 }
304 OS << "\n";
305}
306
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000307void DWARFDebugRnglistTable::dump(raw_ostream &OS,
308 DIDumpOptions DumpOpts) const {
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000309 if (DumpOpts.Verbose)
310 OS << format("0x%8.8" PRIx32 ": ", HeaderOffset);
James Henderson10392cd2018-02-05 10:47:13 +0000311 OS << format("Range List Header: length = 0x%8.8" PRIx32
312 ", version = 0x%4.4" PRIx16 ", "
313 "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8
314 ", offset_entry_count = "
315 "0x%8.8" PRIx32 "\n",
James Hendersonc2dfd502018-02-02 12:45:57 +0000316 HeaderData.Length, HeaderData.Version, HeaderData.AddrSize,
317 HeaderData.SegSize, HeaderData.OffsetEntryCount);
318
319 if (HeaderData.OffsetEntryCount > 0) {
320 OS << "Offsets: [";
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000321 for (const auto &Off : Offsets) {
James Henderson10392cd2018-02-05 10:47:13 +0000322 OS << format("\n0x%8.8" PRIx32, Off);
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000323 if (DumpOpts.Verbose)
324 OS << format(" => 0x%8.8" PRIx32,
325 Off + HeaderOffset + sizeof(HeaderData));
326 }
James Hendersonc2dfd502018-02-02 12:45:57 +0000327 OS << "\n]\n";
328 }
329 OS << "Ranges:\n";
330
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000331 // Determine the length of the longest encoding string we have in the table,
332 // so we can align the output properly. We only need this in verbose mode.
333 size_t MaxEncodingStringLength = 0;
334 if (DumpOpts.Verbose) {
335 for (const auto &List : Ranges)
336 for (const auto &Entry : List.second.getEntries())
337 MaxEncodingStringLength =
338 std::max(MaxEncodingStringLength,
339 dwarf::RangeListEncodingString(Entry.EntryKind).size());
340 }
341
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000342 uint64_t CurrentBase = 0;
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000343 for (const auto &List : Ranges)
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000344 for (const auto &Entry : List.second.getEntries())
Wolfgang Pieba0729d42018-03-08 20:52:35 +0000345 dumpRangeEntry(OS, Entry, HeaderData.AddrSize, MaxEncodingStringLength,
Wolfgang Piebab068ea2018-03-27 20:27:36 +0000346 CurrentBase, DumpOpts);
James Hendersonc2dfd502018-02-02 12:45:57 +0000347}
348
Wolfgang Pieb3fb9e3f2018-04-05 21:01:49 +0000349uint32_t DWARFDebugRnglistTable::length() const {
James Hendersonc2dfd502018-02-02 12:45:57 +0000350 if (HeaderData.Length == 0)
351 return 0;
352 // TODO: DWARF64 support.
353 return HeaderData.Length + sizeof(uint32_t);
354}
Wolfgang Piebad605592018-05-18 20:12:54 +0000355
Wolfgang Pieb61d8c8d2018-06-20 22:56:37 +0000356Expected<DWARFDebugRnglist>
Wolfgang Piebad605592018-05-18 20:12:54 +0000357DWARFDebugRnglistTable::findRangeList(DWARFDataExtractor Data,
358 uint32_t Offset) {
359 auto Entry = Ranges.find(Offset);
360 if (Entry != Ranges.end())
361 return Entry->second;
362
363 // Extract the rangelist from the section and enter it into the ranges map.
364 DWARFDebugRnglist RngList;
365 uint32_t End = HeaderOffset + length();
366 uint32_t StartingOffset = Offset;
Wolfgang Pieb61d8c8d2018-06-20 22:56:37 +0000367 if (Error E = RngList.extract(Data, HeaderOffset, End, &Offset))
368 return std::move(E);
Wolfgang Piebad605592018-05-18 20:12:54 +0000369 Ranges[StartingOffset] = RngList;
370 return RngList;
371}