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/MathExtras.h"
17 #include "llvm/Support/raw_ostream.h"
18 
19 using namespace llvm;
20 
21 Error RangeListEntry::extract(DWARFDataExtractor Data, uint32_t End,
22                               uint16_t Version, StringRef /* SectionName */,
23                               uint32_t *OffsetPtr, bool /* isDWO */) {
24   Offset = *OffsetPtr;
25   SectionIndex = -1ULL;
26 
27   assert((Data.getAddressSize() == 4 || Data.getAddressSize() == 8) &&
28          "Unsupported address size");
29 
30   // We model a DWARF v4 range list entry like DWARF v5 DW_RLE_offset_pair,
31   // since it is subject to base adjustment.
32   uint8_t Encoding = dwarf::DW_RLE_offset_pair;
33   if (Version > 4) {
34     // The caller should guarantee that we have at least 1 byte available, so
35     // we just assert instead of revalidate.
36     assert(*OffsetPtr < End &&
37            "not enough space to extract a rangelist encoding");
38     Encoding = Data.getU8(OffsetPtr);
39   }
40 
41   switch (Encoding) {
42   case dwarf::DW_RLE_end_of_list:
43     Value0 = Value1 = 0;
44     break;
45   // TODO: Support other encodings.
46   case dwarf::DW_RLE_base_addressx: {
47     uint32_t PreviousOffset = *OffsetPtr - 1;
48     Value0 = Data.getULEB128(OffsetPtr);
49     if (End < *OffsetPtr)
50       return createStringError(
51           errc::invalid_argument,
52           "read past end of table when reading "
53           "DW_RLE_base_addressx encoding at offset 0x%" PRIx32,
54           PreviousOffset);
55     break;
56   }
57   case dwarf::DW_RLE_startx_endx:
58     return createStringError(errc::not_supported,
59                        "unsupported rnglists encoding DW_RLE_startx_endx at "
60                        "offset 0x%" PRIx32,
61                        *OffsetPtr - 1);
62   case dwarf::DW_RLE_startx_length: {
63     uint32_t PreviousOffset = *OffsetPtr - 1;
64     Value0 = Data.getULEB128(OffsetPtr);
65     Value1 = Data.getULEB128(OffsetPtr);
66     if (End < *OffsetPtr)
67       return createStringError(
68           errc::invalid_argument,
69           "read past end of table when reading "
70           "DW_RLE_startx_length encoding at offset 0x%" PRIx32,
71           PreviousOffset);
72     break;
73   }
74   case dwarf::DW_RLE_offset_pair: {
75     if (Version < 5) {
76       if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2))
77         return createStringError(
78             errc::illegal_byte_sequence,
79             "invalid range list entry at offset 0x%" PRIx32, *OffsetPtr);
80       Value0 = Data.getRelocatedAddress(OffsetPtr);
81       Value1 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
82       // Adjust the EntryKind for end-of-list and base_address based on the
83       // contents.
84       if (Value0 == maxUIntN(Data.getAddressSize() * 8)) {
85         Encoding = dwarf::DW_RLE_base_address;
86         Value0 = Value1;
87         Value1 = 0;
88       } else if (Value0 == 0 && Value1 == 0)
89         Encoding = dwarf::DW_RLE_end_of_list;
90       break;
91     }
92     uint32_t PreviousOffset = *OffsetPtr - 1;
93     Value0 = Data.getULEB128(OffsetPtr);
94     Value1 = Data.getULEB128(OffsetPtr);
95     if (End < *OffsetPtr)
96       return createStringError(errc::invalid_argument,
97                          "read past end of table when reading "
98                          "DW_RLE_offset_pair encoding at offset 0x%" PRIx32,
99                          PreviousOffset);
100     break;
101   }
102   case dwarf::DW_RLE_base_address:
103     if ((End - *OffsetPtr) < Data.getAddressSize())
104       return createStringError(errc::invalid_argument,
105                          "insufficient space remaining in table for "
106                          "DW_RLE_base_address encoding at offset 0x%" PRIx32,
107                          *OffsetPtr - 1);
108     Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
109     break;
110   case dwarf::DW_RLE_start_end:
111     if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2))
112       return createStringError(errc::invalid_argument,
113                          "insufficient space remaining in table for "
114                          "DW_RLE_start_end encoding "
115                          "at offset 0x%" PRIx32,
116                          *OffsetPtr - 1);
117     Value0 = Data.getRelocatedAddress(OffsetPtr);
118     Value1 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
119     break;
120   case dwarf::DW_RLE_start_length: {
121     uint32_t PreviousOffset = *OffsetPtr - 1;
122     Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
123     Value1 = Data.getULEB128(OffsetPtr);
124     if (End < *OffsetPtr)
125       return createStringError(errc::invalid_argument,
126                          "read past end of table when reading "
127                          "DW_RLE_start_length encoding at offset 0x%" PRIx32,
128                          PreviousOffset);
129     break;
130   }
131   default:
132     return createStringError(errc::not_supported,
133                        "unknown rnglists encoding 0x%" PRIx32
134                        " at offset 0x%" PRIx32,
135                        uint32_t(Encoding), *OffsetPtr - 1);
136   }
137 
138   EntryKind = Encoding;
139   return Error::success();
140 }
141 
142 DWARFAddressRangesVector
143 DWARFDebugRnglist::getAbsoluteRanges(llvm::Optional<SectionedAddress> BaseAddr,
144                                      DWARFUnit &U) const {
145   DWARFAddressRangesVector Res;
146   for (const RangeListEntry &RLE : Entries) {
147     if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
148       break;
149     if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) {
150       BaseAddr = U.getAddrOffsetSectionItem(RLE.Value0);
151       if (!BaseAddr)
152         BaseAddr = {RLE.Value0, 0};
153       continue;
154     }
155     if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
156       BaseAddr = {RLE.Value0, RLE.SectionIndex};
157       continue;
158     }
159 
160     DWARFAddressRange E;
161     E.SectionIndex = RLE.SectionIndex;
162     if (BaseAddr && E.SectionIndex == -1ULL)
163       E.SectionIndex = BaseAddr->SectionIndex;
164 
165     switch (RLE.EntryKind) {
166     case dwarf::DW_RLE_offset_pair:
167       E.LowPC = RLE.Value0;
168       E.HighPC = RLE.Value1;
169       if (BaseAddr) {
170         E.LowPC += BaseAddr->Address;
171         E.HighPC += BaseAddr->Address;
172       }
173       break;
174     case dwarf::DW_RLE_start_end:
175       E.LowPC = RLE.Value0;
176       E.HighPC = RLE.Value1;
177       break;
178     case dwarf::DW_RLE_start_length:
179       E.LowPC = RLE.Value0;
180       E.HighPC = E.LowPC + RLE.Value1;
181       break;
182     case dwarf::DW_RLE_startx_length: {
183       auto Start = U.getAddrOffsetSectionItem(RLE.Value0);
184       if (!Start)
185         Start = {0, 0};
186       E.SectionIndex = Start->SectionIndex;
187       E.LowPC = Start->Address;
188       E.HighPC = E.LowPC + RLE.Value1;
189       break;
190     }
191     default:
192       // Unsupported encodings should have been reported during extraction,
193       // so we should not run into any here.
194       llvm_unreachable("Unsupported range list encoding");
195     }
196     Res.push_back(E);
197   }
198   return Res;
199 }
200 
201 void RangeListEntry::dump(
202     raw_ostream &OS, DWARFContext *, uint8_t AddrSize, uint64_t &CurrentBase,
203     unsigned Indent, uint16_t Version, uint8_t MaxEncodingStringLength,
204     DIDumpOptions DumpOpts,
205     llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
206         LookupPooledAddress) const {
207   auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
208                           uint8_t AddrSize, DIDumpOptions DumpOpts) {
209     if (DumpOpts.Verbose) {
210       DumpOpts.DisplayRawContents = true;
211       DWARFAddressRange(Entry.Value0, Entry.Value1)
212           .dump(OS, AddrSize, DumpOpts);
213       OS << " => ";
214     }
215   };
216 
217   // Output indentations before we print the actual entry. We only print
218   // anything for DW_RLE_base_address when we are in verbose mode.
219   if (Version < 5 || DumpOpts.Verbose || !isBaseAddressSelectionEntry())
220     OS.indent(Indent);
221 
222   // Always print the section offset in DWARF v4 and earlier.
223   if (Version < 5) {
224     OS << format("%08x", Offset);
225     DumpOpts.Verbose = false;
226   }
227 
228   if (DumpOpts.Verbose) {
229     // Print the section offset in verbose mode.
230     OS << format("0x%8.8" PRIx32 ":", Offset);
231     if (Version > 4) {
232       auto EncodingString = dwarf::RangeListEncodingString(EntryKind);
233       // Unsupported encodings should have been reported during parsing.
234       assert(!EncodingString.empty() && "Unknown range entry encoding");
235       OS << format(" [%s%*c", EncodingString.data(),
236                    MaxEncodingStringLength - EncodingString.size() + 1, ']');
237       if (!isEndOfList())
238         OS << ": ";
239     }
240   }
241 
242   switch (EntryKind) {
243   case dwarf::DW_RLE_end_of_list:
244     OS << (DumpOpts.Verbose ? "" : " <End of list>");
245     break;
246     //  case dwarf::DW_RLE_base_addressx:
247   case dwarf::DW_RLE_base_addressx: {
248     if (auto SA = LookupPooledAddress(Value0))
249       CurrentBase = SA->Address;
250     else
251       CurrentBase = Value0;
252     if (!DumpOpts.Verbose)
253       return;
254     OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
255     break;
256   }
257   case dwarf::DW_RLE_base_address:
258     // In non-verbose mode we do not print anything for this entry.
259     CurrentBase = Value0;
260     if (Version < 5) {
261       // Dump the entry in pre-DWARF v5 format, i.e. with a -1 as Value0.
262       uint64_t allOnes = maxUIntN(AddrSize * 8);
263       OS << format(" %*.*" PRIx64, AddrSize * 2, AddrSize * 2, allOnes);
264       OS << format(" %*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
265       break;
266     }
267     if (!DumpOpts.Verbose)
268       return;
269     OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
270     break;
271   case dwarf::DW_RLE_start_length:
272     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
273     DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
274     break;
275   case dwarf::DW_RLE_offset_pair:
276     if (Version < 5) {
277       OS << format(" %*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
278       OS << format(" %*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value1);
279       break;
280     }
281     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
282     DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
283         .dump(OS, AddrSize, DumpOpts);
284     break;
285   case dwarf::DW_RLE_start_end:
286     DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts);
287     break;
288   case dwarf::DW_RLE_startx_length: {
289     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
290     uint64_t Start = 0;
291     if (auto SA = LookupPooledAddress(Value0))
292       Start = SA->Address;
293     DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts);
294     break;
295   } break;
296   default:
297     llvm_unreachable("Unsupported range list encoding");
298   }
299   OS << "\n";
300 }
301