1 //===- DWARFDebugRangesList.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/DWARFDebugRangeList.h" 10 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 11 #include "llvm/Support/Errc.h" 12 #include "llvm/Support/Format.h" 13 #include "llvm/Support/raw_ostream.h" 14 #include <cinttypes> 15 #include <cstdint> 16 17 using namespace llvm; 18 19 bool DWARFDebugRangeList::RangeListEntry::isBaseAddressSelectionEntry( 20 uint8_t AddressSize) const { 21 assert(DWARFContext::isAddressSizeSupported(AddressSize)); 22 return StartAddress == dwarf::computeTombstoneAddress(AddressSize); 23 } 24 25 void DWARFDebugRangeList::clear() { 26 Offset = -1ULL; 27 AddressSize = 0; 28 Entries.clear(); 29 } 30 31 Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data, 32 uint64_t *offset_ptr) { 33 clear(); 34 if (!data.isValidOffset(*offset_ptr)) 35 return createStringError(errc::invalid_argument, 36 "invalid range list offset 0x%" PRIx64, *offset_ptr); 37 38 AddressSize = data.getAddressSize(); 39 if (Error SizeErr = DWARFContext::checkAddressSizeSupported( 40 AddressSize, errc::invalid_argument, 41 "range list at offset 0x%" PRIx64, *offset_ptr)) 42 return SizeErr; 43 Offset = *offset_ptr; 44 while (true) { 45 RangeListEntry Entry; 46 Entry.SectionIndex = -1ULL; 47 48 uint64_t prev_offset = *offset_ptr; 49 Entry.StartAddress = data.getRelocatedAddress(offset_ptr); 50 Entry.EndAddress = 51 data.getRelocatedAddress(offset_ptr, &Entry.SectionIndex); 52 53 // Check that both values were extracted correctly. 54 if (*offset_ptr != prev_offset + 2 * AddressSize) { 55 clear(); 56 return createStringError(errc::invalid_argument, 57 "invalid range list entry at offset 0x%" PRIx64, 58 prev_offset); 59 } 60 if (Entry.isEndOfListEntry()) 61 break; 62 Entries.push_back(Entry); 63 } 64 return Error::success(); 65 } 66 67 void DWARFDebugRangeList::dump(raw_ostream &OS) const { 68 const char *AddrFmt; 69 switch (AddressSize) { 70 case 2: 71 AddrFmt = "%08" PRIx64 " %04" PRIx64 " %04" PRIx64 "\n"; 72 break; 73 case 4: 74 AddrFmt = "%08" PRIx64 " %08" PRIx64 " %08" PRIx64 "\n"; 75 break; 76 case 8: 77 AddrFmt = "%08" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n"; 78 break; 79 default: 80 llvm_unreachable("unsupported address size"); 81 } 82 for (const RangeListEntry &RLE : Entries) 83 OS << format(AddrFmt, Offset, RLE.StartAddress, RLE.EndAddress); 84 OS << format("%08" PRIx64 " <End of list>\n", Offset); 85 } 86 87 DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges( 88 std::optional<object::SectionedAddress> BaseAddr) const { 89 DWARFAddressRangesVector Res; 90 // debug_addr can't use the max integer tombstone because that's used for the 91 // base address specifier entry - so use max-1. 92 uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressSize) - 1; 93 for (const RangeListEntry &RLE : Entries) { 94 if (RLE.isBaseAddressSelectionEntry(AddressSize)) { 95 BaseAddr = {RLE.EndAddress, RLE.SectionIndex}; 96 continue; 97 } 98 99 DWARFAddressRange E; 100 E.LowPC = RLE.StartAddress; 101 if (E.LowPC == Tombstone) 102 continue; 103 E.HighPC = RLE.EndAddress; 104 E.SectionIndex = RLE.SectionIndex; 105 // Base address of a range list entry is determined by the closest preceding 106 // base address selection entry in the same range list. It defaults to the 107 // base address of the compilation unit if there is no such entry. 108 if (BaseAddr) { 109 if (BaseAddr->Address == Tombstone) 110 continue; 111 E.LowPC += BaseAddr->Address; 112 E.HighPC += BaseAddr->Address; 113 if (E.SectionIndex == -1ULL) 114 E.SectionIndex = BaseAddr->SectionIndex; 115 } 116 Res.push_back(E); 117 } 118 return Res; 119 } 120