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