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