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/DWARFUnit.h"
12 #include "llvm/Support/Errc.h"
13 #include "llvm/Support/Error.h"
14 #include "llvm/Support/Format.h"
15 #include "llvm/Support/raw_ostream.h"
19 Error
RangeListEntry::extract(DWARFDataExtractor Data
, uint64_t End
,
20 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
< End
&&
26 "not enough space to extract a rangelist encoding");
27 uint8_t Encoding
= Data
.getU8(OffsetPtr
);
30 case dwarf::DW_RLE_end_of_list
:
33 // TODO: Support other encodings.
34 case dwarf::DW_RLE_base_addressx
: {
35 uint64_t PreviousOffset
= *OffsetPtr
- 1;
36 Value0
= Data
.getULEB128(OffsetPtr
);
38 return createStringError(
39 errc::invalid_argument
,
40 "read past end of table when reading "
41 "DW_RLE_base_addressx encoding at offset 0x%" PRIx64
,
45 case dwarf::DW_RLE_startx_endx
:
46 return createStringError(errc::not_supported
,
47 "unsupported rnglists encoding DW_RLE_startx_endx at "
50 case dwarf::DW_RLE_startx_length
: {
51 uint64_t PreviousOffset
= *OffsetPtr
- 1;
52 Value0
= Data
.getULEB128(OffsetPtr
);
53 Value1
= Data
.getULEB128(OffsetPtr
);
55 return createStringError(
56 errc::invalid_argument
,
57 "read past end of table when reading "
58 "DW_RLE_startx_length encoding at offset 0x%" PRIx64
,
62 case dwarf::DW_RLE_offset_pair
: {
63 uint64_t PreviousOffset
= *OffsetPtr
- 1;
64 Value0
= Data
.getULEB128(OffsetPtr
);
65 Value1
= Data
.getULEB128(OffsetPtr
);
67 return createStringError(errc::invalid_argument
,
68 "read past end of table when reading "
69 "DW_RLE_offset_pair encoding at offset 0x%" PRIx64
,
73 case dwarf::DW_RLE_base_address
: {
74 if ((End
- *OffsetPtr
) < Data
.getAddressSize())
75 return createStringError(errc::invalid_argument
,
76 "insufficient space remaining in table for "
77 "DW_RLE_base_address encoding at offset 0x%" PRIx64
,
79 Value0
= Data
.getRelocatedAddress(OffsetPtr
, &SectionIndex
);
82 case dwarf::DW_RLE_start_end
: {
83 if ((End
- *OffsetPtr
) < unsigned(Data
.getAddressSize() * 2))
84 return createStringError(errc::invalid_argument
,
85 "insufficient space remaining in table for "
86 "DW_RLE_start_end encoding "
87 "at offset 0x%" PRIx64
,
89 Value0
= Data
.getRelocatedAddress(OffsetPtr
, &SectionIndex
);
90 Value1
= Data
.getRelocatedAddress(OffsetPtr
);
93 case dwarf::DW_RLE_start_length
: {
94 uint64_t PreviousOffset
= *OffsetPtr
- 1;
95 Value0
= Data
.getRelocatedAddress(OffsetPtr
, &SectionIndex
);
96 Value1
= Data
.getULEB128(OffsetPtr
);
98 return createStringError(errc::invalid_argument
,
99 "read past end of table when reading "
100 "DW_RLE_start_length encoding at offset 0x%" PRIx64
,
105 return createStringError(errc::not_supported
,
106 "unknown rnglists encoding 0x%" PRIx32
107 " at offset 0x%" PRIx64
,
108 uint32_t(Encoding
), *OffsetPtr
- 1);
111 EntryKind
= Encoding
;
112 return Error::success();
115 DWARFAddressRangesVector
DWARFDebugRnglist::getAbsoluteRanges(
116 llvm::Optional
<object::SectionedAddress
> BaseAddr
, DWARFUnit
&U
) const {
117 DWARFAddressRangesVector Res
;
118 for (const RangeListEntry
&RLE
: Entries
) {
119 if (RLE
.EntryKind
== dwarf::DW_RLE_end_of_list
)
121 if (RLE
.EntryKind
== dwarf::DW_RLE_base_addressx
) {
122 BaseAddr
= U
.getAddrOffsetSectionItem(RLE
.Value0
);
124 BaseAddr
= {RLE
.Value0
, -1ULL};
127 if (RLE
.EntryKind
== dwarf::DW_RLE_base_address
) {
128 BaseAddr
= {RLE
.Value0
, RLE
.SectionIndex
};
133 E
.SectionIndex
= RLE
.SectionIndex
;
134 if (BaseAddr
&& E
.SectionIndex
== -1ULL)
135 E
.SectionIndex
= BaseAddr
->SectionIndex
;
137 switch (RLE
.EntryKind
) {
138 case dwarf::DW_RLE_offset_pair
:
139 E
.LowPC
= RLE
.Value0
;
140 E
.HighPC
= RLE
.Value1
;
142 E
.LowPC
+= BaseAddr
->Address
;
143 E
.HighPC
+= BaseAddr
->Address
;
146 case dwarf::DW_RLE_start_end
:
147 E
.LowPC
= RLE
.Value0
;
148 E
.HighPC
= RLE
.Value1
;
150 case dwarf::DW_RLE_start_length
:
151 E
.LowPC
= RLE
.Value0
;
152 E
.HighPC
= E
.LowPC
+ RLE
.Value1
;
154 case dwarf::DW_RLE_startx_length
: {
155 auto Start
= U
.getAddrOffsetSectionItem(RLE
.Value0
);
158 E
.SectionIndex
= Start
->SectionIndex
;
159 E
.LowPC
= Start
->Address
;
160 E
.HighPC
= E
.LowPC
+ RLE
.Value1
;
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");
173 void RangeListEntry::dump(
174 raw_ostream
&OS
, uint8_t AddrSize
, uint8_t MaxEncodingStringLength
,
175 uint64_t &CurrentBase
, DIDumpOptions DumpOpts
,
176 llvm::function_ref
<Optional
<object::SectionedAddress
>(uint32_t)>
177 LookupPooledAddress
) const {
178 auto PrintRawEntry
= [](raw_ostream
&OS
, const RangeListEntry
&Entry
,
179 uint8_t AddrSize
, DIDumpOptions DumpOpts
) {
180 if (DumpOpts
.Verbose
) {
181 DumpOpts
.DisplayRawContents
= true;
182 DWARFAddressRange(Entry
.Value0
, Entry
.Value1
)
183 .dump(OS
, AddrSize
, DumpOpts
);
188 if (DumpOpts
.Verbose
) {
189 // Print the section offset in verbose mode.
190 OS
<< format("0x%8.8" PRIx64
":", Offset
);
191 auto EncodingString
= dwarf::RangeListEncodingString(EntryKind
);
192 // Unsupported encodings should have been reported during parsing.
193 assert(!EncodingString
.empty() && "Unknown range entry encoding");
194 OS
<< format(" [%s%*c", EncodingString
.data(),
195 MaxEncodingStringLength
- EncodingString
.size() + 1, ']');
196 if (EntryKind
!= dwarf::DW_RLE_end_of_list
)
201 case dwarf::DW_RLE_end_of_list
:
202 OS
<< (DumpOpts
.Verbose
? "" : "<End of list>");
204 case dwarf::DW_RLE_base_addressx
: {
205 if (auto SA
= LookupPooledAddress(Value0
))
206 CurrentBase
= SA
->Address
;
208 CurrentBase
= Value0
;
209 if (!DumpOpts
.Verbose
)
211 OS
<< format(" 0x%*.*" PRIx64
, AddrSize
* 2, AddrSize
* 2, Value0
);
214 case dwarf::DW_RLE_base_address
:
215 // In non-verbose mode we do not print anything for this entry.
216 CurrentBase
= Value0
;
217 if (!DumpOpts
.Verbose
)
219 OS
<< format(" 0x%*.*" PRIx64
, AddrSize
* 2, AddrSize
* 2, Value0
);
221 case dwarf::DW_RLE_start_length
:
222 PrintRawEntry(OS
, *this, AddrSize
, DumpOpts
);
223 DWARFAddressRange(Value0
, Value0
+ Value1
).dump(OS
, AddrSize
, DumpOpts
);
225 case dwarf::DW_RLE_offset_pair
:
226 PrintRawEntry(OS
, *this, AddrSize
, DumpOpts
);
227 DWARFAddressRange(Value0
+ CurrentBase
, Value1
+ CurrentBase
)
228 .dump(OS
, AddrSize
, DumpOpts
);
230 case dwarf::DW_RLE_start_end
:
231 DWARFAddressRange(Value0
, Value1
).dump(OS
, AddrSize
, DumpOpts
);
233 case dwarf::DW_RLE_startx_length
: {
234 PrintRawEntry(OS
, *this, AddrSize
, DumpOpts
);
236 if (auto SA
= LookupPooledAddress(Value0
))
238 DWARFAddressRange(Start
, Start
+ Value1
).dump(OS
, AddrSize
, DumpOpts
);
242 llvm_unreachable("Unsupported range list encoding");