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, uint32_t End, 20 uint32_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 uint32_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%" PRIx32, 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%" PRIx32, 49 *OffsetPtr - 1); 50 case dwarf::DW_RLE_startx_length: { 51 uint32_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%" PRIx32, 59 PreviousOffset); 60 break; 61 } 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 createStringError(errc::invalid_argument, 68 "read past end of table when reading " 69 "DW_RLE_offset_pair encoding at offset 0x%" PRIx32, 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%" PRIx32, 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%" PRIx32, 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 uint32_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%" PRIx32, 101 PreviousOffset); 102 break; 103 } 104 default: 105 return createStringError(errc::not_supported, 106 "unknown rnglists encoding 0x%" PRIx32 107 " at offset 0x%" PRIx32, 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 DWARFAddressRangesVector Res; 118 for (const RangeListEntry &RLE : Entries) { 119 if (RLE.EntryKind == dwarf::DW_RLE_end_of_list) 120 break; 121 if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) { 122 BaseAddr = U.getAddrOffsetSectionItem(RLE.Value0); 123 if (!BaseAddr) 124 BaseAddr = {RLE.Value0, -1ULL}; 125 continue; 126 } 127 if (RLE.EntryKind == dwarf::DW_RLE_base_address) { 128 BaseAddr = {RLE.Value0, RLE.SectionIndex}; 129 continue; 130 } 131 132 DWARFAddressRange E; 133 E.SectionIndex = RLE.SectionIndex; 134 if (BaseAddr && E.SectionIndex == -1ULL) 135 E.SectionIndex = BaseAddr->SectionIndex; 136 137 switch (RLE.EntryKind) { 138 case dwarf::DW_RLE_offset_pair: 139 E.LowPC = RLE.Value0; 140 E.HighPC = RLE.Value1; 141 if (BaseAddr) { 142 E.LowPC += BaseAddr->Address; 143 E.HighPC += BaseAddr->Address; 144 } 145 break; 146 case dwarf::DW_RLE_start_end: 147 E.LowPC = RLE.Value0; 148 E.HighPC = RLE.Value1; 149 break; 150 case dwarf::DW_RLE_start_length: 151 E.LowPC = RLE.Value0; 152 E.HighPC = E.LowPC + RLE.Value1; 153 break; 154 case dwarf::DW_RLE_startx_length: { 155 auto Start = U.getAddrOffsetSectionItem(RLE.Value0); 156 if (!Start) 157 Start = {0, -1ULL}; 158 E.SectionIndex = Start->SectionIndex; 159 E.LowPC = Start->Address; 160 E.HighPC = E.LowPC + RLE.Value1; 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 Res.push_back(E); 169 } 170 return Res; 171 } 172 173 void RangeListEntry::dump( 174 raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength, 175 uint64_t &CurrentBase, DIDumpOptions DumpOpts, 176 llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)> 177 LookupPooledAddress) const { 178 auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry, 179 uint8_t AddrSize, DIDumpOptions DumpOpts) { 180 if (DumpOpts.Verbose) { 181 DumpOpts.DisplayRawContents = true; 182 DWARFAddressRange(Entry.Value0, Entry.Value1) 183 .dump(OS, AddrSize, DumpOpts); 184 OS << " => "; 185 } 186 }; 187 188 if (DumpOpts.Verbose) { 189 // Print the section offset in verbose mode. 190 OS << format("0x%8.8" PRIx32 ":", Offset); 191 auto EncodingString = dwarf::RangeListEncodingString(EntryKind); 192 // Unsupported encodings should have been reported during parsing. 193 assert(!EncodingString.empty() && "Unknown range entry encoding"); 194 OS << format(" [%s%*c", EncodingString.data(), 195 MaxEncodingStringLength - EncodingString.size() + 1, ']'); 196 if (EntryKind != dwarf::DW_RLE_end_of_list) 197 OS << ": "; 198 } 199 200 switch (EntryKind) { 201 case dwarf::DW_RLE_end_of_list: 202 OS << (DumpOpts.Verbose ? "" : "<End of list>"); 203 break; 204 case dwarf::DW_RLE_base_addressx: { 205 if (auto SA = LookupPooledAddress(Value0)) 206 CurrentBase = SA->Address; 207 else 208 CurrentBase = Value0; 209 if (!DumpOpts.Verbose) 210 return; 211 OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0); 212 break; 213 } 214 case dwarf::DW_RLE_base_address: 215 // In non-verbose mode we do not print anything for this entry. 216 CurrentBase = Value0; 217 if (!DumpOpts.Verbose) 218 return; 219 OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0); 220 break; 221 case dwarf::DW_RLE_start_length: 222 PrintRawEntry(OS, *this, AddrSize, DumpOpts); 223 DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts); 224 break; 225 case dwarf::DW_RLE_offset_pair: 226 PrintRawEntry(OS, *this, AddrSize, DumpOpts); 227 DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase) 228 .dump(OS, AddrSize, DumpOpts); 229 break; 230 case dwarf::DW_RLE_start_end: 231 DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts); 232 break; 233 case dwarf::DW_RLE_startx_length: { 234 PrintRawEntry(OS, *this, AddrSize, DumpOpts); 235 uint64_t Start = 0; 236 if (auto SA = LookupPooledAddress(Value0)) 237 Start = SA->Address; 238 DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts); 239 break; 240 } 241 default: 242 llvm_unreachable("Unsupported range list encoding"); 243 } 244 OS << "\n"; 245 } 246