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