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