xref: /freebsd-src/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===- DWARFDebugRangesList.cpp -------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
100b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h"
110b57cec5SDimitry Andric #include "llvm/Support/Errc.h"
120b57cec5SDimitry Andric #include "llvm/Support/Format.h"
130b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
140b57cec5SDimitry Andric #include <cinttypes>
150b57cec5SDimitry Andric #include <cstdint>
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric using namespace llvm;
180b57cec5SDimitry Andric 
isBaseAddressSelectionEntry(uint8_t AddressSize) const19349cc55cSDimitry Andric bool DWARFDebugRangeList::RangeListEntry::isBaseAddressSelectionEntry(
20349cc55cSDimitry Andric     uint8_t AddressSize) const {
21349cc55cSDimitry Andric   assert(DWARFContext::isAddressSizeSupported(AddressSize));
22349cc55cSDimitry Andric   return StartAddress == dwarf::computeTombstoneAddress(AddressSize);
23349cc55cSDimitry Andric }
24349cc55cSDimitry Andric 
clear()250b57cec5SDimitry Andric void DWARFDebugRangeList::clear() {
268bcb0991SDimitry Andric   Offset = -1ULL;
270b57cec5SDimitry Andric   AddressSize = 0;
280b57cec5SDimitry Andric   Entries.clear();
290b57cec5SDimitry Andric }
300b57cec5SDimitry Andric 
extract(const DWARFDataExtractor & data,uint64_t * offset_ptr)310b57cec5SDimitry Andric Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
328bcb0991SDimitry Andric                                    uint64_t *offset_ptr) {
330b57cec5SDimitry Andric   clear();
340b57cec5SDimitry Andric   if (!data.isValidOffset(*offset_ptr))
350b57cec5SDimitry Andric     return createStringError(errc::invalid_argument,
368bcb0991SDimitry Andric                        "invalid range list offset 0x%" PRIx64, *offset_ptr);
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric   AddressSize = data.getAddressSize();
39349cc55cSDimitry Andric   if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
40349cc55cSDimitry Andric           AddressSize, errc::invalid_argument,
41349cc55cSDimitry Andric           "range list at offset 0x%" PRIx64, *offset_ptr))
42349cc55cSDimitry Andric     return SizeErr;
430b57cec5SDimitry Andric   Offset = *offset_ptr;
440b57cec5SDimitry Andric   while (true) {
450b57cec5SDimitry Andric     RangeListEntry Entry;
460b57cec5SDimitry Andric     Entry.SectionIndex = -1ULL;
470b57cec5SDimitry Andric 
488bcb0991SDimitry Andric     uint64_t prev_offset = *offset_ptr;
490b57cec5SDimitry Andric     Entry.StartAddress = data.getRelocatedAddress(offset_ptr);
500b57cec5SDimitry Andric     Entry.EndAddress =
510b57cec5SDimitry Andric         data.getRelocatedAddress(offset_ptr, &Entry.SectionIndex);
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric     // Check that both values were extracted correctly.
540b57cec5SDimitry Andric     if (*offset_ptr != prev_offset + 2 * AddressSize) {
550b57cec5SDimitry Andric       clear();
560b57cec5SDimitry Andric       return createStringError(errc::invalid_argument,
578bcb0991SDimitry Andric                          "invalid range list entry at offset 0x%" PRIx64,
580b57cec5SDimitry Andric                          prev_offset);
590b57cec5SDimitry Andric     }
600b57cec5SDimitry Andric     if (Entry.isEndOfListEntry())
610b57cec5SDimitry Andric       break;
620b57cec5SDimitry Andric     Entries.push_back(Entry);
630b57cec5SDimitry Andric   }
640b57cec5SDimitry Andric   return Error::success();
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
dump(raw_ostream & OS) const670b57cec5SDimitry Andric void DWARFDebugRangeList::dump(raw_ostream &OS) const {
68349cc55cSDimitry Andric   const char *AddrFmt;
69349cc55cSDimitry Andric   switch (AddressSize) {
70349cc55cSDimitry Andric   case 2:
71349cc55cSDimitry Andric     AddrFmt = "%08" PRIx64 " %04" PRIx64 " %04" PRIx64 "\n";
72349cc55cSDimitry Andric     break;
73349cc55cSDimitry Andric   case 4:
74349cc55cSDimitry Andric     AddrFmt = "%08" PRIx64 " %08" PRIx64 " %08" PRIx64 "\n";
75349cc55cSDimitry Andric     break;
76349cc55cSDimitry Andric   case 8:
77349cc55cSDimitry Andric     AddrFmt = "%08" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n";
78349cc55cSDimitry Andric     break;
79349cc55cSDimitry Andric   default:
80349cc55cSDimitry Andric     llvm_unreachable("unsupported address size");
810b57cec5SDimitry Andric   }
82349cc55cSDimitry Andric   for (const RangeListEntry &RLE : Entries)
83349cc55cSDimitry Andric     OS << format(AddrFmt, Offset, RLE.StartAddress, RLE.EndAddress);
848bcb0991SDimitry Andric   OS << format("%08" PRIx64 " <End of list>\n", Offset);
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric 
getAbsoluteRanges(std::optional<object::SectionedAddress> BaseAddr) const870b57cec5SDimitry Andric DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges(
88*bdd1243dSDimitry Andric     std::optional<object::SectionedAddress> BaseAddr) const {
890b57cec5SDimitry Andric   DWARFAddressRangesVector Res;
90e8d8bef9SDimitry Andric   // debug_addr can't use the max integer tombstone because that's used for the
91e8d8bef9SDimitry Andric   // base address specifier entry - so use max-1.
92e8d8bef9SDimitry Andric   uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressSize) - 1;
930b57cec5SDimitry Andric   for (const RangeListEntry &RLE : Entries) {
940b57cec5SDimitry Andric     if (RLE.isBaseAddressSelectionEntry(AddressSize)) {
950b57cec5SDimitry Andric       BaseAddr = {RLE.EndAddress, RLE.SectionIndex};
960b57cec5SDimitry Andric       continue;
970b57cec5SDimitry Andric     }
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric     DWARFAddressRange E;
1000b57cec5SDimitry Andric     E.LowPC = RLE.StartAddress;
101e8d8bef9SDimitry Andric     if (E.LowPC == Tombstone)
102e8d8bef9SDimitry Andric       continue;
1030b57cec5SDimitry Andric     E.HighPC = RLE.EndAddress;
1040b57cec5SDimitry Andric     E.SectionIndex = RLE.SectionIndex;
1050b57cec5SDimitry Andric     // Base address of a range list entry is determined by the closest preceding
1060b57cec5SDimitry Andric     // base address selection entry in the same range list. It defaults to the
1070b57cec5SDimitry Andric     // base address of the compilation unit if there is no such entry.
1080b57cec5SDimitry Andric     if (BaseAddr) {
109e8d8bef9SDimitry Andric       if (BaseAddr->Address == Tombstone)
110e8d8bef9SDimitry Andric         continue;
1110b57cec5SDimitry Andric       E.LowPC += BaseAddr->Address;
1120b57cec5SDimitry Andric       E.HighPC += BaseAddr->Address;
1130b57cec5SDimitry Andric       if (E.SectionIndex == -1ULL)
1140b57cec5SDimitry Andric         E.SectionIndex = BaseAddr->SectionIndex;
1150b57cec5SDimitry Andric     }
1160b57cec5SDimitry Andric     Res.push_back(E);
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric   return Res;
1190b57cec5SDimitry Andric }
120