1 //===- DWARFDebugRnglists.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/DWARFDebugRnglists.h"
11 #include "llvm/BinaryFormat/Dwarf.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"
17
18 using namespace llvm;
19
extract(DWARFDataExtractor Data,uint32_t End,uint32_t * OffsetPtr)20 Error RangeListEntry::extract(DWARFDataExtractor Data, uint32_t End,
21 uint32_t *OffsetPtr) {
22 Offset = *OffsetPtr;
23 SectionIndex = -1ULL;
24 // The caller should guarantee that we have at least 1 byte available, so
25 // we just assert instead of revalidate.
26 assert(*OffsetPtr < End &&
27 "not enough space to extract a rangelist encoding");
28 uint8_t Encoding = Data.getU8(OffsetPtr);
29
30 switch (Encoding) {
31 case dwarf::DW_RLE_end_of_list:
32 Value0 = Value1 = 0;
33 break;
34 // TODO: Support other encodings.
35 case dwarf::DW_RLE_base_addressx: {
36 uint32_t PreviousOffset = *OffsetPtr - 1;
37 Value0 = Data.getULEB128(OffsetPtr);
38 if (End < *OffsetPtr)
39 return createStringError(
40 errc::invalid_argument,
41 "read past end of table when reading "
42 "DW_RLE_base_addressx encoding at offset 0x%" PRIx32,
43 PreviousOffset);
44 break;
45 }
46 case dwarf::DW_RLE_startx_endx:
47 return createStringError(errc::not_supported,
48 "unsupported rnglists encoding DW_RLE_startx_endx at "
49 "offset 0x%" PRIx32,
50 *OffsetPtr - 1);
51 case dwarf::DW_RLE_startx_length: {
52 uint32_t PreviousOffset = *OffsetPtr - 1;
53 Value0 = Data.getULEB128(OffsetPtr);
54 Value1 = Data.getULEB128(OffsetPtr);
55 if (End < *OffsetPtr)
56 return createStringError(
57 errc::invalid_argument,
58 "read past end of table when reading "
59 "DW_RLE_startx_length encoding at offset 0x%" PRIx32,
60 PreviousOffset);
61 break;
62 }
63 case dwarf::DW_RLE_offset_pair: {
64 uint32_t PreviousOffset = *OffsetPtr - 1;
65 Value0 = Data.getULEB128(OffsetPtr);
66 Value1 = Data.getULEB128(OffsetPtr);
67 if (End < *OffsetPtr)
68 return createStringError(errc::invalid_argument,
69 "read past end of table when reading "
70 "DW_RLE_offset_pair encoding at offset 0x%" PRIx32,
71 PreviousOffset);
72 break;
73 }
74 case dwarf::DW_RLE_base_address: {
75 if ((End - *OffsetPtr) < Data.getAddressSize())
76 return createStringError(errc::invalid_argument,
77 "insufficient space remaining in table for "
78 "DW_RLE_base_address encoding at offset 0x%" PRIx32,
79 *OffsetPtr - 1);
80 Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
81 break;
82 }
83 case dwarf::DW_RLE_start_end: {
84 if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2))
85 return createStringError(errc::invalid_argument,
86 "insufficient space remaining in table for "
87 "DW_RLE_start_end encoding "
88 "at offset 0x%" PRIx32,
89 *OffsetPtr - 1);
90 Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
91 Value1 = Data.getRelocatedAddress(OffsetPtr);
92 break;
93 }
94 case dwarf::DW_RLE_start_length: {
95 uint32_t PreviousOffset = *OffsetPtr - 1;
96 Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
97 Value1 = Data.getULEB128(OffsetPtr);
98 if (End < *OffsetPtr)
99 return createStringError(errc::invalid_argument,
100 "read past end of table when reading "
101 "DW_RLE_start_length encoding at offset 0x%" PRIx32,
102 PreviousOffset);
103 break;
104 }
105 default:
106 return createStringError(errc::not_supported,
107 "unknown rnglists encoding 0x%" PRIx32
108 " at offset 0x%" PRIx32,
109 uint32_t(Encoding), *OffsetPtr - 1);
110 }
111
112 EntryKind = Encoding;
113 return Error::success();
114 }
115
116 DWARFAddressRangesVector
getAbsoluteRanges(llvm::Optional<SectionedAddress> BaseAddr,DWARFUnit & U) const117 DWARFDebugRnglist::getAbsoluteRanges(llvm::Optional<SectionedAddress> BaseAddr,
118 DWARFUnit &U) const {
119 DWARFAddressRangesVector Res;
120 for (const RangeListEntry &RLE : Entries) {
121 if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
122 break;
123 if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) {
124 BaseAddr = U.getAddrOffsetSectionItem(RLE.Value0);
125 if (!BaseAddr)
126 BaseAddr = {RLE.Value0, -1ULL};
127 continue;
128 }
129 if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
130 BaseAddr = {RLE.Value0, RLE.SectionIndex};
131 continue;
132 }
133
134 DWARFAddressRange E;
135 E.SectionIndex = RLE.SectionIndex;
136 if (BaseAddr && E.SectionIndex == -1ULL)
137 E.SectionIndex = BaseAddr->SectionIndex;
138
139 switch (RLE.EntryKind) {
140 case dwarf::DW_RLE_offset_pair:
141 E.LowPC = RLE.Value0;
142 E.HighPC = RLE.Value1;
143 if (BaseAddr) {
144 E.LowPC += BaseAddr->Address;
145 E.HighPC += BaseAddr->Address;
146 }
147 break;
148 case dwarf::DW_RLE_start_end:
149 E.LowPC = RLE.Value0;
150 E.HighPC = RLE.Value1;
151 break;
152 case dwarf::DW_RLE_start_length:
153 E.LowPC = RLE.Value0;
154 E.HighPC = E.LowPC + RLE.Value1;
155 break;
156 case dwarf::DW_RLE_startx_length: {
157 auto Start = U.getAddrOffsetSectionItem(RLE.Value0);
158 if (!Start)
159 Start = {0, -1ULL};
160 E.SectionIndex = Start->SectionIndex;
161 E.LowPC = Start->Address;
162 E.HighPC = E.LowPC + RLE.Value1;
163 break;
164 }
165 default:
166 // Unsupported encodings should have been reported during extraction,
167 // so we should not run into any here.
168 llvm_unreachable("Unsupported range list encoding");
169 }
170 Res.push_back(E);
171 }
172 return Res;
173 }
174
dump(raw_ostream & OS,uint8_t AddrSize,uint8_t MaxEncodingStringLength,uint64_t & CurrentBase,DIDumpOptions DumpOpts,llvm::function_ref<Optional<SectionedAddress> (uint32_t)> LookupPooledAddress) const175 void RangeListEntry::dump(
176 raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength,
177 uint64_t &CurrentBase, DIDumpOptions DumpOpts,
178 llvm::function_ref<Optional<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);
186 OS << " => ";
187 }
188 };
189
190 if (DumpOpts.Verbose) {
191 // Print the section offset in verbose mode.
192 OS << format("0x%8.8" PRIx32 ":", 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)
199 OS << ": ";
200 }
201
202 switch (EntryKind) {
203 case dwarf::DW_RLE_end_of_list:
204 OS << (DumpOpts.Verbose ? "" : "<End of list>");
205 break;
206 // case dwarf::DW_RLE_base_addressx:
207 case dwarf::DW_RLE_base_addressx: {
208 if (auto SA = LookupPooledAddress(Value0))
209 CurrentBase = SA->Address;
210 else
211 CurrentBase = Value0;
212 if (!DumpOpts.Verbose)
213 return;
214 OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
215 break;
216 }
217 case dwarf::DW_RLE_base_address:
218 // In non-verbose mode we do not print anything for this entry.
219 CurrentBase = Value0;
220 if (!DumpOpts.Verbose)
221 return;
222 OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
223 break;
224 case dwarf::DW_RLE_start_length:
225 PrintRawEntry(OS, *this, AddrSize, DumpOpts);
226 DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
227 break;
228 case dwarf::DW_RLE_offset_pair:
229 PrintRawEntry(OS, *this, AddrSize, DumpOpts);
230 DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
231 .dump(OS, AddrSize, DumpOpts);
232 break;
233 case dwarf::DW_RLE_start_end:
234 DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts);
235 break;
236 case dwarf::DW_RLE_startx_length: {
237 PrintRawEntry(OS, *this, AddrSize, DumpOpts);
238 uint64_t Start = 0;
239 if (auto SA = LookupPooledAddress(Value0))
240 Start = SA->Address;
241 DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts);
242 break;
243 } break;
244 default:
245 llvm_unreachable("Unsupported range list encoding");
246 }
247 OS << "\n";
248 }
249