1c2dfd502SJames Henderson //===- DWARFDebugRnglists.cpp ---------------------------------------------===// 2c2dfd502SJames Henderson // 3c2dfd502SJames Henderson // The LLVM Compiler Infrastructure 4c2dfd502SJames Henderson // 5c2dfd502SJames Henderson // This file is distributed under the University of Illinois Open Source 6c2dfd502SJames Henderson // License. See LICENSE.TXT for details. 7c2dfd502SJames Henderson // 8c2dfd502SJames Henderson //===----------------------------------------------------------------------===// 9c2dfd502SJames Henderson 10c2dfd502SJames Henderson #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" 11c2dfd502SJames Henderson 12c2dfd502SJames Henderson #include "llvm/BinaryFormat/Dwarf.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 19c2dfd502SJames Henderson void DWARFDebugRnglists::clear() { 20c2dfd502SJames Henderson HeaderData = {}; 21c2dfd502SJames Henderson Offsets.clear(); 22c2dfd502SJames Henderson Ranges.clear(); 23c2dfd502SJames Henderson } 24c2dfd502SJames Henderson 25c2dfd502SJames Henderson template <typename... Ts> 26c2dfd502SJames Henderson static Error createError(char const *Fmt, const Ts &... Vals) { 27c2dfd502SJames Henderson std::string Buffer; 28c2dfd502SJames Henderson raw_string_ostream Stream(Buffer); 29c2dfd502SJames Henderson Stream << format(Fmt, Vals...); 30c2dfd502SJames Henderson return make_error<StringError>(Stream.str(), inconvertibleErrorCode()); 31c2dfd502SJames Henderson } 32c2dfd502SJames Henderson 33c2dfd502SJames Henderson Error DWARFDebugRnglists::extract(DWARFDataExtractor Data, 34c2dfd502SJames Henderson uint32_t *OffsetPtr) { 35c2dfd502SJames Henderson clear(); 36a0729d41SWolfgang Pieb HeaderOffset = *OffsetPtr; 37c2dfd502SJames Henderson 38c2dfd502SJames Henderson // Read and verify the length field. 39c2dfd502SJames Henderson if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t))) 40c2dfd502SJames Henderson return createError("section is not large enough to contain a " 41c2dfd502SJames Henderson ".debug_rnglists table length at offset 0x%" PRIx32, 42c2dfd502SJames Henderson *OffsetPtr); 43c2dfd502SJames Henderson // TODO: Add support for DWARF64. 44c2dfd502SJames Henderson HeaderData.Length = Data.getU32(OffsetPtr); 45a0729d41SWolfgang Pieb if (HeaderData.Length == 0xffffffffu) 46a0729d41SWolfgang Pieb return createError( 47a0729d41SWolfgang Pieb "DWARF64 is not supported in .debug_rnglists at offset 0x%" PRIx32, 48a0729d41SWolfgang Pieb HeaderOffset); 49c2dfd502SJames Henderson if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) 50c2dfd502SJames Henderson return createError(".debug_rnglists table at offset 0x%" PRIx32 51c2dfd502SJames Henderson " has too small length (0x%" PRIx32 52c2dfd502SJames Henderson ") to contain a complete header", 53a0729d41SWolfgang Pieb HeaderOffset, length()); 54a0729d41SWolfgang Pieb uint32_t End = HeaderOffset + length(); 55a0729d41SWolfgang Pieb if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) 56c2dfd502SJames Henderson return createError( 57c2dfd502SJames Henderson "section is not large enough to contain a .debug_rnglists table " 58c2dfd502SJames Henderson "of length 0x%" PRIx32 " at offset 0x%" PRIx32, 59a0729d41SWolfgang Pieb length(), HeaderOffset); 60c2dfd502SJames Henderson 61c2dfd502SJames Henderson HeaderData.Version = Data.getU16(OffsetPtr); 62c2dfd502SJames Henderson HeaderData.AddrSize = Data.getU8(OffsetPtr); 63c2dfd502SJames Henderson HeaderData.SegSize = Data.getU8(OffsetPtr); 64c2dfd502SJames Henderson HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr); 65c2dfd502SJames Henderson 66c2dfd502SJames Henderson // Perform basic validation of the remaining header fields. 67c2dfd502SJames Henderson if (HeaderData.Version != 5) 68c2dfd502SJames Henderson return createError("unrecognised .debug_rnglists table version %" PRIu16 69c2dfd502SJames Henderson " in table at offset 0x%" PRIx32, 70a0729d41SWolfgang Pieb HeaderData.Version, HeaderOffset); 71c2dfd502SJames Henderson if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) 72c2dfd502SJames Henderson return createError(".debug_rnglists table at offset 0x%" PRIx32 73c2dfd502SJames Henderson " has unsupported address size %hhu", 74a0729d41SWolfgang Pieb HeaderOffset, HeaderData.AddrSize); 75c2dfd502SJames Henderson if (HeaderData.SegSize != 0) 76c2dfd502SJames Henderson return createError(".debug_rnglists table at offset 0x%" PRIx32 77c2dfd502SJames Henderson " has unsupported segment selector size %" PRIu8, 78a0729d41SWolfgang Pieb HeaderOffset, HeaderData.SegSize); 79a0729d41SWolfgang Pieb if (End < HeaderOffset + sizeof(HeaderData) + 80c2dfd502SJames Henderson HeaderData.OffsetEntryCount * sizeof(uint32_t)) 81c2dfd502SJames Henderson return createError(".debug_rnglists table at offset 0x%" PRIx32 82c2dfd502SJames Henderson " has more offset entries (%" PRIu32 83c2dfd502SJames Henderson ") than there is space for", 84a0729d41SWolfgang Pieb HeaderOffset, HeaderData.OffsetEntryCount); 85c2dfd502SJames Henderson 86c2dfd502SJames Henderson Data.setAddressSize(HeaderData.AddrSize); 87c2dfd502SJames Henderson 88c2dfd502SJames Henderson for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I) 89c2dfd502SJames Henderson Offsets.push_back(Data.getU32(OffsetPtr)); 90c2dfd502SJames Henderson 91a0729d41SWolfgang Pieb DWARFRangeList CurrentRanges; 92c2dfd502SJames Henderson while (*OffsetPtr < End) { 93a0729d41SWolfgang Pieb uint32_t EntryOffset = *OffsetPtr; 94c2dfd502SJames Henderson uint8_t Encoding = Data.getU8(OffsetPtr); 95a0729d41SWolfgang Pieb MaxEncodingStringLength = 96a0729d41SWolfgang Pieb std::max(MaxEncodingStringLength, 97a0729d41SWolfgang Pieb (uint8_t)dwarf::RangeListEncodingString(Encoding).size()); 98c2dfd502SJames Henderson switch (Encoding) { 99c2dfd502SJames Henderson case dwarf::DW_RLE_end_of_list: 100145bc6e0SZachary Turner CurrentRanges.push_back(RangeListEntry{ EntryOffset, Encoding, 0, 0 }); 10170e6faaaSBenjamin Kramer Ranges.insert(Ranges.end(), std::move(CurrentRanges)); 102c2dfd502SJames Henderson CurrentRanges.clear(); 103c2dfd502SJames Henderson break; 104c2dfd502SJames Henderson // TODO: Support other encodings. 105c2dfd502SJames Henderson case dwarf::DW_RLE_base_addressx: 106c2dfd502SJames Henderson return createError("unsupported rnglists encoding DW_RLE_base_addressx " 107c2dfd502SJames Henderson "at offset 0x%" PRIx32, 108c2dfd502SJames Henderson *OffsetPtr - 1); 109c2dfd502SJames Henderson case dwarf::DW_RLE_startx_endx: 110c2dfd502SJames Henderson return createError("unsupported rnglists encoding DW_RLE_startx_endx at " 111c2dfd502SJames Henderson "offset 0x%" PRIx32, 112c2dfd502SJames Henderson *OffsetPtr - 1); 113c2dfd502SJames Henderson case dwarf::DW_RLE_startx_length: 114c2dfd502SJames Henderson return createError("unsupported rnglists encoding DW_RLE_startx_length " 115c2dfd502SJames Henderson "at offset 0x%" PRIx32, 116c2dfd502SJames Henderson *OffsetPtr - 1); 117*ab068eaaSWolfgang Pieb case dwarf::DW_RLE_offset_pair: { 118*ab068eaaSWolfgang Pieb uint32_t PreviousOffset = *OffsetPtr - 1; 119*ab068eaaSWolfgang Pieb uint64_t StartingOffset = Data.getULEB128(OffsetPtr); 120*ab068eaaSWolfgang Pieb uint64_t EndingOffset = Data.getULEB128(OffsetPtr); 121*ab068eaaSWolfgang Pieb if (End < *OffsetPtr) 122*ab068eaaSWolfgang Pieb return createError("read past end of table when reading " 123*ab068eaaSWolfgang Pieb "DW_RLE_offset_pair encoding at offset 0x%" PRIx32, 124*ab068eaaSWolfgang Pieb PreviousOffset); 125*ab068eaaSWolfgang Pieb CurrentRanges.push_back( 126*ab068eaaSWolfgang Pieb RangeListEntry{EntryOffset, Encoding, StartingOffset, EndingOffset}); 127*ab068eaaSWolfgang Pieb break; 128*ab068eaaSWolfgang Pieb } 129*ab068eaaSWolfgang Pieb case dwarf::DW_RLE_base_address: { 130*ab068eaaSWolfgang Pieb if ((End - *OffsetPtr) < HeaderData.AddrSize) 131*ab068eaaSWolfgang Pieb return createError("insufficient space remaining in table for " 132*ab068eaaSWolfgang Pieb "DW_RLE_base_address encoding at offset 0x%" PRIx32, 133c2dfd502SJames Henderson *OffsetPtr - 1); 134*ab068eaaSWolfgang Pieb uint64_t Base = Data.getAddress(OffsetPtr); 135*ab068eaaSWolfgang Pieb CurrentRanges.push_back(RangeListEntry{EntryOffset, Encoding, Base, 0}); 136*ab068eaaSWolfgang Pieb break; 137*ab068eaaSWolfgang Pieb } 138c2dfd502SJames Henderson case dwarf::DW_RLE_start_end: { 1393d5ee7aaSSimon Pilgrim if ((End - *OffsetPtr) < unsigned(HeaderData.AddrSize * 2)) 140c2dfd502SJames Henderson return createError("insufficient space remaining in table for " 141c2dfd502SJames Henderson "DW_RLE_start_end encoding " 142c2dfd502SJames Henderson "at offset 0x%" PRIx32, 143c2dfd502SJames Henderson *OffsetPtr - 1); 144c2dfd502SJames Henderson uint64_t Start = Data.getAddress(OffsetPtr); 145c2dfd502SJames Henderson uint64_t End = Data.getAddress(OffsetPtr); 146a0729d41SWolfgang Pieb CurrentRanges.push_back( 147a0729d41SWolfgang Pieb RangeListEntry{EntryOffset, Encoding, Start, End}); 148c2dfd502SJames Henderson break; 149c2dfd502SJames Henderson } 150c2dfd502SJames Henderson case dwarf::DW_RLE_start_length: { 151c2dfd502SJames Henderson uint32_t PreviousOffset = *OffsetPtr - 1; 152c2dfd502SJames Henderson uint64_t Start = Data.getAddress(OffsetPtr); 153c2dfd502SJames Henderson uint64_t Length = Data.getULEB128(OffsetPtr); 154c2dfd502SJames Henderson if (End < *OffsetPtr) 155c2dfd502SJames Henderson return createError("read past end of table when reading " 156c2dfd502SJames Henderson "DW_RLE_start_length encoding at offset 0x%" PRIx32, 157c2dfd502SJames Henderson PreviousOffset); 158a0729d41SWolfgang Pieb CurrentRanges.push_back( 159a0729d41SWolfgang Pieb RangeListEntry{EntryOffset, Encoding, Start, Length}); 160c2dfd502SJames Henderson break; 161c2dfd502SJames Henderson } 162c2dfd502SJames Henderson default: 16370e6faaaSBenjamin Kramer Ranges.insert(Ranges.end(), std::move(CurrentRanges)); 164c2dfd502SJames Henderson return createError("unknown rnglists encoding 0x%" PRIx32 165c2dfd502SJames Henderson " at offset 0x%" PRIx32, 166c2dfd502SJames Henderson uint32_t(Encoding), *OffsetPtr - 1); 167c2dfd502SJames Henderson } 168c2dfd502SJames Henderson } 169c2dfd502SJames Henderson 170c2dfd502SJames Henderson // If OffsetPtr does not indicate the End offset, then either the above loop 171c2dfd502SJames Henderson // terminated prematurely, or we encountered a malformed encoding, but did not 172c2dfd502SJames Henderson // report an error when we should have done. 173c2dfd502SJames Henderson assert(*OffsetPtr == End && 174c2dfd502SJames Henderson "did not detect malformed data or loop ended unexpectedly"); 175c2dfd502SJames Henderson 176c2dfd502SJames Henderson // If CurrentRanges is not empty, we have a malformed section, because we did 177c2dfd502SJames Henderson // not find a DW_RLE_end_of_list marker at the end of the last list. 178c2dfd502SJames Henderson if (!CurrentRanges.empty()) 179c2dfd502SJames Henderson return createError( 180c2dfd502SJames Henderson "no end of list marker detected at end of .debug_rnglists table " 181c2dfd502SJames Henderson "starting at offset 0x%" PRIx32, 182a0729d41SWolfgang Pieb HeaderOffset); 183c2dfd502SJames Henderson return Error::success(); 184c2dfd502SJames Henderson } 185c2dfd502SJames Henderson 186a0729d41SWolfgang Pieb static void dumpRangeEntry(raw_ostream &OS, 187a0729d41SWolfgang Pieb DWARFDebugRnglists::RangeListEntry Entry, 188a0729d41SWolfgang Pieb uint8_t AddrSize, uint8_t MaxEncodingStringLength, 189*ab068eaaSWolfgang Pieb uint64_t &CurrentBase, DIDumpOptions DumpOpts) { 190*ab068eaaSWolfgang Pieb auto PrintRawEntry = [](raw_ostream &OS, 191*ab068eaaSWolfgang Pieb DWARFDebugRnglists::RangeListEntry Entry, 192*ab068eaaSWolfgang Pieb uint8_t AddrSize, DIDumpOptions DumpOpts) { 193*ab068eaaSWolfgang Pieb if (DumpOpts.Verbose) { 194*ab068eaaSWolfgang Pieb DumpOpts.DisplayRawContents = true; 195*ab068eaaSWolfgang Pieb DWARFAddressRange(Entry.Value0, Entry.Value1) 196*ab068eaaSWolfgang Pieb .dump(OS, AddrSize, DumpOpts); 197*ab068eaaSWolfgang Pieb OS << " => "; 198*ab068eaaSWolfgang Pieb } 199*ab068eaaSWolfgang Pieb }; 200*ab068eaaSWolfgang Pieb 201a0729d41SWolfgang Pieb if (DumpOpts.Verbose) { 202a0729d41SWolfgang Pieb // Print the section offset in verbose mode. 203a0729d41SWolfgang Pieb OS << format("0x%8.8" PRIx32 ":", Entry.Offset); 204a0729d41SWolfgang Pieb auto EncodingString = dwarf::RangeListEncodingString(Entry.EntryKind); 205a0729d41SWolfgang Pieb // Unsupported encodings should have been reported during parsing. 206a0729d41SWolfgang Pieb assert(!EncodingString.empty() && "Unknown range entry encoding"); 207a0729d41SWolfgang Pieb OS << format(" [%s%*c", EncodingString.data(), 208a0729d41SWolfgang Pieb MaxEncodingStringLength - EncodingString.size() + 1, ']'); 209a0729d41SWolfgang Pieb if (Entry.EntryKind != dwarf::DW_RLE_end_of_list) 210a0729d41SWolfgang Pieb OS << ": "; 211a0729d41SWolfgang Pieb } 212a0729d41SWolfgang Pieb 213a0729d41SWolfgang Pieb switch (Entry.EntryKind) { 214a0729d41SWolfgang Pieb case dwarf::DW_RLE_end_of_list: 215a0729d41SWolfgang Pieb OS << (DumpOpts.Verbose ? "" : "<End of list>"); 216a0729d41SWolfgang Pieb break; 217*ab068eaaSWolfgang Pieb case dwarf::DW_RLE_base_address: 218*ab068eaaSWolfgang Pieb // In non-verbose mode we do not print anything for this entry. 219*ab068eaaSWolfgang Pieb CurrentBase = Entry.Value0; 220*ab068eaaSWolfgang Pieb if (!DumpOpts.Verbose) 221*ab068eaaSWolfgang Pieb return; 222*ab068eaaSWolfgang Pieb OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Entry.Value0); 223*ab068eaaSWolfgang Pieb break; 224a0729d41SWolfgang Pieb case dwarf::DW_RLE_start_length: 225*ab068eaaSWolfgang Pieb PrintRawEntry(OS, Entry, AddrSize, DumpOpts); 226a0729d41SWolfgang Pieb DWARFAddressRange(Entry.Value0, Entry.Value0 + Entry.Value1) 227a0729d41SWolfgang Pieb .dump(OS, AddrSize, DumpOpts); 228a0729d41SWolfgang Pieb break; 229*ab068eaaSWolfgang Pieb case dwarf::DW_RLE_offset_pair: 230*ab068eaaSWolfgang Pieb PrintRawEntry(OS, Entry, AddrSize, DumpOpts); 231*ab068eaaSWolfgang Pieb DWARFAddressRange(Entry.Value0 + CurrentBase, Entry.Value1 + CurrentBase) 232*ab068eaaSWolfgang Pieb .dump(OS, AddrSize, DumpOpts); 233*ab068eaaSWolfgang Pieb break; 234a0729d41SWolfgang Pieb case dwarf::DW_RLE_start_end: 235a0729d41SWolfgang Pieb DWARFAddressRange(Entry.Value0, Entry.Value1).dump(OS, AddrSize, DumpOpts); 236a0729d41SWolfgang Pieb break; 237a0729d41SWolfgang Pieb default: 238a0729d41SWolfgang Pieb llvm_unreachable("Unsupported range list encoding"); 239a0729d41SWolfgang Pieb } 240a0729d41SWolfgang Pieb OS << "\n"; 241a0729d41SWolfgang Pieb } 242a0729d41SWolfgang Pieb 243a0729d41SWolfgang Pieb void DWARFDebugRnglists::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { 244a0729d41SWolfgang Pieb if (DumpOpts.Verbose) 245a0729d41SWolfgang Pieb OS << format("0x%8.8" PRIx32 ": ", HeaderOffset); 24610392cdbSJames Henderson OS << format("Range List Header: length = 0x%8.8" PRIx32 24710392cdbSJames Henderson ", version = 0x%4.4" PRIx16 ", " 24810392cdbSJames Henderson "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 24910392cdbSJames Henderson ", offset_entry_count = " 25010392cdbSJames Henderson "0x%8.8" PRIx32 "\n", 251c2dfd502SJames Henderson HeaderData.Length, HeaderData.Version, HeaderData.AddrSize, 252c2dfd502SJames Henderson HeaderData.SegSize, HeaderData.OffsetEntryCount); 253c2dfd502SJames Henderson 254c2dfd502SJames Henderson if (HeaderData.OffsetEntryCount > 0) { 255c2dfd502SJames Henderson OS << "Offsets: ["; 256a0729d41SWolfgang Pieb for (const auto &Off : Offsets) { 25710392cdbSJames Henderson OS << format("\n0x%8.8" PRIx32, Off); 258a0729d41SWolfgang Pieb if (DumpOpts.Verbose) 259a0729d41SWolfgang Pieb OS << format(" => 0x%8.8" PRIx32, 260a0729d41SWolfgang Pieb Off + HeaderOffset + sizeof(HeaderData)); 261a0729d41SWolfgang Pieb } 262c2dfd502SJames Henderson OS << "\n]\n"; 263c2dfd502SJames Henderson } 264c2dfd502SJames Henderson OS << "Ranges:\n"; 265c2dfd502SJames Henderson 266*ab068eaaSWolfgang Pieb uint64_t CurrentBase = 0; 267a0729d41SWolfgang Pieb for (const auto &List : Ranges) 268c2dfd502SJames Henderson for (const auto &Entry : List) 269a0729d41SWolfgang Pieb dumpRangeEntry(OS, Entry, HeaderData.AddrSize, MaxEncodingStringLength, 270*ab068eaaSWolfgang Pieb CurrentBase, DumpOpts); 271c2dfd502SJames Henderson } 272c2dfd502SJames Henderson 27324656332SJames Henderson uint32_t DWARFDebugRnglists::length() const { 274c2dfd502SJames Henderson if (HeaderData.Length == 0) 275c2dfd502SJames Henderson return 0; 276c2dfd502SJames Henderson // TODO: DWARF64 support. 277c2dfd502SJames Henderson return HeaderData.Length + sizeof(uint32_t); 278c2dfd502SJames Henderson } 279