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