xref: /llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp (revision 89fab98e884f05076bbd420d95b5de3596f5452c)
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"
11ea83e0b1SDavid Blaikie #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
12ad60559bSWolfgang Pieb #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
13cba595daSVictor Leschuk #include "llvm/Support/Errc.h"
14c2dfd502SJames Henderson #include "llvm/Support/Error.h"
15c2dfd502SJames Henderson #include "llvm/Support/Format.h"
16c2dfd502SJames Henderson #include "llvm/Support/raw_ostream.h"
17c2dfd502SJames Henderson 
18c2dfd502SJames Henderson using namespace llvm;
19c2dfd502SJames Henderson 
extract(DWARFDataExtractor Data,uint64_t * OffsetPtr)20ad68a8b9SDavid Blaikie Error RangeListEntry::extract(DWARFDataExtractor Data, 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.
25ad68a8b9SDavid Blaikie   assert(*OffsetPtr < Data.size() &&
263fb9e3f3SWolfgang Pieb          "not enough space to extract a rangelist encoding");
27f39a9bbeSWolfgang Pieb   uint8_t Encoding = Data.getU8(OffsetPtr);
283fb9e3f3SWolfgang Pieb 
29ad68a8b9SDavid Blaikie   DataExtractor::Cursor C(*OffsetPtr);
30c2dfd502SJames Henderson   switch (Encoding) {
31c2dfd502SJames Henderson   case dwarf::DW_RLE_end_of_list:
323fb9e3f3SWolfgang Pieb     Value0 = Value1 = 0;
33c2dfd502SJames Henderson     break;
34c2dfd502SJames Henderson   // TODO: Support other encodings.
3559ac2064SDavid Blaikie   case dwarf::DW_RLE_base_addressx: {
36ad68a8b9SDavid Blaikie     Value0 = Data.getULEB128(C);
3759ac2064SDavid Blaikie     break;
3859ac2064SDavid Blaikie   }
39c2dfd502SJames Henderson   case dwarf::DW_RLE_startx_endx:
4092c45e4eSDavid Blaikie     Value0 = Data.getULEB128(C);
4192c45e4eSDavid Blaikie     Value1 = Data.getULEB128(C);
4292c45e4eSDavid Blaikie     break;
4359ac2064SDavid Blaikie   case dwarf::DW_RLE_startx_length: {
44ad68a8b9SDavid Blaikie     Value0 = Data.getULEB128(C);
45ad68a8b9SDavid Blaikie     Value1 = Data.getULEB128(C);
4659ac2064SDavid Blaikie     break;
4759ac2064SDavid Blaikie   }
48ab068eaaSWolfgang Pieb   case dwarf::DW_RLE_offset_pair: {
49ad68a8b9SDavid Blaikie     Value0 = Data.getULEB128(C);
50ad68a8b9SDavid Blaikie     Value1 = Data.getULEB128(C);
51ab068eaaSWolfgang Pieb     break;
52ab068eaaSWolfgang Pieb   }
53f39a9bbeSWolfgang Pieb   case dwarf::DW_RLE_base_address: {
54ad68a8b9SDavid Blaikie     Value0 = Data.getRelocatedAddress(C, &SectionIndex);
55ab068eaaSWolfgang Pieb     break;
56f39a9bbeSWolfgang Pieb   }
57f39a9bbeSWolfgang Pieb   case dwarf::DW_RLE_start_end: {
58ad68a8b9SDavid Blaikie     Value0 = Data.getRelocatedAddress(C, &SectionIndex);
59ad68a8b9SDavid Blaikie     Value1 = Data.getRelocatedAddress(C);
60c2dfd502SJames Henderson     break;
61f39a9bbeSWolfgang Pieb   }
62c2dfd502SJames Henderson   case dwarf::DW_RLE_start_length: {
63ad68a8b9SDavid Blaikie     Value0 = Data.getRelocatedAddress(C, &SectionIndex);
64ad68a8b9SDavid Blaikie     Value1 = Data.getULEB128(C);
65c2dfd502SJames Henderson     break;
66c2dfd502SJames Henderson   }
67c2dfd502SJames Henderson   default:
68ad68a8b9SDavid Blaikie     consumeError(C.takeError());
69cba595daSVictor Leschuk     return createStringError(errc::not_supported,
70cba595daSVictor Leschuk                              "unknown rnglists encoding 0x%" PRIx32
71f26a70a5SIgor Kudrin                              " at offset 0x%" PRIx64,
72ad68a8b9SDavid Blaikie                              uint32_t(Encoding), Offset);
73c2dfd502SJames Henderson   }
743fb9e3f3SWolfgang Pieb 
75ad68a8b9SDavid Blaikie   if (!C) {
76ad68a8b9SDavid Blaikie     consumeError(C.takeError());
77ad68a8b9SDavid Blaikie     return createStringError(
78ad68a8b9SDavid Blaikie         errc::invalid_argument,
79ad68a8b9SDavid Blaikie         "read past end of table when reading %s encoding at offset 0x%" PRIx64,
80ad68a8b9SDavid Blaikie         dwarf::RLEString(Encoding).data(), Offset);
81ad68a8b9SDavid Blaikie   }
82ad68a8b9SDavid Blaikie 
83ad68a8b9SDavid Blaikie   *OffsetPtr = C.tell();
843fb9e3f3SWolfgang Pieb   EntryKind = Encoding;
853fb9e3f3SWolfgang Pieb   return Error::success();
86c2dfd502SJames Henderson }
87c2dfd502SJames Henderson 
getAbsoluteRanges(std::optional<object::SectionedAddress> BaseAddr,DWARFUnit & U) const8877fc1f60SAlexey Lapshin DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
89*89fab98eSFangrui Song     std::optional<object::SectionedAddress> BaseAddr, DWARFUnit &U) const {
908036cf7fSDavid Blaikie   return getAbsoluteRanges(
918036cf7fSDavid Blaikie       BaseAddr, U.getAddressByteSize(),
928036cf7fSDavid Blaikie       [&](uint32_t Index) { return U.getAddrOffsetSectionItem(Index); });
93d34927e7SPavel Labath }
94d34927e7SPavel Labath 
getAbsoluteRanges(std::optional<object::SectionedAddress> BaseAddr,uint8_t AddressByteSize,function_ref<std::optional<object::SectionedAddress> (uint32_t)> LookupPooledAddress) const95d34927e7SPavel Labath DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
96*89fab98eSFangrui Song     std::optional<object::SectionedAddress> BaseAddr, uint8_t AddressByteSize,
97*89fab98eSFangrui Song     function_ref<std::optional<object::SectionedAddress>(uint32_t)>
98d34927e7SPavel Labath         LookupPooledAddress) const {
99ad60559bSWolfgang Pieb   DWARFAddressRangesVector Res;
1008036cf7fSDavid Blaikie   uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressByteSize);
101ad60559bSWolfgang Pieb   for (const RangeListEntry &RLE : Entries) {
102ad60559bSWolfgang Pieb     if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
103ad60559bSWolfgang Pieb       break;
10459ac2064SDavid Blaikie     if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) {
105d34927e7SPavel Labath       BaseAddr = LookupPooledAddress(RLE.Value0);
10659ac2064SDavid Blaikie       if (!BaseAddr)
1076d85c583SGeorge Rimar         BaseAddr = {RLE.Value0, -1ULL};
10859ac2064SDavid Blaikie       continue;
10959ac2064SDavid Blaikie     }
110ad60559bSWolfgang Pieb     if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
111ad60559bSWolfgang Pieb       BaseAddr = {RLE.Value0, RLE.SectionIndex};
112ad60559bSWolfgang Pieb       continue;
113ad60559bSWolfgang Pieb     }
114ad60559bSWolfgang Pieb 
115ad60559bSWolfgang Pieb     DWARFAddressRange E;
116ad60559bSWolfgang Pieb     E.SectionIndex = RLE.SectionIndex;
117ad60559bSWolfgang Pieb     if (BaseAddr && E.SectionIndex == -1ULL)
118ad60559bSWolfgang Pieb       E.SectionIndex = BaseAddr->SectionIndex;
119ad60559bSWolfgang Pieb 
120ad60559bSWolfgang Pieb     switch (RLE.EntryKind) {
121ad60559bSWolfgang Pieb     case dwarf::DW_RLE_offset_pair:
122ad60559bSWolfgang Pieb       E.LowPC = RLE.Value0;
1238036cf7fSDavid Blaikie       if (E.LowPC == Tombstone)
1248036cf7fSDavid Blaikie         continue;
125ad60559bSWolfgang Pieb       E.HighPC = RLE.Value1;
126ad60559bSWolfgang Pieb       if (BaseAddr) {
1278036cf7fSDavid Blaikie         if (BaseAddr->Address == Tombstone)
1288036cf7fSDavid Blaikie           continue;
129ad60559bSWolfgang Pieb         E.LowPC += BaseAddr->Address;
130ad60559bSWolfgang Pieb         E.HighPC += BaseAddr->Address;
131ad60559bSWolfgang Pieb       }
132ad60559bSWolfgang Pieb       break;
133ad60559bSWolfgang Pieb     case dwarf::DW_RLE_start_end:
134ad60559bSWolfgang Pieb       E.LowPC = RLE.Value0;
135ad60559bSWolfgang Pieb       E.HighPC = RLE.Value1;
136ad60559bSWolfgang Pieb       break;
137ad60559bSWolfgang Pieb     case dwarf::DW_RLE_start_length:
138ad60559bSWolfgang Pieb       E.LowPC = RLE.Value0;
139ad60559bSWolfgang Pieb       E.HighPC = E.LowPC + RLE.Value1;
140ad60559bSWolfgang Pieb       break;
14159ac2064SDavid Blaikie     case dwarf::DW_RLE_startx_length: {
142d34927e7SPavel Labath       auto Start = LookupPooledAddress(RLE.Value0);
14359ac2064SDavid Blaikie       if (!Start)
1446d85c583SGeorge Rimar         Start = {0, -1ULL};
14559ac2064SDavid Blaikie       E.SectionIndex = Start->SectionIndex;
14659ac2064SDavid Blaikie       E.LowPC = Start->Address;
14759ac2064SDavid Blaikie       E.HighPC = E.LowPC + RLE.Value1;
14859ac2064SDavid Blaikie       break;
14959ac2064SDavid Blaikie     }
15092c45e4eSDavid Blaikie     case dwarf::DW_RLE_startx_endx: {
15192c45e4eSDavid Blaikie       auto Start = LookupPooledAddress(RLE.Value0);
15292c45e4eSDavid Blaikie       if (!Start)
15392c45e4eSDavid Blaikie         Start = {0, -1ULL};
15492c45e4eSDavid Blaikie       auto End = LookupPooledAddress(RLE.Value1);
15592c45e4eSDavid Blaikie       if (!End)
15692c45e4eSDavid Blaikie         End = {0, -1ULL};
15792c45e4eSDavid Blaikie       // FIXME: Some error handling if Start.SectionIndex != End.SectionIndex
15892c45e4eSDavid Blaikie       E.SectionIndex = Start->SectionIndex;
15992c45e4eSDavid Blaikie       E.LowPC = Start->Address;
16092c45e4eSDavid Blaikie       E.HighPC = End->Address;
16192c45e4eSDavid Blaikie       break;
16292c45e4eSDavid 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     }
1688036cf7fSDavid Blaikie     if (E.LowPC == Tombstone)
1698036cf7fSDavid Blaikie       continue;
170ad60559bSWolfgang Pieb     Res.push_back(E);
171ad60559bSWolfgang Pieb   }
172ad60559bSWolfgang Pieb   return Res;
173ad60559bSWolfgang Pieb }
174ad60559bSWolfgang Pieb 
dump(raw_ostream & OS,uint8_t AddrSize,uint8_t MaxEncodingStringLength,uint64_t & CurrentBase,DIDumpOptions DumpOpts,llvm::function_ref<std::optional<object::SectionedAddress> (uint32_t)> LookupPooledAddress) const17559ac2064SDavid Blaikie void RangeListEntry::dump(
176f39a9bbeSWolfgang Pieb     raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength,
177f39a9bbeSWolfgang Pieb     uint64_t &CurrentBase, DIDumpOptions DumpOpts,
178*89fab98eSFangrui Song     llvm::function_ref<std::optional<object::SectionedAddress>(uint32_t)>
17959ac2064SDavid Blaikie         LookupPooledAddress) const {
180439801baSWolfgang Pieb   auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
181ab068eaaSWolfgang Pieb                           uint8_t AddrSize, DIDumpOptions DumpOpts) {
182ab068eaaSWolfgang Pieb     if (DumpOpts.Verbose) {
183ab068eaaSWolfgang Pieb       DumpOpts.DisplayRawContents = true;
184ab068eaaSWolfgang Pieb       DWARFAddressRange(Entry.Value0, Entry.Value1)
185ab068eaaSWolfgang Pieb           .dump(OS, AddrSize, DumpOpts);
186ab068eaaSWolfgang Pieb       OS << " => ";
187ab068eaaSWolfgang Pieb     }
188ab068eaaSWolfgang Pieb   };
189ab068eaaSWolfgang Pieb 
190a0729d41SWolfgang Pieb   if (DumpOpts.Verbose) {
191a0729d41SWolfgang Pieb     // Print the section offset in verbose mode.
192f26a70a5SIgor Kudrin     OS << format("0x%8.8" PRIx64 ":", Offset);
193439801baSWolfgang Pieb     auto EncodingString = dwarf::RangeListEncodingString(EntryKind);
194a0729d41SWolfgang Pieb     // Unsupported encodings should have been reported during parsing.
195a0729d41SWolfgang Pieb     assert(!EncodingString.empty() && "Unknown range entry encoding");
196a0729d41SWolfgang Pieb     OS << format(" [%s%*c", EncodingString.data(),
197a0729d41SWolfgang Pieb                  MaxEncodingStringLength - EncodingString.size() + 1, ']');
198f39a9bbeSWolfgang Pieb     if (EntryKind != dwarf::DW_RLE_end_of_list)
199a0729d41SWolfgang Pieb       OS << ": ";
200a0729d41SWolfgang Pieb   }
201a0729d41SWolfgang Pieb 
2028036cf7fSDavid Blaikie   uint64_t Tombstone = dwarf::computeTombstoneAddress(AddrSize);
2038036cf7fSDavid Blaikie 
204439801baSWolfgang Pieb   switch (EntryKind) {
205a0729d41SWolfgang Pieb   case dwarf::DW_RLE_end_of_list:
206e74e0f11SAlexander Kornienko     OS << (DumpOpts.Verbose ? "" : "<End of list>");
207a0729d41SWolfgang Pieb     break;
20859ac2064SDavid Blaikie   case dwarf::DW_RLE_base_addressx: {
20959ac2064SDavid Blaikie     if (auto SA = LookupPooledAddress(Value0))
21059ac2064SDavid Blaikie       CurrentBase = SA->Address;
21159ac2064SDavid Blaikie     else
21259ac2064SDavid Blaikie       CurrentBase = Value0;
21359ac2064SDavid Blaikie     if (!DumpOpts.Verbose)
21459ac2064SDavid Blaikie       return;
215ea83e0b1SDavid Blaikie     DWARFFormValue::dumpAddress(OS << ' ', AddrSize, Value0);
21659ac2064SDavid Blaikie     break;
21759ac2064SDavid Blaikie   }
218ab068eaaSWolfgang Pieb   case dwarf::DW_RLE_base_address:
219e74e0f11SAlexander Kornienko     // In non-verbose mode we do not print anything for this entry.
220439801baSWolfgang Pieb     CurrentBase = Value0;
221ab068eaaSWolfgang Pieb     if (!DumpOpts.Verbose)
222ab068eaaSWolfgang Pieb       return;
223ea83e0b1SDavid Blaikie     DWARFFormValue::dumpAddress(OS << ' ', AddrSize, Value0);
224ab068eaaSWolfgang Pieb     break;
225a0729d41SWolfgang Pieb   case dwarf::DW_RLE_start_length:
226439801baSWolfgang Pieb     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
227439801baSWolfgang Pieb     DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
228a0729d41SWolfgang Pieb     break;
229ab068eaaSWolfgang Pieb   case dwarf::DW_RLE_offset_pair:
230439801baSWolfgang Pieb     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
2318036cf7fSDavid Blaikie     if (CurrentBase != Tombstone)
232439801baSWolfgang Pieb       DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
233ab068eaaSWolfgang Pieb           .dump(OS, AddrSize, DumpOpts);
2348036cf7fSDavid Blaikie     else
2358036cf7fSDavid Blaikie       OS << "dead code";
236ab068eaaSWolfgang Pieb     break;
237a0729d41SWolfgang Pieb   case dwarf::DW_RLE_start_end:
238439801baSWolfgang Pieb     DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts);
239a0729d41SWolfgang Pieb     break;
24059ac2064SDavid Blaikie   case dwarf::DW_RLE_startx_length: {
24159ac2064SDavid Blaikie     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
24259ac2064SDavid Blaikie     uint64_t Start = 0;
24359ac2064SDavid Blaikie     if (auto SA = LookupPooledAddress(Value0))
24459ac2064SDavid Blaikie       Start = SA->Address;
24559ac2064SDavid Blaikie     DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts);
24659ac2064SDavid Blaikie     break;
24740483e18SFangrui Song   }
24892c45e4eSDavid Blaikie   case dwarf::DW_RLE_startx_endx: {
24992c45e4eSDavid Blaikie     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
25092c45e4eSDavid Blaikie     uint64_t Start = 0;
25192c45e4eSDavid Blaikie     if (auto SA = LookupPooledAddress(Value0))
25292c45e4eSDavid Blaikie       Start = SA->Address;
25392c45e4eSDavid Blaikie     uint64_t End = 0;
25492c45e4eSDavid Blaikie     if (auto SA = LookupPooledAddress(Value1))
25592c45e4eSDavid Blaikie       End = SA->Address;
25692c45e4eSDavid Blaikie     DWARFAddressRange(Start, End).dump(OS, AddrSize, DumpOpts);
25792c45e4eSDavid Blaikie     break;
25892c45e4eSDavid Blaikie   }
259a0729d41SWolfgang Pieb   default:
260a0729d41SWolfgang Pieb     llvm_unreachable("Unsupported range list encoding");
261a0729d41SWolfgang Pieb   }
262a0729d41SWolfgang Pieb   OS << "\n";
263a0729d41SWolfgang Pieb }
264