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 DWARFDebugRnglistTable::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 DWARFDebugRnglistTable::extractHeaderAndOffsets(DWARFDataExtractor Data, 34 uint32_t *OffsetPtr) { 35 HeaderOffset = *OffsetPtr; 36 // Read and verify the length field. 37 if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t))) 38 return createError("section is not large enough to contain a " 39 ".debug_rnglists table length at offset 0x%" PRIx32, 40 *OffsetPtr); 41 // TODO: Add support for DWARF64. 42 HeaderData.Length = Data.getU32(OffsetPtr); 43 if (HeaderData.Length == 0xffffffffu) 44 return createError( 45 "DWARF64 is not supported in .debug_rnglists at offset 0x%" PRIx32, 46 HeaderOffset); 47 if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) 48 return createError(".debug_rnglists table at offset 0x%" PRIx32 49 " has too small length (0x%" PRIx32 50 ") to contain a complete header", 51 HeaderOffset, length()); 52 uint32_t End = HeaderOffset + length(); 53 if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) 54 return createError( 55 "section is not large enough to contain a .debug_rnglists table " 56 "of length 0x%" PRIx32 " at offset 0x%" PRIx32, 57 length(), HeaderOffset); 58 59 HeaderData.Version = Data.getU16(OffsetPtr); 60 HeaderData.AddrSize = Data.getU8(OffsetPtr); 61 HeaderData.SegSize = Data.getU8(OffsetPtr); 62 HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr); 63 64 // Perform basic validation of the remaining header fields. 65 if (HeaderData.Version != 5) 66 return createError("unrecognised .debug_rnglists table version %" PRIu16 67 " in table at offset 0x%" PRIx32, 68 HeaderData.Version, HeaderOffset); 69 if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) 70 return createError(".debug_rnglists table at offset 0x%" PRIx32 71 " has unsupported address size %hhu", 72 HeaderOffset, HeaderData.AddrSize); 73 if (HeaderData.SegSize != 0) 74 return createError(".debug_rnglists table at offset 0x%" PRIx32 75 " has unsupported segment selector size %" PRIu8, 76 HeaderOffset, HeaderData.SegSize); 77 if (End < HeaderOffset + sizeof(HeaderData) + 78 HeaderData.OffsetEntryCount * sizeof(uint32_t)) 79 return createError(".debug_rnglists table at offset 0x%" PRIx32 80 " has more offset entries (%" PRIu32 81 ") than there is space for", 82 HeaderOffset, HeaderData.OffsetEntryCount); 83 Data.setAddressSize(HeaderData.AddrSize); 84 for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I) 85 Offsets.push_back(Data.getU32(OffsetPtr)); 86 return Error::success(); 87 } 88 89 Error DWARFDebugRnglist::RangeListEntry::extract(DWARFDataExtractor Data, 90 uint32_t End, 91 uint32_t *OffsetPtr) { 92 Offset = *OffsetPtr; 93 // The caller should guarantee that we have at least 1 byte available, so 94 // we just assert instead of revalidate. 95 assert(*OffsetPtr < End && 96 "not enough space to extract a rangelist encoding"); 97 uint8_t Encoding = Data.getU8(OffsetPtr); 98 99 switch (Encoding) { 100 case dwarf::DW_RLE_end_of_list: 101 Value0 = Value1 = 0; 102 break; 103 // TODO: Support other encodings. 104 case dwarf::DW_RLE_base_addressx: 105 return createError("unsupported rnglists encoding DW_RLE_base_addressx " 106 "at offset 0x%" PRIx32, 107 *OffsetPtr - 1); 108 case dwarf::DW_RLE_startx_endx: 109 return createError("unsupported rnglists encoding DW_RLE_startx_endx at " 110 "offset 0x%" PRIx32, 111 *OffsetPtr - 1); 112 case dwarf::DW_RLE_startx_length: 113 return createError("unsupported rnglists encoding DW_RLE_startx_length " 114 "at offset 0x%" PRIx32, 115 *OffsetPtr - 1); 116 case dwarf::DW_RLE_offset_pair: { 117 uint32_t PreviousOffset = *OffsetPtr - 1; 118 Value0 = Data.getULEB128(OffsetPtr); 119 Value1 = Data.getULEB128(OffsetPtr); 120 if (End < *OffsetPtr) 121 return createError("read past end of table when reading " 122 "DW_RLE_offset_pair encoding at offset 0x%" PRIx32, 123 PreviousOffset); 124 break; 125 } 126 case dwarf::DW_RLE_base_address: { 127 if ((End - *OffsetPtr) < Data.getAddressSize()) 128 return createError("insufficient space remaining in table for " 129 "DW_RLE_base_address encoding at offset 0x%" PRIx32, 130 *OffsetPtr - 1); 131 Value0 = Data.getAddress(OffsetPtr); 132 break; 133 } 134 case dwarf::DW_RLE_start_end: { 135 if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2)) 136 return createError("insufficient space remaining in table for " 137 "DW_RLE_start_end encoding " 138 "at offset 0x%" PRIx32, 139 *OffsetPtr - 1); 140 Value0 = Data.getAddress(OffsetPtr); 141 Value1 = Data.getAddress(OffsetPtr); 142 break; 143 } 144 case dwarf::DW_RLE_start_length: { 145 uint32_t PreviousOffset = *OffsetPtr - 1; 146 Value0 = Data.getAddress(OffsetPtr); 147 Value1 = Data.getULEB128(OffsetPtr); 148 if (End < *OffsetPtr) 149 return createError("read past end of table when reading " 150 "DW_RLE_start_length encoding at offset 0x%" PRIx32, 151 PreviousOffset); 152 break; 153 } 154 default: 155 return createError("unknown rnglists encoding 0x%" PRIx32 156 " at offset 0x%" PRIx32, 157 uint32_t(Encoding), *OffsetPtr - 1); 158 } 159 160 EntryKind = Encoding; 161 return Error::success(); 162 } 163 164 Error DWARFDebugRnglist::extract(DWARFDataExtractor Data, uint32_t HeaderOffset, 165 uint32_t End, uint32_t *OffsetPtr) { 166 Entries.clear(); 167 while (*OffsetPtr < End) { 168 RangeListEntry Entry{0, 0, 0, 0}; 169 if (Error E = Entry.extract(Data, End, OffsetPtr)) 170 return E; 171 Entries.push_back(Entry); 172 if (Entry.EntryKind == dwarf::DW_RLE_end_of_list) 173 return Error::success(); 174 } 175 return createError( 176 "no end of list marker detected at end of .debug_rnglists table " 177 "starting at offset 0x%" PRIx32, 178 HeaderOffset); 179 } 180 181 Error DWARFDebugRnglistTable::extract(DWARFDataExtractor Data, 182 uint32_t *OffsetPtr) { 183 clear(); 184 if (Error E = extractHeaderAndOffsets(Data, OffsetPtr)) 185 return E; 186 187 Data.setAddressSize(HeaderData.AddrSize); 188 uint32_t End = HeaderOffset + length(); 189 while (*OffsetPtr < End) { 190 DWARFDebugRnglist CurrentRangeList; 191 uint32_t Off = *OffsetPtr; 192 if (Error E = CurrentRangeList.extract(Data, HeaderOffset, End, OffsetPtr)) 193 return E; 194 Ranges[Off] = CurrentRangeList; 195 } 196 197 assert(*OffsetPtr == End && 198 "mismatch between expected length of .debug_rnglists table and length " 199 "of extracted data"); 200 return Error::success(); 201 } 202 203 static void dumpRangeEntry(raw_ostream &OS, 204 DWARFDebugRnglist::RangeListEntry Entry, 205 uint8_t AddrSize, uint8_t MaxEncodingStringLength, 206 uint64_t &CurrentBase, DIDumpOptions DumpOpts) { 207 auto PrintRawEntry = [](raw_ostream &OS, 208 DWARFDebugRnglist::RangeListEntry Entry, 209 uint8_t AddrSize, DIDumpOptions DumpOpts) { 210 if (DumpOpts.Verbose) { 211 DumpOpts.DisplayRawContents = true; 212 DWARFAddressRange(Entry.Value0, Entry.Value1) 213 .dump(OS, AddrSize, DumpOpts); 214 OS << " => "; 215 } 216 }; 217 218 if (DumpOpts.Verbose) { 219 // Print the section offset in verbose mode. 220 OS << format("0x%8.8" PRIx32 ":", Entry.Offset); 221 auto EncodingString = dwarf::RangeListEncodingString(Entry.EntryKind); 222 // Unsupported encodings should have been reported during parsing. 223 assert(!EncodingString.empty() && "Unknown range entry encoding"); 224 OS << format(" [%s%*c", EncodingString.data(), 225 MaxEncodingStringLength - EncodingString.size() + 1, ']'); 226 if (Entry.EntryKind != dwarf::DW_RLE_end_of_list) 227 OS << ": "; 228 } 229 230 switch (Entry.EntryKind) { 231 case dwarf::DW_RLE_end_of_list: 232 OS << (DumpOpts.Verbose ? "" : "<End of list>"); 233 break; 234 case dwarf::DW_RLE_base_address: 235 // In non-verbose mode we do not print anything for this entry. 236 CurrentBase = Entry.Value0; 237 if (!DumpOpts.Verbose) 238 return; 239 OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Entry.Value0); 240 break; 241 case dwarf::DW_RLE_start_length: 242 PrintRawEntry(OS, Entry, AddrSize, DumpOpts); 243 DWARFAddressRange(Entry.Value0, Entry.Value0 + Entry.Value1) 244 .dump(OS, AddrSize, DumpOpts); 245 break; 246 case dwarf::DW_RLE_offset_pair: 247 PrintRawEntry(OS, Entry, AddrSize, DumpOpts); 248 DWARFAddressRange(Entry.Value0 + CurrentBase, Entry.Value1 + CurrentBase) 249 .dump(OS, AddrSize, DumpOpts); 250 break; 251 case dwarf::DW_RLE_start_end: 252 DWARFAddressRange(Entry.Value0, Entry.Value1).dump(OS, AddrSize, DumpOpts); 253 break; 254 default: 255 llvm_unreachable("Unsupported range list encoding"); 256 } 257 OS << "\n"; 258 } 259 260 void DWARFDebugRnglistTable::dump(raw_ostream &OS, 261 DIDumpOptions DumpOpts) const { 262 if (DumpOpts.Verbose) 263 OS << format("0x%8.8" PRIx32 ": ", HeaderOffset); 264 OS << format("Range List Header: length = 0x%8.8" PRIx32 265 ", version = 0x%4.4" PRIx16 ", " 266 "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 267 ", offset_entry_count = " 268 "0x%8.8" PRIx32 "\n", 269 HeaderData.Length, HeaderData.Version, HeaderData.AddrSize, 270 HeaderData.SegSize, HeaderData.OffsetEntryCount); 271 272 if (HeaderData.OffsetEntryCount > 0) { 273 OS << "Offsets: ["; 274 for (const auto &Off : Offsets) { 275 OS << format("\n0x%8.8" PRIx32, Off); 276 if (DumpOpts.Verbose) 277 OS << format(" => 0x%8.8" PRIx32, 278 Off + HeaderOffset + sizeof(HeaderData)); 279 } 280 OS << "\n]\n"; 281 } 282 OS << "Ranges:\n"; 283 284 // Determine the length of the longest encoding string we have in the table, 285 // so we can align the output properly. We only need this in verbose mode. 286 size_t MaxEncodingStringLength = 0; 287 if (DumpOpts.Verbose) { 288 for (const auto &List : Ranges) 289 for (const auto &Entry : List.second.getEntries()) 290 MaxEncodingStringLength = 291 std::max(MaxEncodingStringLength, 292 dwarf::RangeListEncodingString(Entry.EntryKind).size()); 293 } 294 295 uint64_t CurrentBase = 0; 296 for (const auto &List : Ranges) 297 for (const auto &Entry : List.second.getEntries()) 298 dumpRangeEntry(OS, Entry, HeaderData.AddrSize, MaxEncodingStringLength, 299 CurrentBase, DumpOpts); 300 } 301 302 uint32_t DWARFDebugRnglistTable::length() const { 303 if (HeaderData.Length == 0) 304 return 0; 305 // TODO: DWARF64 support. 306 return HeaderData.Length + sizeof(uint32_t); 307 } 308