1 //===- DWARFDebugRnglists.cpp ---------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" 10 #include "llvm/BinaryFormat/Dwarf.h" 11 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" 12 #include "llvm/DebugInfo/DWARF/DWARFUnit.h" 13 #include "llvm/Support/Errc.h" 14 #include "llvm/Support/Error.h" 15 #include "llvm/Support/Format.h" 16 #include "llvm/Support/raw_ostream.h" 17 18 using namespace llvm; 19 20 Error RangeListEntry::extract(DWARFDataExtractor Data, uint64_t *OffsetPtr) { 21 Offset = *OffsetPtr; 22 SectionIndex = -1ULL; 23 // The caller should guarantee that we have at least 1 byte available, so 24 // we just assert instead of revalidate. 25 assert(*OffsetPtr < Data.size() && 26 "not enough space to extract a rangelist encoding"); 27 uint8_t Encoding = Data.getU8(OffsetPtr); 28 29 DataExtractor::Cursor C(*OffsetPtr); 30 switch (Encoding) { 31 case dwarf::DW_RLE_end_of_list: 32 Value0 = Value1 = 0; 33 break; 34 // TODO: Support other encodings. 35 case dwarf::DW_RLE_base_addressx: { 36 Value0 = Data.getULEB128(C); 37 break; 38 } 39 case dwarf::DW_RLE_startx_endx: 40 Value0 = Data.getULEB128(C); 41 Value1 = Data.getULEB128(C); 42 break; 43 case dwarf::DW_RLE_startx_length: { 44 Value0 = Data.getULEB128(C); 45 Value1 = Data.getULEB128(C); 46 break; 47 } 48 case dwarf::DW_RLE_offset_pair: { 49 Value0 = Data.getULEB128(C); 50 Value1 = Data.getULEB128(C); 51 break; 52 } 53 case dwarf::DW_RLE_base_address: { 54 Value0 = Data.getRelocatedAddress(C, &SectionIndex); 55 break; 56 } 57 case dwarf::DW_RLE_start_end: { 58 Value0 = Data.getRelocatedAddress(C, &SectionIndex); 59 Value1 = Data.getRelocatedAddress(C); 60 break; 61 } 62 case dwarf::DW_RLE_start_length: { 63 Value0 = Data.getRelocatedAddress(C, &SectionIndex); 64 Value1 = Data.getULEB128(C); 65 break; 66 } 67 default: 68 consumeError(C.takeError()); 69 return createStringError(errc::not_supported, 70 "unknown rnglists encoding 0x%" PRIx32 71 " at offset 0x%" PRIx64, 72 uint32_t(Encoding), Offset); 73 } 74 75 if (!C) { 76 consumeError(C.takeError()); 77 return createStringError( 78 errc::invalid_argument, 79 "read past end of table when reading %s encoding at offset 0x%" PRIx64, 80 dwarf::RLEString(Encoding).data(), Offset); 81 } 82 83 *OffsetPtr = C.tell(); 84 EntryKind = Encoding; 85 return Error::success(); 86 } 87 88 DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges( 89 std::optional<object::SectionedAddress> BaseAddr, DWARFUnit &U) const { 90 return getAbsoluteRanges( 91 BaseAddr, U.getAddressByteSize(), 92 [&](uint32_t Index) { return U.getAddrOffsetSectionItem(Index); }); 93 } 94 95 DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges( 96 std::optional<object::SectionedAddress> BaseAddr, uint8_t AddressByteSize, 97 function_ref<std::optional<object::SectionedAddress>(uint32_t)> 98 LookupPooledAddress) const { 99 DWARFAddressRangesVector Res; 100 uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressByteSize); 101 for (const RangeListEntry &RLE : Entries) { 102 if (RLE.EntryKind == dwarf::DW_RLE_end_of_list) 103 break; 104 if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) { 105 BaseAddr = LookupPooledAddress(RLE.Value0); 106 if (!BaseAddr) 107 BaseAddr = {RLE.Value0, -1ULL}; 108 continue; 109 } 110 if (RLE.EntryKind == dwarf::DW_RLE_base_address) { 111 BaseAddr = {RLE.Value0, RLE.SectionIndex}; 112 continue; 113 } 114 115 DWARFAddressRange E; 116 E.SectionIndex = RLE.SectionIndex; 117 if (BaseAddr && E.SectionIndex == -1ULL) 118 E.SectionIndex = BaseAddr->SectionIndex; 119 120 switch (RLE.EntryKind) { 121 case dwarf::DW_RLE_offset_pair: 122 E.LowPC = RLE.Value0; 123 if (E.LowPC == Tombstone) 124 continue; 125 E.HighPC = RLE.Value1; 126 if (BaseAddr) { 127 if (BaseAddr->Address == Tombstone) 128 continue; 129 E.LowPC += BaseAddr->Address; 130 E.HighPC += BaseAddr->Address; 131 } 132 break; 133 case dwarf::DW_RLE_start_end: 134 E.LowPC = RLE.Value0; 135 E.HighPC = RLE.Value1; 136 break; 137 case dwarf::DW_RLE_start_length: 138 E.LowPC = RLE.Value0; 139 E.HighPC = E.LowPC + RLE.Value1; 140 break; 141 case dwarf::DW_RLE_startx_length: { 142 auto Start = LookupPooledAddress(RLE.Value0); 143 if (!Start) 144 Start = {0, -1ULL}; 145 E.SectionIndex = Start->SectionIndex; 146 E.LowPC = Start->Address; 147 E.HighPC = E.LowPC + RLE.Value1; 148 break; 149 } 150 case dwarf::DW_RLE_startx_endx: { 151 auto Start = LookupPooledAddress(RLE.Value0); 152 if (!Start) 153 Start = {0, -1ULL}; 154 auto End = LookupPooledAddress(RLE.Value1); 155 if (!End) 156 End = {0, -1ULL}; 157 // FIXME: Some error handling if Start.SectionIndex != End.SectionIndex 158 E.SectionIndex = Start->SectionIndex; 159 E.LowPC = Start->Address; 160 E.HighPC = End->Address; 161 break; 162 } 163 default: 164 // Unsupported encodings should have been reported during extraction, 165 // so we should not run into any here. 166 llvm_unreachable("Unsupported range list encoding"); 167 } 168 if (E.LowPC == Tombstone) 169 continue; 170 Res.push_back(E); 171 } 172 return Res; 173 } 174 175 void RangeListEntry::dump( 176 raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength, 177 uint64_t &CurrentBase, DIDumpOptions DumpOpts, 178 llvm::function_ref<std::optional<object::SectionedAddress>(uint32_t)> 179 LookupPooledAddress) const { 180 auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry, 181 uint8_t AddrSize, DIDumpOptions DumpOpts) { 182 if (DumpOpts.Verbose) { 183 DumpOpts.DisplayRawContents = true; 184 DWARFAddressRange(Entry.Value0, Entry.Value1) 185 .dump(OS, AddrSize, DumpOpts); 186 OS << " => "; 187 } 188 }; 189 190 if (DumpOpts.Verbose) { 191 // Print the section offset in verbose mode. 192 OS << format("0x%8.8" PRIx64 ":", Offset); 193 auto EncodingString = dwarf::RangeListEncodingString(EntryKind); 194 // Unsupported encodings should have been reported during parsing. 195 assert(!EncodingString.empty() && "Unknown range entry encoding"); 196 OS << format(" [%s%*c", EncodingString.data(), 197 MaxEncodingStringLength - EncodingString.size() + 1, ']'); 198 if (EntryKind != dwarf::DW_RLE_end_of_list) 199 OS << ": "; 200 } 201 202 uint64_t Tombstone = dwarf::computeTombstoneAddress(AddrSize); 203 204 switch (EntryKind) { 205 case dwarf::DW_RLE_end_of_list: 206 OS << (DumpOpts.Verbose ? "" : "<End of list>"); 207 break; 208 case dwarf::DW_RLE_base_addressx: { 209 if (auto SA = LookupPooledAddress(Value0)) 210 CurrentBase = SA->Address; 211 else 212 CurrentBase = Value0; 213 if (!DumpOpts.Verbose) 214 return; 215 DWARFFormValue::dumpAddress(OS << ' ', AddrSize, Value0); 216 break; 217 } 218 case dwarf::DW_RLE_base_address: 219 // In non-verbose mode we do not print anything for this entry. 220 CurrentBase = Value0; 221 if (!DumpOpts.Verbose) 222 return; 223 DWARFFormValue::dumpAddress(OS << ' ', AddrSize, Value0); 224 break; 225 case dwarf::DW_RLE_start_length: 226 PrintRawEntry(OS, *this, AddrSize, DumpOpts); 227 DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts); 228 break; 229 case dwarf::DW_RLE_offset_pair: 230 PrintRawEntry(OS, *this, AddrSize, DumpOpts); 231 if (CurrentBase != Tombstone) 232 DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase) 233 .dump(OS, AddrSize, DumpOpts); 234 else 235 OS << "dead code"; 236 break; 237 case dwarf::DW_RLE_start_end: 238 DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts); 239 break; 240 case dwarf::DW_RLE_startx_length: { 241 PrintRawEntry(OS, *this, AddrSize, DumpOpts); 242 uint64_t Start = 0; 243 if (auto SA = LookupPooledAddress(Value0)) 244 Start = SA->Address; 245 DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts); 246 break; 247 } 248 case dwarf::DW_RLE_startx_endx: { 249 PrintRawEntry(OS, *this, AddrSize, DumpOpts); 250 uint64_t Start = 0; 251 if (auto SA = LookupPooledAddress(Value0)) 252 Start = SA->Address; 253 uint64_t End = 0; 254 if (auto SA = LookupPooledAddress(Value1)) 255 End = SA->Address; 256 DWARFAddressRange(Start, End).dump(OS, AddrSize, DumpOpts); 257 break; 258 } 259 default: 260 llvm_unreachable("Unsupported range list encoding"); 261 } 262 OS << "\n"; 263 } 264