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 19f26a70a5SIgor Kudrin Error RangeListEntry::extract(DWARFDataExtractor Data, uint64_t End, 20f26a70a5SIgor 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: { 35f26a70a5SIgor 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 " 41f26a70a5SIgor 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 " 48f26a70a5SIgor Kudrin "offset 0x%" PRIx64, 49c2dfd502SJames Henderson *OffsetPtr - 1); 5059ac2064SDavid Blaikie case dwarf::DW_RLE_startx_length: { 51f26a70a5SIgor 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 " 58f26a70a5SIgor 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: { 63f26a70a5SIgor 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 " 69f26a70a5SIgor 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 " 77f26a70a5SIgor 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 " 87f26a70a5SIgor 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: { 94f26a70a5SIgor 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 " 100f26a70a5SIgor 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 107f26a70a5SIgor 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 { 117*d34927e7SPavel Labath return getAbsoluteRanges(BaseAddr, [&](uint32_t Index) { 118*d34927e7SPavel Labath return U.getAddrOffsetSectionItem(Index); 119*d34927e7SPavel Labath }); 120*d34927e7SPavel Labath } 121*d34927e7SPavel Labath 122*d34927e7SPavel Labath DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges( 123*d34927e7SPavel Labath Optional<object::SectionedAddress> BaseAddr, 124*d34927e7SPavel Labath function_ref<Optional<object::SectionedAddress>(uint32_t)> 125*d34927e7SPavel Labath LookupPooledAddress) const { 126ad60559bSWolfgang Pieb DWARFAddressRangesVector Res; 127ad60559bSWolfgang Pieb for (const RangeListEntry &RLE : Entries) { 128ad60559bSWolfgang Pieb if (RLE.EntryKind == dwarf::DW_RLE_end_of_list) 129ad60559bSWolfgang Pieb break; 13059ac2064SDavid Blaikie if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) { 131*d34927e7SPavel Labath BaseAddr = LookupPooledAddress(RLE.Value0); 13259ac2064SDavid Blaikie if (!BaseAddr) 1336d85c583SGeorge Rimar BaseAddr = {RLE.Value0, -1ULL}; 13459ac2064SDavid Blaikie continue; 13559ac2064SDavid Blaikie } 136ad60559bSWolfgang Pieb if (RLE.EntryKind == dwarf::DW_RLE_base_address) { 137ad60559bSWolfgang Pieb BaseAddr = {RLE.Value0, RLE.SectionIndex}; 138ad60559bSWolfgang Pieb continue; 139ad60559bSWolfgang Pieb } 140ad60559bSWolfgang Pieb 141ad60559bSWolfgang Pieb DWARFAddressRange E; 142ad60559bSWolfgang Pieb E.SectionIndex = RLE.SectionIndex; 143ad60559bSWolfgang Pieb if (BaseAddr && E.SectionIndex == -1ULL) 144ad60559bSWolfgang Pieb E.SectionIndex = BaseAddr->SectionIndex; 145ad60559bSWolfgang Pieb 146ad60559bSWolfgang Pieb switch (RLE.EntryKind) { 147ad60559bSWolfgang Pieb case dwarf::DW_RLE_offset_pair: 148ad60559bSWolfgang Pieb E.LowPC = RLE.Value0; 149ad60559bSWolfgang Pieb E.HighPC = RLE.Value1; 150ad60559bSWolfgang Pieb if (BaseAddr) { 151ad60559bSWolfgang Pieb E.LowPC += BaseAddr->Address; 152ad60559bSWolfgang Pieb E.HighPC += BaseAddr->Address; 153ad60559bSWolfgang Pieb } 154ad60559bSWolfgang Pieb break; 155ad60559bSWolfgang Pieb case dwarf::DW_RLE_start_end: 156ad60559bSWolfgang Pieb E.LowPC = RLE.Value0; 157ad60559bSWolfgang Pieb E.HighPC = RLE.Value1; 158ad60559bSWolfgang Pieb break; 159ad60559bSWolfgang Pieb case dwarf::DW_RLE_start_length: 160ad60559bSWolfgang Pieb E.LowPC = RLE.Value0; 161ad60559bSWolfgang Pieb E.HighPC = E.LowPC + RLE.Value1; 162ad60559bSWolfgang Pieb break; 16359ac2064SDavid Blaikie case dwarf::DW_RLE_startx_length: { 164*d34927e7SPavel Labath auto Start = LookupPooledAddress(RLE.Value0); 16559ac2064SDavid Blaikie if (!Start) 1666d85c583SGeorge Rimar Start = {0, -1ULL}; 16759ac2064SDavid Blaikie E.SectionIndex = Start->SectionIndex; 16859ac2064SDavid Blaikie E.LowPC = Start->Address; 16959ac2064SDavid Blaikie E.HighPC = E.LowPC + RLE.Value1; 17059ac2064SDavid Blaikie break; 17159ac2064SDavid Blaikie } 172ad60559bSWolfgang Pieb default: 173ad60559bSWolfgang Pieb // Unsupported encodings should have been reported during extraction, 174ad60559bSWolfgang Pieb // so we should not run into any here. 175ad60559bSWolfgang Pieb llvm_unreachable("Unsupported range list encoding"); 176ad60559bSWolfgang Pieb } 177ad60559bSWolfgang Pieb Res.push_back(E); 178ad60559bSWolfgang Pieb } 179ad60559bSWolfgang Pieb return Res; 180ad60559bSWolfgang Pieb } 181ad60559bSWolfgang Pieb 18259ac2064SDavid Blaikie void RangeListEntry::dump( 183f39a9bbeSWolfgang Pieb raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength, 184f39a9bbeSWolfgang Pieb uint64_t &CurrentBase, DIDumpOptions DumpOpts, 18577fc1f60SAlexey Lapshin llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)> 18659ac2064SDavid Blaikie LookupPooledAddress) const { 187439801baSWolfgang Pieb auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry, 188ab068eaaSWolfgang Pieb uint8_t AddrSize, DIDumpOptions DumpOpts) { 189ab068eaaSWolfgang Pieb if (DumpOpts.Verbose) { 190ab068eaaSWolfgang Pieb DumpOpts.DisplayRawContents = true; 191ab068eaaSWolfgang Pieb DWARFAddressRange(Entry.Value0, Entry.Value1) 192ab068eaaSWolfgang Pieb .dump(OS, AddrSize, DumpOpts); 193ab068eaaSWolfgang Pieb OS << " => "; 194ab068eaaSWolfgang Pieb } 195ab068eaaSWolfgang Pieb }; 196ab068eaaSWolfgang Pieb 197a0729d41SWolfgang Pieb if (DumpOpts.Verbose) { 198a0729d41SWolfgang Pieb // Print the section offset in verbose mode. 199f26a70a5SIgor Kudrin OS << format("0x%8.8" PRIx64 ":", Offset); 200439801baSWolfgang Pieb auto EncodingString = dwarf::RangeListEncodingString(EntryKind); 201a0729d41SWolfgang Pieb // Unsupported encodings should have been reported during parsing. 202a0729d41SWolfgang Pieb assert(!EncodingString.empty() && "Unknown range entry encoding"); 203a0729d41SWolfgang Pieb OS << format(" [%s%*c", EncodingString.data(), 204a0729d41SWolfgang Pieb MaxEncodingStringLength - EncodingString.size() + 1, ']'); 205f39a9bbeSWolfgang Pieb if (EntryKind != dwarf::DW_RLE_end_of_list) 206a0729d41SWolfgang Pieb OS << ": "; 207a0729d41SWolfgang Pieb } 208a0729d41SWolfgang Pieb 209439801baSWolfgang Pieb switch (EntryKind) { 210a0729d41SWolfgang Pieb case dwarf::DW_RLE_end_of_list: 211e74e0f11SAlexander Kornienko OS << (DumpOpts.Verbose ? "" : "<End of list>"); 212a0729d41SWolfgang Pieb break; 21359ac2064SDavid Blaikie case dwarf::DW_RLE_base_addressx: { 21459ac2064SDavid Blaikie if (auto SA = LookupPooledAddress(Value0)) 21559ac2064SDavid Blaikie CurrentBase = SA->Address; 21659ac2064SDavid Blaikie else 21759ac2064SDavid Blaikie CurrentBase = Value0; 21859ac2064SDavid Blaikie if (!DumpOpts.Verbose) 21959ac2064SDavid Blaikie return; 22059ac2064SDavid Blaikie OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0); 22159ac2064SDavid Blaikie break; 22259ac2064SDavid Blaikie } 223ab068eaaSWolfgang Pieb case dwarf::DW_RLE_base_address: 224e74e0f11SAlexander Kornienko // In non-verbose mode we do not print anything for this entry. 225439801baSWolfgang Pieb CurrentBase = Value0; 226ab068eaaSWolfgang Pieb if (!DumpOpts.Verbose) 227ab068eaaSWolfgang Pieb return; 228439801baSWolfgang Pieb OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0); 229ab068eaaSWolfgang Pieb break; 230a0729d41SWolfgang Pieb case dwarf::DW_RLE_start_length: 231439801baSWolfgang Pieb PrintRawEntry(OS, *this, AddrSize, DumpOpts); 232439801baSWolfgang Pieb DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts); 233a0729d41SWolfgang Pieb break; 234ab068eaaSWolfgang Pieb case dwarf::DW_RLE_offset_pair: 235439801baSWolfgang Pieb PrintRawEntry(OS, *this, AddrSize, DumpOpts); 236439801baSWolfgang Pieb DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase) 237ab068eaaSWolfgang Pieb .dump(OS, AddrSize, DumpOpts); 238ab068eaaSWolfgang Pieb break; 239a0729d41SWolfgang Pieb case dwarf::DW_RLE_start_end: 240439801baSWolfgang Pieb DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts); 241a0729d41SWolfgang Pieb break; 24259ac2064SDavid Blaikie case dwarf::DW_RLE_startx_length: { 24359ac2064SDavid Blaikie PrintRawEntry(OS, *this, AddrSize, DumpOpts); 24459ac2064SDavid Blaikie uint64_t Start = 0; 24559ac2064SDavid Blaikie if (auto SA = LookupPooledAddress(Value0)) 24659ac2064SDavid Blaikie Start = SA->Address; 24759ac2064SDavid Blaikie DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts); 24859ac2064SDavid Blaikie break; 24940483e18SFangrui Song } 250a0729d41SWolfgang Pieb default: 251a0729d41SWolfgang Pieb llvm_unreachable("Unsupported range list encoding"); 252a0729d41SWolfgang Pieb } 253a0729d41SWolfgang Pieb OS << "\n"; 254a0729d41SWolfgang Pieb } 255