1 //===- DWARFDebugRangesList.cpp -------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
10 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
11 #include "llvm/Support/Errc.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
isBaseAddressSelectionEntry(uint8_t AddressSize) const19 bool DWARFDebugRangeList::RangeListEntry::isBaseAddressSelectionEntry(
20 uint8_t AddressSize) const {
21 assert(DWARFContext::isAddressSizeSupported(AddressSize));
22 return StartAddress == dwarf::computeTombstoneAddress(AddressSize);
23 }
24
clear()25 void DWARFDebugRangeList::clear() {
26 Offset = -1ULL;
27 AddressSize = 0;
28 Entries.clear();
29 }
30
extract(const DWARFDataExtractor & data,uint64_t * offset_ptr)31 Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
32 uint64_t *offset_ptr) {
33 clear();
34 if (!data.isValidOffset(*offset_ptr))
35 return createStringError(errc::invalid_argument,
36 "invalid range list offset 0x%" PRIx64, *offset_ptr);
37
38 AddressSize = data.getAddressSize();
39 if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
40 AddressSize, errc::invalid_argument,
41 "range list at offset 0x%" PRIx64, *offset_ptr))
42 return SizeErr;
43 Offset = *offset_ptr;
44 while (true) {
45 RangeListEntry Entry;
46 Entry.SectionIndex = -1ULL;
47
48 uint64_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 createStringError(errc::invalid_argument,
57 "invalid range list entry at offset 0x%" PRIx64,
58 prev_offset);
59 }
60 if (Entry.isEndOfListEntry())
61 break;
62 Entries.push_back(Entry);
63 }
64 return Error::success();
65 }
66
dump(raw_ostream & OS) const67 void DWARFDebugRangeList::dump(raw_ostream &OS) const {
68 const char *AddrFmt;
69 switch (AddressSize) {
70 case 2:
71 AddrFmt = "%08" PRIx64 " %04" PRIx64 " %04" PRIx64 "\n";
72 break;
73 case 4:
74 AddrFmt = "%08" PRIx64 " %08" PRIx64 " %08" PRIx64 "\n";
75 break;
76 case 8:
77 AddrFmt = "%08" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n";
78 break;
79 default:
80 llvm_unreachable("unsupported address size");
81 }
82 for (const RangeListEntry &RLE : Entries)
83 OS << format(AddrFmt, Offset, RLE.StartAddress, RLE.EndAddress);
84 OS << format("%08" PRIx64 " <End of list>\n", Offset);
85 }
86
getAbsoluteRanges(std::optional<object::SectionedAddress> BaseAddr) const87 DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges(
88 std::optional<object::SectionedAddress> BaseAddr) const {
89 DWARFAddressRangesVector Res;
90 // debug_addr can't use the max integer tombstone because that's used for the
91 // base address specifier entry - so use max-1.
92 uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressSize) - 1;
93 for (const RangeListEntry &RLE : Entries) {
94 if (RLE.isBaseAddressSelectionEntry(AddressSize)) {
95 BaseAddr = {RLE.EndAddress, RLE.SectionIndex};
96 continue;
97 }
98
99 DWARFAddressRange E;
100 E.LowPC = RLE.StartAddress;
101 if (E.LowPC == Tombstone)
102 continue;
103 E.HighPC = RLE.EndAddress;
104 E.SectionIndex = RLE.SectionIndex;
105 // Base address of a range list entry is determined by the closest preceding
106 // base address selection entry in the same range list. It defaults to the
107 // base address of the compilation unit if there is no such entry.
108 if (BaseAddr) {
109 if (BaseAddr->Address == Tombstone)
110 continue;
111 E.LowPC += BaseAddr->Address;
112 E.HighPC += BaseAddr->Address;
113 if (E.SectionIndex == -1ULL)
114 E.SectionIndex = BaseAddr->SectionIndex;
115 }
116 Res.push_back(E);
117 }
118 return Res;
119 }
120