1c2dfd502SJames Henderson //===- DWARFDebugRnglists.cpp ---------------------------------------------===//
2c2dfd502SJames Henderson //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c2dfd502SJames Henderson //
7c2dfd502SJames Henderson //===----------------------------------------------------------------------===//
8c2dfd502SJames Henderson 
9c2dfd502SJames Henderson #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
10c2dfd502SJames Henderson #include "llvm/BinaryFormat/Dwarf.h"
11ad60559bSWolfgang Pieb #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
12cba595daSVictor Leschuk #include "llvm/Support/Errc.h"
13c2dfd502SJames Henderson #include "llvm/Support/Error.h"
14c2dfd502SJames Henderson #include "llvm/Support/Format.h"
15c2dfd502SJames Henderson #include "llvm/Support/raw_ostream.h"
16c2dfd502SJames Henderson 
17c2dfd502SJames Henderson using namespace llvm;
18c2dfd502SJames Henderson 
19*f26a70a5SIgor Kudrin Error RangeListEntry::extract(DWARFDataExtractor Data, uint64_t End,
20*f26a70a5SIgor Kudrin                               uint64_t *OffsetPtr) {
213fb9e3f3SWolfgang Pieb   Offset = *OffsetPtr;
22ad60559bSWolfgang Pieb   SectionIndex = -1ULL;
233fb9e3f3SWolfgang Pieb   // The caller should guarantee that we have at least 1 byte available, so
243fb9e3f3SWolfgang Pieb   // we just assert instead of revalidate.
253fb9e3f3SWolfgang Pieb   assert(*OffsetPtr < End &&
263fb9e3f3SWolfgang Pieb          "not enough space to extract a rangelist encoding");
27f39a9bbeSWolfgang Pieb   uint8_t Encoding = Data.getU8(OffsetPtr);
283fb9e3f3SWolfgang Pieb 
29c2dfd502SJames Henderson   switch (Encoding) {
30c2dfd502SJames Henderson   case dwarf::DW_RLE_end_of_list:
313fb9e3f3SWolfgang Pieb     Value0 = Value1 = 0;
32c2dfd502SJames Henderson     break;
33c2dfd502SJames Henderson   // TODO: Support other encodings.
3459ac2064SDavid Blaikie   case dwarf::DW_RLE_base_addressx: {
35*f26a70a5SIgor Kudrin     uint64_t PreviousOffset = *OffsetPtr - 1;
3659ac2064SDavid Blaikie     Value0 = Data.getULEB128(OffsetPtr);
3759ac2064SDavid Blaikie     if (End < *OffsetPtr)
3859ac2064SDavid Blaikie       return createStringError(
3959ac2064SDavid Blaikie           errc::invalid_argument,
4059ac2064SDavid Blaikie           "read past end of table when reading "
41*f26a70a5SIgor Kudrin           "DW_RLE_base_addressx encoding at offset 0x%" PRIx64,
4259ac2064SDavid Blaikie           PreviousOffset);
4359ac2064SDavid Blaikie     break;
4459ac2064SDavid Blaikie   }
45c2dfd502SJames Henderson   case dwarf::DW_RLE_startx_endx:
46cba595daSVictor Leschuk     return createStringError(errc::not_supported,
47cba595daSVictor Leschuk                        "unsupported rnglists encoding DW_RLE_startx_endx at "
48*f26a70a5SIgor Kudrin                        "offset 0x%" PRIx64,
49c2dfd502SJames Henderson                        *OffsetPtr - 1);
5059ac2064SDavid Blaikie   case dwarf::DW_RLE_startx_length: {
51*f26a70a5SIgor Kudrin     uint64_t PreviousOffset = *OffsetPtr - 1;
5259ac2064SDavid Blaikie     Value0 = Data.getULEB128(OffsetPtr);
5359ac2064SDavid Blaikie     Value1 = Data.getULEB128(OffsetPtr);
5459ac2064SDavid Blaikie     if (End < *OffsetPtr)
5559ac2064SDavid Blaikie       return createStringError(
5659ac2064SDavid Blaikie           errc::invalid_argument,
5759ac2064SDavid Blaikie           "read past end of table when reading "
58*f26a70a5SIgor Kudrin           "DW_RLE_startx_length encoding at offset 0x%" PRIx64,
5959ac2064SDavid Blaikie           PreviousOffset);
6059ac2064SDavid Blaikie     break;
6159ac2064SDavid Blaikie   }
62ab068eaaSWolfgang Pieb   case dwarf::DW_RLE_offset_pair: {
63*f26a70a5SIgor Kudrin     uint64_t PreviousOffset = *OffsetPtr - 1;
643fb9e3f3SWolfgang Pieb     Value0 = Data.getULEB128(OffsetPtr);
653fb9e3f3SWolfgang Pieb     Value1 = Data.getULEB128(OffsetPtr);
66ab068eaaSWolfgang Pieb     if (End < *OffsetPtr)
67cba595daSVictor Leschuk       return createStringError(errc::invalid_argument,
68cba595daSVictor Leschuk                          "read past end of table when reading "
69*f26a70a5SIgor Kudrin                          "DW_RLE_offset_pair encoding at offset 0x%" PRIx64,
70ab068eaaSWolfgang Pieb                          PreviousOffset);
71ab068eaaSWolfgang Pieb     break;
72ab068eaaSWolfgang Pieb   }
73f39a9bbeSWolfgang Pieb   case dwarf::DW_RLE_base_address: {
743fb9e3f3SWolfgang Pieb     if ((End - *OffsetPtr) < Data.getAddressSize())
75cba595daSVictor Leschuk       return createStringError(errc::invalid_argument,
76cba595daSVictor Leschuk                          "insufficient space remaining in table for "
77*f26a70a5SIgor Kudrin                          "DW_RLE_base_address encoding at offset 0x%" PRIx64,
78c2dfd502SJames Henderson                          *OffsetPtr - 1);
79ad60559bSWolfgang Pieb     Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
80ab068eaaSWolfgang Pieb     break;
81f39a9bbeSWolfgang Pieb   }
82f39a9bbeSWolfgang Pieb   case dwarf::DW_RLE_start_end: {
833fb9e3f3SWolfgang Pieb     if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2))
84cba595daSVictor Leschuk       return createStringError(errc::invalid_argument,
85cba595daSVictor Leschuk                          "insufficient space remaining in table for "
86c2dfd502SJames Henderson                          "DW_RLE_start_end encoding "
87*f26a70a5SIgor Kudrin                          "at offset 0x%" PRIx64,
88c2dfd502SJames Henderson                          *OffsetPtr - 1);
89f39a9bbeSWolfgang Pieb     Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
90f39a9bbeSWolfgang Pieb     Value1 = Data.getRelocatedAddress(OffsetPtr);
91c2dfd502SJames Henderson     break;
92f39a9bbeSWolfgang Pieb   }
93c2dfd502SJames Henderson   case dwarf::DW_RLE_start_length: {
94*f26a70a5SIgor Kudrin     uint64_t PreviousOffset = *OffsetPtr - 1;
95ad60559bSWolfgang Pieb     Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
963fb9e3f3SWolfgang Pieb     Value1 = Data.getULEB128(OffsetPtr);
97c2dfd502SJames Henderson     if (End < *OffsetPtr)
98cba595daSVictor Leschuk       return createStringError(errc::invalid_argument,
99cba595daSVictor Leschuk                          "read past end of table when reading "
100*f26a70a5SIgor Kudrin                          "DW_RLE_start_length encoding at offset 0x%" PRIx64,
101c2dfd502SJames Henderson                          PreviousOffset);
102c2dfd502SJames Henderson     break;
103c2dfd502SJames Henderson   }
104c2dfd502SJames Henderson   default:
105cba595daSVictor Leschuk     return createStringError(errc::not_supported,
106cba595daSVictor Leschuk                        "unknown rnglists encoding 0x%" PRIx32
107*f26a70a5SIgor Kudrin                        " at offset 0x%" PRIx64,
108c2dfd502SJames Henderson                        uint32_t(Encoding), *OffsetPtr - 1);
109c2dfd502SJames Henderson   }
1103fb9e3f3SWolfgang Pieb 
1113fb9e3f3SWolfgang Pieb   EntryKind = Encoding;
1123fb9e3f3SWolfgang Pieb   return Error::success();
113c2dfd502SJames Henderson }
114c2dfd502SJames Henderson 
11577fc1f60SAlexey Lapshin DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
11677fc1f60SAlexey Lapshin     llvm::Optional<object::SectionedAddress> BaseAddr, DWARFUnit &U) const {
117ad60559bSWolfgang Pieb   DWARFAddressRangesVector Res;
118ad60559bSWolfgang Pieb   for (const RangeListEntry &RLE : Entries) {
119ad60559bSWolfgang Pieb     if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
120ad60559bSWolfgang Pieb       break;
12159ac2064SDavid Blaikie     if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) {
12259ac2064SDavid Blaikie       BaseAddr = U.getAddrOffsetSectionItem(RLE.Value0);
12359ac2064SDavid Blaikie       if (!BaseAddr)
1246d85c583SGeorge Rimar         BaseAddr = {RLE.Value0, -1ULL};
12559ac2064SDavid Blaikie       continue;
12659ac2064SDavid Blaikie     }
127ad60559bSWolfgang Pieb     if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
128ad60559bSWolfgang Pieb       BaseAddr = {RLE.Value0, RLE.SectionIndex};
129ad60559bSWolfgang Pieb       continue;
130ad60559bSWolfgang Pieb     }
131ad60559bSWolfgang Pieb 
132ad60559bSWolfgang Pieb     DWARFAddressRange E;
133ad60559bSWolfgang Pieb     E.SectionIndex = RLE.SectionIndex;
134ad60559bSWolfgang Pieb     if (BaseAddr && E.SectionIndex == -1ULL)
135ad60559bSWolfgang Pieb       E.SectionIndex = BaseAddr->SectionIndex;
136ad60559bSWolfgang Pieb 
137ad60559bSWolfgang Pieb     switch (RLE.EntryKind) {
138ad60559bSWolfgang Pieb     case dwarf::DW_RLE_offset_pair:
139ad60559bSWolfgang Pieb       E.LowPC = RLE.Value0;
140ad60559bSWolfgang Pieb       E.HighPC = RLE.Value1;
141ad60559bSWolfgang Pieb       if (BaseAddr) {
142ad60559bSWolfgang Pieb         E.LowPC += BaseAddr->Address;
143ad60559bSWolfgang Pieb         E.HighPC += BaseAddr->Address;
144ad60559bSWolfgang Pieb       }
145ad60559bSWolfgang Pieb       break;
146ad60559bSWolfgang Pieb     case dwarf::DW_RLE_start_end:
147ad60559bSWolfgang Pieb       E.LowPC = RLE.Value0;
148ad60559bSWolfgang Pieb       E.HighPC = RLE.Value1;
149ad60559bSWolfgang Pieb       break;
150ad60559bSWolfgang Pieb     case dwarf::DW_RLE_start_length:
151ad60559bSWolfgang Pieb       E.LowPC = RLE.Value0;
152ad60559bSWolfgang Pieb       E.HighPC = E.LowPC + RLE.Value1;
153ad60559bSWolfgang Pieb       break;
15459ac2064SDavid Blaikie     case dwarf::DW_RLE_startx_length: {
15559ac2064SDavid Blaikie       auto Start = U.getAddrOffsetSectionItem(RLE.Value0);
15659ac2064SDavid Blaikie       if (!Start)
1576d85c583SGeorge Rimar         Start = {0, -1ULL};
15859ac2064SDavid Blaikie       E.SectionIndex = Start->SectionIndex;
15959ac2064SDavid Blaikie       E.LowPC = Start->Address;
16059ac2064SDavid Blaikie       E.HighPC = E.LowPC + RLE.Value1;
16159ac2064SDavid Blaikie       break;
16259ac2064SDavid Blaikie     }
163ad60559bSWolfgang Pieb     default:
164ad60559bSWolfgang Pieb       // Unsupported encodings should have been reported during extraction,
165ad60559bSWolfgang Pieb       // so we should not run into any here.
166ad60559bSWolfgang Pieb       llvm_unreachable("Unsupported range list encoding");
167ad60559bSWolfgang Pieb     }
168ad60559bSWolfgang Pieb     Res.push_back(E);
169ad60559bSWolfgang Pieb   }
170ad60559bSWolfgang Pieb   return Res;
171ad60559bSWolfgang Pieb }
172ad60559bSWolfgang Pieb 
17359ac2064SDavid Blaikie void RangeListEntry::dump(
174f39a9bbeSWolfgang Pieb     raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength,
175f39a9bbeSWolfgang Pieb     uint64_t &CurrentBase, DIDumpOptions DumpOpts,
17677fc1f60SAlexey Lapshin     llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
17759ac2064SDavid Blaikie         LookupPooledAddress) const {
178439801baSWolfgang Pieb   auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
179ab068eaaSWolfgang Pieb                           uint8_t AddrSize, DIDumpOptions DumpOpts) {
180ab068eaaSWolfgang Pieb     if (DumpOpts.Verbose) {
181ab068eaaSWolfgang Pieb       DumpOpts.DisplayRawContents = true;
182ab068eaaSWolfgang Pieb       DWARFAddressRange(Entry.Value0, Entry.Value1)
183ab068eaaSWolfgang Pieb           .dump(OS, AddrSize, DumpOpts);
184ab068eaaSWolfgang Pieb       OS << " => ";
185ab068eaaSWolfgang Pieb     }
186ab068eaaSWolfgang Pieb   };
187ab068eaaSWolfgang Pieb 
188a0729d41SWolfgang Pieb   if (DumpOpts.Verbose) {
189a0729d41SWolfgang Pieb     // Print the section offset in verbose mode.
190*f26a70a5SIgor Kudrin     OS << format("0x%8.8" PRIx64 ":", Offset);
191439801baSWolfgang Pieb     auto EncodingString = dwarf::RangeListEncodingString(EntryKind);
192a0729d41SWolfgang Pieb     // Unsupported encodings should have been reported during parsing.
193a0729d41SWolfgang Pieb     assert(!EncodingString.empty() && "Unknown range entry encoding");
194a0729d41SWolfgang Pieb     OS << format(" [%s%*c", EncodingString.data(),
195a0729d41SWolfgang Pieb                  MaxEncodingStringLength - EncodingString.size() + 1, ']');
196f39a9bbeSWolfgang Pieb     if (EntryKind != dwarf::DW_RLE_end_of_list)
197a0729d41SWolfgang Pieb       OS << ": ";
198a0729d41SWolfgang Pieb   }
199a0729d41SWolfgang Pieb 
200439801baSWolfgang Pieb   switch (EntryKind) {
201a0729d41SWolfgang Pieb   case dwarf::DW_RLE_end_of_list:
202e74e0f11SAlexander Kornienko     OS << (DumpOpts.Verbose ? "" : "<End of list>");
203a0729d41SWolfgang Pieb     break;
20459ac2064SDavid Blaikie   case dwarf::DW_RLE_base_addressx: {
20559ac2064SDavid Blaikie     if (auto SA = LookupPooledAddress(Value0))
20659ac2064SDavid Blaikie       CurrentBase = SA->Address;
20759ac2064SDavid Blaikie     else
20859ac2064SDavid Blaikie       CurrentBase = Value0;
20959ac2064SDavid Blaikie     if (!DumpOpts.Verbose)
21059ac2064SDavid Blaikie       return;
21159ac2064SDavid Blaikie     OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
21259ac2064SDavid Blaikie     break;
21359ac2064SDavid Blaikie   }
214ab068eaaSWolfgang Pieb   case dwarf::DW_RLE_base_address:
215e74e0f11SAlexander Kornienko     // In non-verbose mode we do not print anything for this entry.
216439801baSWolfgang Pieb     CurrentBase = Value0;
217ab068eaaSWolfgang Pieb     if (!DumpOpts.Verbose)
218ab068eaaSWolfgang Pieb       return;
219439801baSWolfgang Pieb     OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
220ab068eaaSWolfgang Pieb     break;
221a0729d41SWolfgang Pieb   case dwarf::DW_RLE_start_length:
222439801baSWolfgang Pieb     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
223439801baSWolfgang Pieb     DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
224a0729d41SWolfgang Pieb     break;
225ab068eaaSWolfgang Pieb   case dwarf::DW_RLE_offset_pair:
226439801baSWolfgang Pieb     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
227439801baSWolfgang Pieb     DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
228ab068eaaSWolfgang Pieb         .dump(OS, AddrSize, DumpOpts);
229ab068eaaSWolfgang Pieb     break;
230a0729d41SWolfgang Pieb   case dwarf::DW_RLE_start_end:
231439801baSWolfgang Pieb     DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts);
232a0729d41SWolfgang Pieb     break;
23359ac2064SDavid Blaikie   case dwarf::DW_RLE_startx_length: {
23459ac2064SDavid Blaikie     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
23559ac2064SDavid Blaikie     uint64_t Start = 0;
23659ac2064SDavid Blaikie     if (auto SA = LookupPooledAddress(Value0))
23759ac2064SDavid Blaikie       Start = SA->Address;
23859ac2064SDavid Blaikie     DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts);
23959ac2064SDavid Blaikie     break;
24040483e18SFangrui Song   }
241a0729d41SWolfgang Pieb   default:
242a0729d41SWolfgang Pieb     llvm_unreachable("Unsupported range list encoding");
243a0729d41SWolfgang Pieb   }
244a0729d41SWolfgang Pieb   OS << "\n";
245a0729d41SWolfgang Pieb }
246