1 //===- DWARFDebugRnglists.cpp ---------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
10 #include "llvm/BinaryFormat/Dwarf.h"
11 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
12 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
13 #include "llvm/Support/Errc.h"
14 #include "llvm/Support/Error.h"
15 #include "llvm/Support/Format.h"
16 #include "llvm/Support/raw_ostream.h"
20 Error
RangeListEntry::extract(DWARFDataExtractor Data
, uint64_t *OffsetPtr
) {
23 // The caller should guarantee that we have at least 1 byte available, so
24 // we just assert instead of revalidate.
25 assert(*OffsetPtr
< Data
.size() &&
26 "not enough space to extract a rangelist encoding");
27 uint8_t Encoding
= Data
.getU8(OffsetPtr
);
29 DataExtractor::Cursor
C(*OffsetPtr
);
31 case dwarf::DW_RLE_end_of_list
:
34 // TODO: Support other encodings.
35 case dwarf::DW_RLE_base_addressx
: {
36 Value0
= Data
.getULEB128(C
);
39 case dwarf::DW_RLE_startx_endx
:
40 Value0
= Data
.getULEB128(C
);
41 Value1
= Data
.getULEB128(C
);
43 case dwarf::DW_RLE_startx_length
: {
44 Value0
= Data
.getULEB128(C
);
45 Value1
= Data
.getULEB128(C
);
48 case dwarf::DW_RLE_offset_pair
: {
49 Value0
= Data
.getULEB128(C
);
50 Value1
= Data
.getULEB128(C
);
53 case dwarf::DW_RLE_base_address
: {
54 Value0
= Data
.getRelocatedAddress(C
, &SectionIndex
);
57 case dwarf::DW_RLE_start_end
: {
58 Value0
= Data
.getRelocatedAddress(C
, &SectionIndex
);
59 Value1
= Data
.getRelocatedAddress(C
);
62 case dwarf::DW_RLE_start_length
: {
63 Value0
= Data
.getRelocatedAddress(C
, &SectionIndex
);
64 Value1
= Data
.getULEB128(C
);
68 consumeError(C
.takeError());
69 return createStringError(errc::not_supported
,
70 "unknown rnglists encoding 0x%" PRIx32
71 " at offset 0x%" PRIx64
,
72 uint32_t(Encoding
), Offset
);
76 consumeError(C
.takeError());
77 return createStringError(
78 errc::invalid_argument
,
79 "read past end of table when reading %s encoding at offset 0x%" PRIx64
,
80 dwarf::RLEString(Encoding
).data(), Offset
);
83 *OffsetPtr
= C
.tell();
85 return Error::success();
88 DWARFAddressRangesVector
DWARFDebugRnglist::getAbsoluteRanges(
89 std::optional
<object::SectionedAddress
> BaseAddr
, DWARFUnit
&U
) const {
90 return getAbsoluteRanges(
91 BaseAddr
, U
.getAddressByteSize(),
92 [&](uint32_t Index
) { return U
.getAddrOffsetSectionItem(Index
); });
95 DWARFAddressRangesVector
DWARFDebugRnglist::getAbsoluteRanges(
96 std::optional
<object::SectionedAddress
> BaseAddr
, uint8_t AddressByteSize
,
97 function_ref
<std::optional
<object::SectionedAddress
>(uint32_t)>
98 LookupPooledAddress
) const {
99 DWARFAddressRangesVector Res
;
100 uint64_t Tombstone
= dwarf::computeTombstoneAddress(AddressByteSize
);
101 for (const RangeListEntry
&RLE
: Entries
) {
102 if (RLE
.EntryKind
== dwarf::DW_RLE_end_of_list
)
104 if (RLE
.EntryKind
== dwarf::DW_RLE_base_addressx
) {
105 BaseAddr
= LookupPooledAddress(RLE
.Value0
);
107 BaseAddr
= {RLE
.Value0
, -1ULL};
110 if (RLE
.EntryKind
== dwarf::DW_RLE_base_address
) {
111 BaseAddr
= {RLE
.Value0
, RLE
.SectionIndex
};
116 E
.SectionIndex
= RLE
.SectionIndex
;
117 if (BaseAddr
&& E
.SectionIndex
== -1ULL)
118 E
.SectionIndex
= BaseAddr
->SectionIndex
;
120 switch (RLE
.EntryKind
) {
121 case dwarf::DW_RLE_offset_pair
:
122 E
.LowPC
= RLE
.Value0
;
123 if (E
.LowPC
== Tombstone
)
125 E
.HighPC
= RLE
.Value1
;
127 if (BaseAddr
->Address
== Tombstone
)
129 E
.LowPC
+= BaseAddr
->Address
;
130 E
.HighPC
+= BaseAddr
->Address
;
133 case dwarf::DW_RLE_start_end
:
134 E
.LowPC
= RLE
.Value0
;
135 E
.HighPC
= RLE
.Value1
;
137 case dwarf::DW_RLE_start_length
:
138 E
.LowPC
= RLE
.Value0
;
139 E
.HighPC
= E
.LowPC
+ RLE
.Value1
;
141 case dwarf::DW_RLE_startx_length
: {
142 auto Start
= LookupPooledAddress(RLE
.Value0
);
145 E
.SectionIndex
= Start
->SectionIndex
;
146 E
.LowPC
= Start
->Address
;
147 E
.HighPC
= E
.LowPC
+ RLE
.Value1
;
150 case dwarf::DW_RLE_startx_endx
: {
151 auto Start
= LookupPooledAddress(RLE
.Value0
);
154 auto End
= LookupPooledAddress(RLE
.Value1
);
157 // FIXME: Some error handling if Start.SectionIndex != End.SectionIndex
158 E
.SectionIndex
= Start
->SectionIndex
;
159 E
.LowPC
= Start
->Address
;
160 E
.HighPC
= End
->Address
;
164 // Unsupported encodings should have been reported during extraction,
165 // so we should not run into any here.
166 llvm_unreachable("Unsupported range list encoding");
168 if (E
.LowPC
== Tombstone
)
175 void RangeListEntry::dump(
176 raw_ostream
&OS
, uint8_t AddrSize
, uint8_t MaxEncodingStringLength
,
177 uint64_t &CurrentBase
, DIDumpOptions DumpOpts
,
178 llvm::function_ref
<std::optional
<object::SectionedAddress
>(uint32_t)>
179 LookupPooledAddress
) const {
180 auto PrintRawEntry
= [](raw_ostream
&OS
, const RangeListEntry
&Entry
,
181 uint8_t AddrSize
, DIDumpOptions DumpOpts
) {
182 if (DumpOpts
.Verbose
) {
183 DumpOpts
.DisplayRawContents
= true;
184 DWARFAddressRange(Entry
.Value0
, Entry
.Value1
)
185 .dump(OS
, AddrSize
, DumpOpts
);
190 if (DumpOpts
.Verbose
) {
191 // Print the section offset in verbose mode.
192 OS
<< format("0x%8.8" PRIx64
":", Offset
);
193 auto EncodingString
= dwarf::RangeListEncodingString(EntryKind
);
194 // Unsupported encodings should have been reported during parsing.
195 assert(!EncodingString
.empty() && "Unknown range entry encoding");
196 OS
<< format(" [%s%*c", EncodingString
.data(),
197 MaxEncodingStringLength
- EncodingString
.size() + 1, ']');
198 if (EntryKind
!= dwarf::DW_RLE_end_of_list
)
202 uint64_t Tombstone
= dwarf::computeTombstoneAddress(AddrSize
);
205 case dwarf::DW_RLE_end_of_list
:
206 OS
<< (DumpOpts
.Verbose
? "" : "<End of list>");
208 case dwarf::DW_RLE_base_addressx
: {
209 if (auto SA
= LookupPooledAddress(Value0
))
210 CurrentBase
= SA
->Address
;
212 CurrentBase
= Value0
;
213 if (!DumpOpts
.Verbose
)
215 DWARFFormValue::dumpAddress(OS
<< ' ', AddrSize
, Value0
);
218 case dwarf::DW_RLE_base_address
:
219 // In non-verbose mode we do not print anything for this entry.
220 CurrentBase
= Value0
;
221 if (!DumpOpts
.Verbose
)
223 DWARFFormValue::dumpAddress(OS
<< ' ', AddrSize
, Value0
);
225 case dwarf::DW_RLE_start_length
:
226 PrintRawEntry(OS
, *this, AddrSize
, DumpOpts
);
227 DWARFAddressRange(Value0
, Value0
+ Value1
).dump(OS
, AddrSize
, DumpOpts
);
229 case dwarf::DW_RLE_offset_pair
:
230 PrintRawEntry(OS
, *this, AddrSize
, DumpOpts
);
231 if (CurrentBase
!= Tombstone
)
232 DWARFAddressRange(Value0
+ CurrentBase
, Value1
+ CurrentBase
)
233 .dump(OS
, AddrSize
, DumpOpts
);
237 case dwarf::DW_RLE_start_end
:
238 DWARFAddressRange(Value0
, Value1
).dump(OS
, AddrSize
, DumpOpts
);
240 case dwarf::DW_RLE_startx_length
: {
241 PrintRawEntry(OS
, *this, AddrSize
, DumpOpts
);
243 if (auto SA
= LookupPooledAddress(Value0
))
245 DWARFAddressRange(Start
, Start
+ Value1
).dump(OS
, AddrSize
, DumpOpts
);
248 case dwarf::DW_RLE_startx_endx
: {
249 PrintRawEntry(OS
, *this, AddrSize
, DumpOpts
);
251 if (auto SA
= LookupPooledAddress(Value0
))
254 if (auto SA
= LookupPooledAddress(Value1
))
256 DWARFAddressRange(Start
, End
).dump(OS
, AddrSize
, DumpOpts
);
260 llvm_unreachable("Unsupported range list encoding");