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 #include "llvm/BinaryFormat/Dwarf.h" 12 #include "llvm/DebugInfo/DWARF/DWARFUnit.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 template <typename... Ts> 20 static Error createError(char const *Fmt, const Ts &... Vals) { 21 std::string Buffer; 22 raw_string_ostream Stream(Buffer); 23 Stream << format(Fmt, Vals...); 24 return make_error<StringError>(Stream.str(), inconvertibleErrorCode()); 25 } 26 27 namespace llvm { // workaround for gcc bug 28 template <> 29 Error DWARFListType<RangeListEntry>::createError(const char *Fmt, const char *s, 30 uint32_t Val) { 31 return ::createError(Fmt, s, Val); 32 } 33 } 34 35 Error RangeListEntry::extract(DWARFDataExtractor Data, uint32_t End, 36 uint32_t *OffsetPtr) { 37 Offset = *OffsetPtr; 38 SectionIndex = -1ULL; 39 // The caller should guarantee that we have at least 1 byte available, so 40 // we just assert instead of revalidate. 41 assert(*OffsetPtr < End && 42 "not enough space to extract a rangelist encoding"); 43 uint8_t Encoding = Data.getU8(OffsetPtr); 44 45 switch (Encoding) { 46 case dwarf::DW_RLE_end_of_list: 47 Value0 = Value1 = 0; 48 break; 49 // TODO: Support other encodings. 50 case dwarf::DW_RLE_base_addressx: 51 return createError("unsupported rnglists encoding DW_RLE_base_addressx " 52 "at offset 0x%" PRIx32, 53 *OffsetPtr - 1); 54 case dwarf::DW_RLE_startx_endx: 55 return createError("unsupported rnglists encoding DW_RLE_startx_endx at " 56 "offset 0x%" PRIx32, 57 *OffsetPtr - 1); 58 case dwarf::DW_RLE_startx_length: 59 return createError("unsupported rnglists encoding DW_RLE_startx_length " 60 "at offset 0x%" PRIx32, 61 *OffsetPtr - 1); 62 case dwarf::DW_RLE_offset_pair: { 63 uint32_t PreviousOffset = *OffsetPtr - 1; 64 Value0 = Data.getULEB128(OffsetPtr); 65 Value1 = Data.getULEB128(OffsetPtr); 66 if (End < *OffsetPtr) 67 return createError("read past end of table when reading " 68 "DW_RLE_offset_pair encoding at offset 0x%" PRIx32, 69 PreviousOffset); 70 break; 71 } 72 case dwarf::DW_RLE_base_address: { 73 if ((End - *OffsetPtr) < Data.getAddressSize()) 74 return createError("insufficient space remaining in table for " 75 "DW_RLE_base_address encoding at offset 0x%" PRIx32, 76 *OffsetPtr - 1); 77 Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex); 78 break; 79 } 80 case dwarf::DW_RLE_start_end: { 81 if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2)) 82 return createError("insufficient space remaining in table for " 83 "DW_RLE_start_end encoding " 84 "at offset 0x%" PRIx32, 85 *OffsetPtr - 1); 86 Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex); 87 Value1 = Data.getRelocatedAddress(OffsetPtr); 88 break; 89 } 90 case dwarf::DW_RLE_start_length: { 91 uint32_t PreviousOffset = *OffsetPtr - 1; 92 Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex); 93 Value1 = Data.getULEB128(OffsetPtr); 94 if (End < *OffsetPtr) 95 return createError("read past end of table when reading " 96 "DW_RLE_start_length encoding at offset 0x%" PRIx32, 97 PreviousOffset); 98 break; 99 } 100 default: 101 return createError("unknown rnglists encoding 0x%" PRIx32 102 " at offset 0x%" PRIx32, 103 uint32_t(Encoding), *OffsetPtr - 1); 104 } 105 106 EntryKind = Encoding; 107 return Error::success(); 108 } 109 110 DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges( 111 llvm::Optional<BaseAddress> BaseAddr) const { 112 DWARFAddressRangesVector Res; 113 for (const RangeListEntry &RLE : Entries) { 114 if (RLE.EntryKind == dwarf::DW_RLE_end_of_list) 115 break; 116 if (RLE.EntryKind == dwarf::DW_RLE_base_address) { 117 BaseAddr = {RLE.Value0, RLE.SectionIndex}; 118 continue; 119 } 120 121 DWARFAddressRange E; 122 E.SectionIndex = RLE.SectionIndex; 123 if (BaseAddr && E.SectionIndex == -1ULL) 124 E.SectionIndex = BaseAddr->SectionIndex; 125 126 switch (RLE.EntryKind) { 127 case dwarf::DW_RLE_offset_pair: 128 E.LowPC = RLE.Value0; 129 E.HighPC = RLE.Value1; 130 if (BaseAddr) { 131 E.LowPC += BaseAddr->Address; 132 E.HighPC += BaseAddr->Address; 133 } 134 break; 135 case dwarf::DW_RLE_start_end: 136 E.LowPC = RLE.Value0; 137 E.HighPC = RLE.Value1; 138 break; 139 case dwarf::DW_RLE_start_length: 140 E.LowPC = RLE.Value0; 141 E.HighPC = E.LowPC + RLE.Value1; 142 break; 143 default: 144 // Unsupported encodings should have been reported during extraction, 145 // so we should not run into any here. 146 llvm_unreachable("Unsupported range list encoding"); 147 } 148 Res.push_back(E); 149 } 150 return Res; 151 } 152 153 void RangeListEntry::dump(raw_ostream &OS, uint8_t AddrSize, 154 uint8_t MaxEncodingStringLength, 155 uint64_t &CurrentBase, DIDumpOptions DumpOpts) const { 156 auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry, 157 uint8_t AddrSize, DIDumpOptions DumpOpts) { 158 if (DumpOpts.Verbose) { 159 DumpOpts.DisplayRawContents = true; 160 DWARFAddressRange(Entry.Value0, Entry.Value1) 161 .dump(OS, AddrSize, DumpOpts); 162 OS << " => "; 163 } 164 }; 165 166 if (DumpOpts.Verbose) { 167 // Print the section offset in verbose mode. 168 OS << format("0x%8.8" PRIx32 ":", Offset); 169 auto EncodingString = dwarf::RangeListEncodingString(EntryKind); 170 // Unsupported encodings should have been reported during parsing. 171 assert(!EncodingString.empty() && "Unknown range entry encoding"); 172 OS << format(" [%s%*c", EncodingString.data(), 173 MaxEncodingStringLength - EncodingString.size() + 1, ']'); 174 if (EntryKind != dwarf::DW_RLE_end_of_list) 175 OS << ": "; 176 } 177 178 switch (EntryKind) { 179 case dwarf::DW_RLE_end_of_list: 180 OS << (DumpOpts.Verbose ? "" : "<End of list>"); 181 break; 182 case dwarf::DW_RLE_base_address: 183 // In non-verbose mode we do not print anything for this entry. 184 CurrentBase = Value0; 185 if (!DumpOpts.Verbose) 186 return; 187 OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0); 188 break; 189 case dwarf::DW_RLE_start_length: 190 PrintRawEntry(OS, *this, AddrSize, DumpOpts); 191 DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts); 192 break; 193 case dwarf::DW_RLE_offset_pair: 194 PrintRawEntry(OS, *this, AddrSize, DumpOpts); 195 DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase) 196 .dump(OS, AddrSize, DumpOpts); 197 break; 198 case dwarf::DW_RLE_start_end: 199 DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts); 200 break; 201 default: 202 llvm_unreachable("Unsupported range list encoding"); 203 } 204 OS << "\n"; 205 } 206