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