1 //===- DWARFDebugRangesList.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/DWARFDebugRangeList.h"
11 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
12 #include "llvm/Support/Format.h"
13 #include "llvm/Support/raw_ostream.h"
14 #include <cinttypes>
15 #include <cstdint>
16 
17 using namespace llvm;
18 
19 // FIXME: There are several versions of this. Consolidate them.
20 template <typename... Ts>
21 static Error createError(char const *Fmt, const Ts &... Vals) {
22   std::string Buffer;
23   raw_string_ostream Stream(Buffer);
24   Stream << format(Fmt, Vals...);
25   return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
26 }
27 
28 void DWARFDebugRangeList::clear() {
29   Offset = -1U;
30   AddressSize = 0;
31   Entries.clear();
32 }
33 
34 Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
35                                    uint32_t *offset_ptr) {
36   clear();
37   if (!data.isValidOffset(*offset_ptr))
38     return createError("invalid range list offset 0x%" PRIx32, *offset_ptr);
39 
40   AddressSize = data.getAddressSize();
41   if (AddressSize != 4 && AddressSize != 8)
42     return createError("invalid address size: %d", AddressSize);
43   Offset = *offset_ptr;
44   while (true) {
45     RangeListEntry Entry;
46     Entry.SectionIndex = -1ULL;
47 
48     uint32_t prev_offset = *offset_ptr;
49     Entry.StartAddress = data.getRelocatedAddress(offset_ptr);
50     Entry.EndAddress =
51         data.getRelocatedAddress(offset_ptr, &Entry.SectionIndex);
52 
53     // Check that both values were extracted correctly.
54     if (*offset_ptr != prev_offset + 2 * AddressSize) {
55       clear();
56       return createError("invalid range list entry at offset 0x%" PRIx32,
57                          prev_offset);
58     }
59     if (Entry.isEndOfListEntry())
60       break;
61     Entries.push_back(Entry);
62   }
63   return Error::success();
64 }
65 
66 void DWARFDebugRangeList::dump(raw_ostream &OS) const {
67   for (const RangeListEntry &RLE : Entries) {
68     const char *format_str = (AddressSize == 4
69                               ? "%08x %08"  PRIx64 " %08"  PRIx64 "\n"
70                               : "%08x %016" PRIx64 " %016" PRIx64 "\n");
71     OS << format(format_str, Offset, RLE.StartAddress, RLE.EndAddress);
72   }
73   OS << format("%08x <End of list>\n", Offset);
74 }
75 
76 DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges(
77     llvm::Optional<BaseAddress> BaseAddr) const {
78   DWARFAddressRangesVector Res;
79   for (const RangeListEntry &RLE : Entries) {
80     if (RLE.isBaseAddressSelectionEntry(AddressSize)) {
81       BaseAddr = {RLE.EndAddress, RLE.SectionIndex};
82       continue;
83     }
84 
85     DWARFAddressRange E;
86     E.LowPC = RLE.StartAddress;
87     E.HighPC = RLE.EndAddress;
88     E.SectionIndex = RLE.SectionIndex;
89     // Base address of a range list entry is determined by the closest preceding
90     // base address selection entry in the same range list. It defaults to the
91     // base address of the compilation unit if there is no such entry.
92     if (BaseAddr) {
93       E.LowPC += BaseAddr->Address;
94       E.HighPC += BaseAddr->Address;
95       if (E.SectionIndex == -1ULL)
96         E.SectionIndex = BaseAddr->SectionIndex;
97     }
98     Res.push_back(E);
99   }
100   return Res;
101 }
102