1*c2dfd502SJames Henderson //===- DWARFDebugRnglists.cpp ---------------------------------------------===// 2*c2dfd502SJames Henderson // 3*c2dfd502SJames Henderson // The LLVM Compiler Infrastructure 4*c2dfd502SJames Henderson // 5*c2dfd502SJames Henderson // This file is distributed under the University of Illinois Open Source 6*c2dfd502SJames Henderson // License. See LICENSE.TXT for details. 7*c2dfd502SJames Henderson // 8*c2dfd502SJames Henderson //===----------------------------------------------------------------------===// 9*c2dfd502SJames Henderson 10*c2dfd502SJames Henderson #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" 11*c2dfd502SJames Henderson 12*c2dfd502SJames Henderson #include "llvm/BinaryFormat/Dwarf.h" 13*c2dfd502SJames Henderson #include "llvm/Support/Error.h" 14*c2dfd502SJames Henderson #include "llvm/Support/Format.h" 15*c2dfd502SJames Henderson #include "llvm/Support/raw_ostream.h" 16*c2dfd502SJames Henderson 17*c2dfd502SJames Henderson using namespace llvm; 18*c2dfd502SJames Henderson 19*c2dfd502SJames Henderson void DWARFDebugRnglists::clear() { 20*c2dfd502SJames Henderson HeaderData = {}; 21*c2dfd502SJames Henderson Offsets.clear(); 22*c2dfd502SJames Henderson Ranges.clear(); 23*c2dfd502SJames Henderson } 24*c2dfd502SJames Henderson 25*c2dfd502SJames Henderson template <typename... Ts> 26*c2dfd502SJames Henderson static Error createError(char const *Fmt, const Ts &... Vals) { 27*c2dfd502SJames Henderson std::string Buffer; 28*c2dfd502SJames Henderson raw_string_ostream Stream(Buffer); 29*c2dfd502SJames Henderson Stream << format(Fmt, Vals...); 30*c2dfd502SJames Henderson return make_error<StringError>(Stream.str(), inconvertibleErrorCode()); 31*c2dfd502SJames Henderson } 32*c2dfd502SJames Henderson 33*c2dfd502SJames Henderson Error DWARFDebugRnglists::extract(DWARFDataExtractor Data, 34*c2dfd502SJames Henderson uint32_t *OffsetPtr) { 35*c2dfd502SJames Henderson clear(); 36*c2dfd502SJames Henderson uint32_t TableOffset = *OffsetPtr; 37*c2dfd502SJames Henderson 38*c2dfd502SJames Henderson // Read and verify the length field. 39*c2dfd502SJames Henderson if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t))) 40*c2dfd502SJames Henderson return createError("section is not large enough to contain a " 41*c2dfd502SJames Henderson ".debug_rnglists table length at offset 0x%" PRIx32, 42*c2dfd502SJames Henderson *OffsetPtr); 43*c2dfd502SJames Henderson // TODO: Add support for DWARF64. 44*c2dfd502SJames Henderson HeaderData.Length = Data.getU32(OffsetPtr); 45*c2dfd502SJames Henderson if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) 46*c2dfd502SJames Henderson return createError(".debug_rnglists table at offset 0x%" PRIx32 47*c2dfd502SJames Henderson " has too small length (0x%" PRIx32 48*c2dfd502SJames Henderson ") to contain a complete header", 49*c2dfd502SJames Henderson TableOffset, length()); 50*c2dfd502SJames Henderson uint64_t End = TableOffset + length(); 51*c2dfd502SJames Henderson if (!Data.isValidOffsetForDataOfSize(TableOffset, End - TableOffset)) 52*c2dfd502SJames Henderson return createError( 53*c2dfd502SJames Henderson "section is not large enough to contain a .debug_rnglists table " 54*c2dfd502SJames Henderson "of length 0x%" PRIx32 " at offset 0x%" PRIx32, 55*c2dfd502SJames Henderson length(), TableOffset); 56*c2dfd502SJames Henderson 57*c2dfd502SJames Henderson HeaderData.Version = Data.getU16(OffsetPtr); 58*c2dfd502SJames Henderson HeaderData.AddrSize = Data.getU8(OffsetPtr); 59*c2dfd502SJames Henderson HeaderData.SegSize = Data.getU8(OffsetPtr); 60*c2dfd502SJames Henderson HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr); 61*c2dfd502SJames Henderson 62*c2dfd502SJames Henderson // Perform basic validation of the remaining header fields. 63*c2dfd502SJames Henderson if (HeaderData.Version != 5) 64*c2dfd502SJames Henderson return createError("unrecognised .debug_rnglists table version %" PRIu16 65*c2dfd502SJames Henderson " in table at offset 0x%" PRIx32, 66*c2dfd502SJames Henderson HeaderData.Version, TableOffset); 67*c2dfd502SJames Henderson if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) 68*c2dfd502SJames Henderson return createError(".debug_rnglists table at offset 0x%" PRIx32 69*c2dfd502SJames Henderson " has unsupported address size %hhu", 70*c2dfd502SJames Henderson TableOffset, HeaderData.AddrSize); 71*c2dfd502SJames Henderson if (HeaderData.SegSize != 0) 72*c2dfd502SJames Henderson return createError(".debug_rnglists table at offset 0x%" PRIx32 73*c2dfd502SJames Henderson " has unsupported segment selector size %" PRIu8, 74*c2dfd502SJames Henderson TableOffset, HeaderData.SegSize); 75*c2dfd502SJames Henderson if (End < TableOffset + sizeof(HeaderData) + 76*c2dfd502SJames Henderson HeaderData.OffsetEntryCount * sizeof(uint32_t)) 77*c2dfd502SJames Henderson return createError(".debug_rnglists table at offset 0x%" PRIx32 78*c2dfd502SJames Henderson " has more offset entries (%" PRIu32 79*c2dfd502SJames Henderson ") than there is space for", 80*c2dfd502SJames Henderson TableOffset, HeaderData.OffsetEntryCount); 81*c2dfd502SJames Henderson 82*c2dfd502SJames Henderson Data.setAddressSize(HeaderData.AddrSize); 83*c2dfd502SJames Henderson 84*c2dfd502SJames Henderson for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I) 85*c2dfd502SJames Henderson Offsets.push_back(Data.getU32(OffsetPtr)); 86*c2dfd502SJames Henderson 87*c2dfd502SJames Henderson DWARFAddressRangesVector CurrentRanges; 88*c2dfd502SJames Henderson while (*OffsetPtr < End) { 89*c2dfd502SJames Henderson uint8_t Encoding = Data.getU8(OffsetPtr); 90*c2dfd502SJames Henderson switch (Encoding) { 91*c2dfd502SJames Henderson case dwarf::DW_RLE_end_of_list: 92*c2dfd502SJames Henderson Ranges.insert(Ranges.end(), CurrentRanges); 93*c2dfd502SJames Henderson CurrentRanges.clear(); 94*c2dfd502SJames Henderson break; 95*c2dfd502SJames Henderson // TODO: Support other encodings. 96*c2dfd502SJames Henderson case dwarf::DW_RLE_base_addressx: 97*c2dfd502SJames Henderson return createError("unsupported rnglists encoding DW_RLE_base_addressx " 98*c2dfd502SJames Henderson "at offset 0x%" PRIx32, 99*c2dfd502SJames Henderson *OffsetPtr - 1); 100*c2dfd502SJames Henderson case dwarf::DW_RLE_startx_endx: 101*c2dfd502SJames Henderson return createError("unsupported rnglists encoding DW_RLE_startx_endx at " 102*c2dfd502SJames Henderson "offset 0x%" PRIx32, 103*c2dfd502SJames Henderson *OffsetPtr - 1); 104*c2dfd502SJames Henderson case dwarf::DW_RLE_startx_length: 105*c2dfd502SJames Henderson return createError("unsupported rnglists encoding DW_RLE_startx_length " 106*c2dfd502SJames Henderson "at offset 0x%" PRIx32, 107*c2dfd502SJames Henderson *OffsetPtr - 1); 108*c2dfd502SJames Henderson case dwarf::DW_RLE_offset_pair: 109*c2dfd502SJames Henderson return createError("unsupported rnglists encoding DW_RLE_offset_pair at " 110*c2dfd502SJames Henderson "offset 0x%" PRIx32, 111*c2dfd502SJames Henderson *OffsetPtr - 1); 112*c2dfd502SJames Henderson case dwarf::DW_RLE_base_address: 113*c2dfd502SJames Henderson return createError("unsupported rnglists encoding DW_RLE_base_address at " 114*c2dfd502SJames Henderson "offset 0x%" PRIx32, 115*c2dfd502SJames Henderson *OffsetPtr - 1); 116*c2dfd502SJames Henderson case dwarf::DW_RLE_start_end: { 117*c2dfd502SJames Henderson if (End - *OffsetPtr < HeaderData.AddrSize * 2) 118*c2dfd502SJames Henderson return createError("insufficient space remaining in table for " 119*c2dfd502SJames Henderson "DW_RLE_start_end encoding " 120*c2dfd502SJames Henderson "at offset 0x%" PRIx32, 121*c2dfd502SJames Henderson *OffsetPtr - 1); 122*c2dfd502SJames Henderson uint64_t Start = Data.getAddress(OffsetPtr); 123*c2dfd502SJames Henderson uint64_t End = Data.getAddress(OffsetPtr); 124*c2dfd502SJames Henderson CurrentRanges.emplace_back(Start, End); 125*c2dfd502SJames Henderson break; 126*c2dfd502SJames Henderson } 127*c2dfd502SJames Henderson case dwarf::DW_RLE_start_length: { 128*c2dfd502SJames Henderson uint32_t PreviousOffset = *OffsetPtr - 1; 129*c2dfd502SJames Henderson uint64_t Start = Data.getAddress(OffsetPtr); 130*c2dfd502SJames Henderson uint64_t Length = Data.getULEB128(OffsetPtr); 131*c2dfd502SJames Henderson if (End < *OffsetPtr) 132*c2dfd502SJames Henderson return createError("read past end of table when reading " 133*c2dfd502SJames Henderson "DW_RLE_start_length encoding at offset 0x%" PRIx32, 134*c2dfd502SJames Henderson PreviousOffset); 135*c2dfd502SJames Henderson CurrentRanges.emplace_back(Start, Start + Length); 136*c2dfd502SJames Henderson break; 137*c2dfd502SJames Henderson } 138*c2dfd502SJames Henderson default: 139*c2dfd502SJames Henderson Ranges.insert(Ranges.end(), CurrentRanges); 140*c2dfd502SJames Henderson return createError("unknown rnglists encoding 0x%" PRIx32 141*c2dfd502SJames Henderson " at offset 0x%" PRIx32, 142*c2dfd502SJames Henderson uint32_t(Encoding), *OffsetPtr - 1); 143*c2dfd502SJames Henderson } 144*c2dfd502SJames Henderson } 145*c2dfd502SJames Henderson 146*c2dfd502SJames Henderson // If OffsetPtr does not indicate the End offset, then either the above loop 147*c2dfd502SJames Henderson // terminated prematurely, or we encountered a malformed encoding, but did not 148*c2dfd502SJames Henderson // report an error when we should have done. 149*c2dfd502SJames Henderson assert(*OffsetPtr == End && 150*c2dfd502SJames Henderson "did not detect malformed data or loop ended unexpectedly"); 151*c2dfd502SJames Henderson 152*c2dfd502SJames Henderson // If CurrentRanges is not empty, we have a malformed section, because we did 153*c2dfd502SJames Henderson // not find a DW_RLE_end_of_list marker at the end of the last list. 154*c2dfd502SJames Henderson if (!CurrentRanges.empty()) 155*c2dfd502SJames Henderson return createError( 156*c2dfd502SJames Henderson "no end of list marker detected at end of .debug_rnglists table " 157*c2dfd502SJames Henderson "starting at offset 0x%" PRIx32, 158*c2dfd502SJames Henderson TableOffset); 159*c2dfd502SJames Henderson return Error::success(); 160*c2dfd502SJames Henderson } 161*c2dfd502SJames Henderson 162*c2dfd502SJames Henderson void DWARFDebugRnglists::dump(raw_ostream &OS) const { 163*c2dfd502SJames Henderson // TODO: Add verbose printing of the raw encodings. 164*c2dfd502SJames Henderson OS << format("Range List Header: length = 0x%8.8x, version = 0x%4.4x, " 165*c2dfd502SJames Henderson "addr_size = 0x%2.2x, seg_size = 0x%2.2x, offset_entry_count = " 166*c2dfd502SJames Henderson "0x%8.8x\n", 167*c2dfd502SJames Henderson HeaderData.Length, HeaderData.Version, HeaderData.AddrSize, 168*c2dfd502SJames Henderson HeaderData.SegSize, HeaderData.OffsetEntryCount); 169*c2dfd502SJames Henderson 170*c2dfd502SJames Henderson if (HeaderData.OffsetEntryCount > 0) { 171*c2dfd502SJames Henderson OS << "Offsets: ["; 172*c2dfd502SJames Henderson for (const auto &Off : Offsets) 173*c2dfd502SJames Henderson OS << format("\n0x%8.8x", Off); 174*c2dfd502SJames Henderson OS << "\n]\n"; 175*c2dfd502SJames Henderson } 176*c2dfd502SJames Henderson OS << "Ranges:\n"; 177*c2dfd502SJames Henderson 178*c2dfd502SJames Henderson const uint32_t HexWidth = HeaderData.AddrSize * 2; 179*c2dfd502SJames Henderson for (const auto &List : Ranges) { 180*c2dfd502SJames Henderson for (const auto &Entry : List) 181*c2dfd502SJames Henderson OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 ")\n", HexWidth, HexWidth, 182*c2dfd502SJames Henderson Entry.LowPC, HexWidth, HexWidth, Entry.HighPC); 183*c2dfd502SJames Henderson OS << "<End of list>\n"; 184*c2dfd502SJames Henderson } 185*c2dfd502SJames Henderson } 186*c2dfd502SJames Henderson 187*c2dfd502SJames Henderson uint64_t DWARFDebugRnglists::length() const { 188*c2dfd502SJames Henderson if (HeaderData.Length == 0) 189*c2dfd502SJames Henderson return 0; 190*c2dfd502SJames Henderson // TODO: DWARF64 support. 191*c2dfd502SJames Henderson return HeaderData.Length + sizeof(uint32_t); 192*c2dfd502SJames Henderson } 193