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 
19ad68a8b9SDavid Blaikie Error RangeListEntry::extract(DWARFDataExtractor Data, uint64_t *OffsetPtr) {
203fb9e3f3SWolfgang Pieb   Offset = *OffsetPtr;
21ad60559bSWolfgang Pieb   SectionIndex = -1ULL;
223fb9e3f3SWolfgang Pieb   // The caller should guarantee that we have at least 1 byte available, so
233fb9e3f3SWolfgang Pieb   // we just assert instead of revalidate.
24ad68a8b9SDavid Blaikie   assert(*OffsetPtr < Data.size() &&
253fb9e3f3SWolfgang Pieb          "not enough space to extract a rangelist encoding");
26f39a9bbeSWolfgang Pieb   uint8_t Encoding = Data.getU8(OffsetPtr);
273fb9e3f3SWolfgang Pieb 
28ad68a8b9SDavid Blaikie   DataExtractor::Cursor C(*OffsetPtr);
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: {
35ad68a8b9SDavid Blaikie     Value0 = Data.getULEB128(C);
3659ac2064SDavid Blaikie     break;
3759ac2064SDavid Blaikie   }
38c2dfd502SJames Henderson   case dwarf::DW_RLE_startx_endx:
39ad68a8b9SDavid Blaikie     consumeError(C.takeError());
40ad68a8b9SDavid Blaikie     return createStringError(
41ad68a8b9SDavid Blaikie         errc::not_supported,
42cba595daSVictor Leschuk         "unsupported rnglists encoding DW_RLE_startx_endx at "
43f26a70a5SIgor Kudrin         "offset 0x%" PRIx64,
44ad68a8b9SDavid Blaikie         Offset);
4559ac2064SDavid Blaikie   case dwarf::DW_RLE_startx_length: {
46ad68a8b9SDavid Blaikie     Value0 = Data.getULEB128(C);
47ad68a8b9SDavid Blaikie     Value1 = Data.getULEB128(C);
4859ac2064SDavid Blaikie     break;
4959ac2064SDavid Blaikie   }
50ab068eaaSWolfgang Pieb   case dwarf::DW_RLE_offset_pair: {
51ad68a8b9SDavid Blaikie     Value0 = Data.getULEB128(C);
52ad68a8b9SDavid Blaikie     Value1 = Data.getULEB128(C);
53ab068eaaSWolfgang Pieb     break;
54ab068eaaSWolfgang Pieb   }
55f39a9bbeSWolfgang Pieb   case dwarf::DW_RLE_base_address: {
56ad68a8b9SDavid Blaikie     Value0 = Data.getRelocatedAddress(C, &SectionIndex);
57ab068eaaSWolfgang Pieb     break;
58f39a9bbeSWolfgang Pieb   }
59f39a9bbeSWolfgang Pieb   case dwarf::DW_RLE_start_end: {
60ad68a8b9SDavid Blaikie     Value0 = Data.getRelocatedAddress(C, &SectionIndex);
61ad68a8b9SDavid Blaikie     Value1 = Data.getRelocatedAddress(C);
62c2dfd502SJames Henderson     break;
63f39a9bbeSWolfgang Pieb   }
64c2dfd502SJames Henderson   case dwarf::DW_RLE_start_length: {
65ad68a8b9SDavid Blaikie     Value0 = Data.getRelocatedAddress(C, &SectionIndex);
66ad68a8b9SDavid Blaikie     Value1 = Data.getULEB128(C);
67c2dfd502SJames Henderson     break;
68c2dfd502SJames Henderson   }
69c2dfd502SJames Henderson   default:
70ad68a8b9SDavid Blaikie     consumeError(C.takeError());
71cba595daSVictor Leschuk     return createStringError(errc::not_supported,
72cba595daSVictor Leschuk                              "unknown rnglists encoding 0x%" PRIx32
73f26a70a5SIgor Kudrin                              " at offset 0x%" PRIx64,
74ad68a8b9SDavid Blaikie                              uint32_t(Encoding), Offset);
75c2dfd502SJames Henderson   }
763fb9e3f3SWolfgang Pieb 
77ad68a8b9SDavid Blaikie   if (!C) {
78ad68a8b9SDavid Blaikie     consumeError(C.takeError());
79ad68a8b9SDavid Blaikie     return createStringError(
80ad68a8b9SDavid Blaikie         errc::invalid_argument,
81ad68a8b9SDavid Blaikie         "read past end of table when reading %s encoding at offset 0x%" PRIx64,
82ad68a8b9SDavid Blaikie         dwarf::RLEString(Encoding).data(), Offset);
83ad68a8b9SDavid Blaikie   }
84ad68a8b9SDavid Blaikie 
85ad68a8b9SDavid Blaikie   *OffsetPtr = C.tell();
863fb9e3f3SWolfgang Pieb   EntryKind = Encoding;
873fb9e3f3SWolfgang Pieb   return Error::success();
88c2dfd502SJames Henderson }
89c2dfd502SJames Henderson 
9077fc1f60SAlexey Lapshin DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
9177fc1f60SAlexey Lapshin     llvm::Optional<object::SectionedAddress> BaseAddr, DWARFUnit &U) const {
92*8036cf7fSDavid Blaikie   return getAbsoluteRanges(
93*8036cf7fSDavid Blaikie       BaseAddr, U.getAddressByteSize(),
94*8036cf7fSDavid Blaikie       [&](uint32_t Index) { return U.getAddrOffsetSectionItem(Index); });
95d34927e7SPavel Labath }
96d34927e7SPavel Labath 
97d34927e7SPavel Labath DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
98*8036cf7fSDavid Blaikie     Optional<object::SectionedAddress> BaseAddr, uint8_t AddressByteSize,
99d34927e7SPavel Labath     function_ref<Optional<object::SectionedAddress>(uint32_t)>
100d34927e7SPavel Labath         LookupPooledAddress) const {
101ad60559bSWolfgang Pieb   DWARFAddressRangesVector Res;
102*8036cf7fSDavid Blaikie   uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressByteSize);
103ad60559bSWolfgang Pieb   for (const RangeListEntry &RLE : Entries) {
104ad60559bSWolfgang Pieb     if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
105ad60559bSWolfgang Pieb       break;
10659ac2064SDavid Blaikie     if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) {
107d34927e7SPavel Labath       BaseAddr = LookupPooledAddress(RLE.Value0);
10859ac2064SDavid Blaikie       if (!BaseAddr)
1096d85c583SGeorge Rimar         BaseAddr = {RLE.Value0, -1ULL};
11059ac2064SDavid Blaikie       continue;
11159ac2064SDavid Blaikie     }
112ad60559bSWolfgang Pieb     if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
113ad60559bSWolfgang Pieb       BaseAddr = {RLE.Value0, RLE.SectionIndex};
114ad60559bSWolfgang Pieb       continue;
115ad60559bSWolfgang Pieb     }
116ad60559bSWolfgang Pieb 
117ad60559bSWolfgang Pieb     DWARFAddressRange E;
118ad60559bSWolfgang Pieb     E.SectionIndex = RLE.SectionIndex;
119ad60559bSWolfgang Pieb     if (BaseAddr && E.SectionIndex == -1ULL)
120ad60559bSWolfgang Pieb       E.SectionIndex = BaseAddr->SectionIndex;
121ad60559bSWolfgang Pieb 
122ad60559bSWolfgang Pieb     switch (RLE.EntryKind) {
123ad60559bSWolfgang Pieb     case dwarf::DW_RLE_offset_pair:
124ad60559bSWolfgang Pieb       E.LowPC = RLE.Value0;
125*8036cf7fSDavid Blaikie       if (E.LowPC == Tombstone)
126*8036cf7fSDavid Blaikie         continue;
127ad60559bSWolfgang Pieb       E.HighPC = RLE.Value1;
128ad60559bSWolfgang Pieb       if (BaseAddr) {
129*8036cf7fSDavid Blaikie         if (BaseAddr->Address == Tombstone)
130*8036cf7fSDavid Blaikie           continue;
131ad60559bSWolfgang Pieb         E.LowPC += BaseAddr->Address;
132ad60559bSWolfgang Pieb         E.HighPC += BaseAddr->Address;
133ad60559bSWolfgang Pieb       }
134ad60559bSWolfgang Pieb       break;
135ad60559bSWolfgang Pieb     case dwarf::DW_RLE_start_end:
136ad60559bSWolfgang Pieb       E.LowPC = RLE.Value0;
137ad60559bSWolfgang Pieb       E.HighPC = RLE.Value1;
138ad60559bSWolfgang Pieb       break;
139ad60559bSWolfgang Pieb     case dwarf::DW_RLE_start_length:
140ad60559bSWolfgang Pieb       E.LowPC = RLE.Value0;
141ad60559bSWolfgang Pieb       E.HighPC = E.LowPC + RLE.Value1;
142ad60559bSWolfgang Pieb       break;
14359ac2064SDavid Blaikie     case dwarf::DW_RLE_startx_length: {
144d34927e7SPavel Labath       auto Start = LookupPooledAddress(RLE.Value0);
14559ac2064SDavid Blaikie       if (!Start)
1466d85c583SGeorge Rimar         Start = {0, -1ULL};
14759ac2064SDavid Blaikie       E.SectionIndex = Start->SectionIndex;
14859ac2064SDavid Blaikie       E.LowPC = Start->Address;
14959ac2064SDavid Blaikie       E.HighPC = E.LowPC + RLE.Value1;
15059ac2064SDavid Blaikie       break;
15159ac2064SDavid Blaikie     }
152ad60559bSWolfgang Pieb     default:
153ad60559bSWolfgang Pieb       // Unsupported encodings should have been reported during extraction,
154ad60559bSWolfgang Pieb       // so we should not run into any here.
155ad60559bSWolfgang Pieb       llvm_unreachable("Unsupported range list encoding");
156ad60559bSWolfgang Pieb     }
157*8036cf7fSDavid Blaikie     if (E.LowPC == Tombstone)
158*8036cf7fSDavid Blaikie       continue;
159ad60559bSWolfgang Pieb     Res.push_back(E);
160ad60559bSWolfgang Pieb   }
161ad60559bSWolfgang Pieb   return Res;
162ad60559bSWolfgang Pieb }
163ad60559bSWolfgang Pieb 
16459ac2064SDavid Blaikie void RangeListEntry::dump(
165f39a9bbeSWolfgang Pieb     raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength,
166f39a9bbeSWolfgang Pieb     uint64_t &CurrentBase, DIDumpOptions DumpOpts,
16777fc1f60SAlexey Lapshin     llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
16859ac2064SDavid Blaikie         LookupPooledAddress) const {
169439801baSWolfgang Pieb   auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
170ab068eaaSWolfgang Pieb                           uint8_t AddrSize, DIDumpOptions DumpOpts) {
171ab068eaaSWolfgang Pieb     if (DumpOpts.Verbose) {
172ab068eaaSWolfgang Pieb       DumpOpts.DisplayRawContents = true;
173ab068eaaSWolfgang Pieb       DWARFAddressRange(Entry.Value0, Entry.Value1)
174ab068eaaSWolfgang Pieb           .dump(OS, AddrSize, DumpOpts);
175ab068eaaSWolfgang Pieb       OS << " => ";
176ab068eaaSWolfgang Pieb     }
177ab068eaaSWolfgang Pieb   };
178ab068eaaSWolfgang Pieb 
179a0729d41SWolfgang Pieb   if (DumpOpts.Verbose) {
180a0729d41SWolfgang Pieb     // Print the section offset in verbose mode.
181f26a70a5SIgor Kudrin     OS << format("0x%8.8" PRIx64 ":", Offset);
182439801baSWolfgang Pieb     auto EncodingString = dwarf::RangeListEncodingString(EntryKind);
183a0729d41SWolfgang Pieb     // Unsupported encodings should have been reported during parsing.
184a0729d41SWolfgang Pieb     assert(!EncodingString.empty() && "Unknown range entry encoding");
185a0729d41SWolfgang Pieb     OS << format(" [%s%*c", EncodingString.data(),
186a0729d41SWolfgang Pieb                  MaxEncodingStringLength - EncodingString.size() + 1, ']');
187f39a9bbeSWolfgang Pieb     if (EntryKind != dwarf::DW_RLE_end_of_list)
188a0729d41SWolfgang Pieb       OS << ": ";
189a0729d41SWolfgang Pieb   }
190a0729d41SWolfgang Pieb 
191*8036cf7fSDavid Blaikie   uint64_t Tombstone = dwarf::computeTombstoneAddress(AddrSize);
192*8036cf7fSDavid Blaikie 
193439801baSWolfgang Pieb   switch (EntryKind) {
194a0729d41SWolfgang Pieb   case dwarf::DW_RLE_end_of_list:
195e74e0f11SAlexander Kornienko     OS << (DumpOpts.Verbose ? "" : "<End of list>");
196a0729d41SWolfgang Pieb     break;
19759ac2064SDavid Blaikie   case dwarf::DW_RLE_base_addressx: {
19859ac2064SDavid Blaikie     if (auto SA = LookupPooledAddress(Value0))
19959ac2064SDavid Blaikie       CurrentBase = SA->Address;
20059ac2064SDavid Blaikie     else
20159ac2064SDavid Blaikie       CurrentBase = Value0;
20259ac2064SDavid Blaikie     if (!DumpOpts.Verbose)
20359ac2064SDavid Blaikie       return;
20459ac2064SDavid Blaikie     OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
20559ac2064SDavid Blaikie     break;
20659ac2064SDavid Blaikie   }
207ab068eaaSWolfgang Pieb   case dwarf::DW_RLE_base_address:
208e74e0f11SAlexander Kornienko     // In non-verbose mode we do not print anything for this entry.
209439801baSWolfgang Pieb     CurrentBase = Value0;
210ab068eaaSWolfgang Pieb     if (!DumpOpts.Verbose)
211ab068eaaSWolfgang Pieb       return;
212439801baSWolfgang Pieb     OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
213ab068eaaSWolfgang Pieb     break;
214a0729d41SWolfgang Pieb   case dwarf::DW_RLE_start_length:
215439801baSWolfgang Pieb     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
216439801baSWolfgang Pieb     DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
217a0729d41SWolfgang Pieb     break;
218ab068eaaSWolfgang Pieb   case dwarf::DW_RLE_offset_pair:
219439801baSWolfgang Pieb     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
220*8036cf7fSDavid Blaikie     if (CurrentBase != Tombstone)
221439801baSWolfgang Pieb       DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
222ab068eaaSWolfgang Pieb           .dump(OS, AddrSize, DumpOpts);
223*8036cf7fSDavid Blaikie     else
224*8036cf7fSDavid Blaikie       OS << "dead code";
225ab068eaaSWolfgang Pieb     break;
226a0729d41SWolfgang Pieb   case dwarf::DW_RLE_start_end:
227439801baSWolfgang Pieb     DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts);
228a0729d41SWolfgang Pieb     break;
22959ac2064SDavid Blaikie   case dwarf::DW_RLE_startx_length: {
23059ac2064SDavid Blaikie     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
23159ac2064SDavid Blaikie     uint64_t Start = 0;
23259ac2064SDavid Blaikie     if (auto SA = LookupPooledAddress(Value0))
23359ac2064SDavid Blaikie       Start = SA->Address;
23459ac2064SDavid Blaikie     DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts);
23559ac2064SDavid Blaikie     break;
23640483e18SFangrui Song   }
237a0729d41SWolfgang Pieb   default:
238a0729d41SWolfgang Pieb     llvm_unreachable("Unsupported range list encoding");
239a0729d41SWolfgang Pieb   }
240a0729d41SWolfgang Pieb   OS << "\n";
241a0729d41SWolfgang Pieb }
242