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