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
17using namespace llvm;
18
19bool DWARFDebugRangeList::RangeListEntry::isBaseAddressSelectionEntry(
20 uint8_t AddressSize) const {
21 assert(DWARFContext::isAddressSizeSupported(AddressSize));
22 return StartAddress == dwarf::computeTombstoneAddress(AddressByteSize: AddressSize);
23}
24
25void DWARFDebugRangeList::clear() {
26 Offset = -1ULL;
27 AddressSize = 0;
28 Entries.clear();
29}
30
31Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
32 uint64_t *offset_ptr) {
33 clear();
34 if (!data.isValidOffset(offset: *offset_ptr))
35 return createStringError(EC: errc::invalid_argument,
36 Fmt: "invalid range list offset 0x%" PRIx64, Vals: *offset_ptr);
37
38 AddressSize = data.getAddressSize();
39 if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
40 AddressSize, EC: errc::invalid_argument,
41 Fmt: "range list at offset 0x%" PRIx64, Vals: *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(Off: offset_ptr);
50 Entry.EndAddress =
51 data.getRelocatedAddress(Off: offset_ptr, SecIx: &Entry.SectionIndex);
52
53 // Check that both values were extracted correctly.
54 if (*offset_ptr != prev_offset + 2 * AddressSize) {
55 clear();
56 return createStringError(EC: errc::invalid_argument,
57 Fmt: "invalid range list entry at offset 0x%" PRIx64,
58 Vals: prev_offset);
59 }
60 if (Entry.isEndOfListEntry())
61 break;
62 Entries.push_back(x: Entry);
63 }
64 return Error::success();
65}
66
67void 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(Fmt: AddrFmt, Vals: Offset, Vals: RLE.StartAddress, Vals: RLE.EndAddress);
84 OS << format(Fmt: "%08" PRIx64 " <End of list>\n", Vals: Offset);
85}
86
87DWARFAddressRangesVector 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(AddressByteSize: AddressSize) - 1;
93 for (const RangeListEntry &RLE : Entries) {
94 if (RLE.isBaseAddressSelectionEntry(AddressSize)) {
95 BaseAddr = {.Address: RLE.EndAddress, .SectionIndex: 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(x: E);
117 }
118 return Res;
119}
120