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
clear()190b57cec5SDimitry Andric void DWARFDebugRangeList::clear() {
208bcb0991SDimitry Andric Offset = -1ULL;
210b57cec5SDimitry Andric AddressSize = 0;
220b57cec5SDimitry Andric Entries.clear();
230b57cec5SDimitry Andric }
240b57cec5SDimitry Andric
extract(const DWARFDataExtractor & data,uint64_t * offset_ptr)250b57cec5SDimitry Andric Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
268bcb0991SDimitry Andric uint64_t *offset_ptr) {
270b57cec5SDimitry Andric clear();
280b57cec5SDimitry Andric if (!data.isValidOffset(*offset_ptr))
290b57cec5SDimitry Andric return createStringError(errc::invalid_argument,
308bcb0991SDimitry Andric "invalid range list offset 0x%" PRIx64, *offset_ptr);
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric AddressSize = data.getAddressSize();
330b57cec5SDimitry Andric if (AddressSize != 4 && AddressSize != 8)
340b57cec5SDimitry Andric return createStringError(errc::invalid_argument,
350b57cec5SDimitry Andric "invalid address size: %" PRIu8, AddressSize);
360b57cec5SDimitry Andric Offset = *offset_ptr;
370b57cec5SDimitry Andric while (true) {
380b57cec5SDimitry Andric RangeListEntry Entry;
390b57cec5SDimitry Andric Entry.SectionIndex = -1ULL;
400b57cec5SDimitry Andric
418bcb0991SDimitry Andric uint64_t prev_offset = *offset_ptr;
420b57cec5SDimitry Andric Entry.StartAddress = data.getRelocatedAddress(offset_ptr);
430b57cec5SDimitry Andric Entry.EndAddress =
440b57cec5SDimitry Andric data.getRelocatedAddress(offset_ptr, &Entry.SectionIndex);
450b57cec5SDimitry Andric
460b57cec5SDimitry Andric // Check that both values were extracted correctly.
470b57cec5SDimitry Andric if (*offset_ptr != prev_offset + 2 * AddressSize) {
480b57cec5SDimitry Andric clear();
490b57cec5SDimitry Andric return createStringError(errc::invalid_argument,
508bcb0991SDimitry Andric "invalid range list entry at offset 0x%" PRIx64,
510b57cec5SDimitry Andric prev_offset);
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric if (Entry.isEndOfListEntry())
540b57cec5SDimitry Andric break;
550b57cec5SDimitry Andric Entries.push_back(Entry);
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric return Error::success();
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric
dump(raw_ostream & OS) const600b57cec5SDimitry Andric void DWARFDebugRangeList::dump(raw_ostream &OS) const {
610b57cec5SDimitry Andric for (const RangeListEntry &RLE : Entries) {
628bcb0991SDimitry Andric const char *format_str =
638bcb0991SDimitry Andric (AddressSize == 4 ? "%08" PRIx64 " %08" PRIx64 " %08" PRIx64 "\n"
648bcb0991SDimitry Andric : "%08" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n");
650b57cec5SDimitry Andric OS << format(format_str, Offset, RLE.StartAddress, RLE.EndAddress);
660b57cec5SDimitry Andric }
678bcb0991SDimitry Andric OS << format("%08" PRIx64 " <End of list>\n", Offset);
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric
getAbsoluteRanges(llvm::Optional<object::SectionedAddress> BaseAddr) const700b57cec5SDimitry Andric DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges(
710b57cec5SDimitry Andric llvm::Optional<object::SectionedAddress> BaseAddr) const {
720b57cec5SDimitry Andric DWARFAddressRangesVector Res;
73*af732203SDimitry Andric // debug_addr can't use the max integer tombstone because that's used for the
74*af732203SDimitry Andric // base address specifier entry - so use max-1.
75*af732203SDimitry Andric uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressSize) - 1;
760b57cec5SDimitry Andric for (const RangeListEntry &RLE : Entries) {
770b57cec5SDimitry Andric if (RLE.isBaseAddressSelectionEntry(AddressSize)) {
780b57cec5SDimitry Andric BaseAddr = {RLE.EndAddress, RLE.SectionIndex};
790b57cec5SDimitry Andric continue;
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric
820b57cec5SDimitry Andric DWARFAddressRange E;
830b57cec5SDimitry Andric E.LowPC = RLE.StartAddress;
84*af732203SDimitry Andric if (E.LowPC == Tombstone)
85*af732203SDimitry Andric continue;
860b57cec5SDimitry Andric E.HighPC = RLE.EndAddress;
870b57cec5SDimitry Andric E.SectionIndex = RLE.SectionIndex;
880b57cec5SDimitry Andric // Base address of a range list entry is determined by the closest preceding
890b57cec5SDimitry Andric // base address selection entry in the same range list. It defaults to the
900b57cec5SDimitry Andric // base address of the compilation unit if there is no such entry.
910b57cec5SDimitry Andric if (BaseAddr) {
92*af732203SDimitry Andric if (BaseAddr->Address == Tombstone)
93*af732203SDimitry Andric continue;
940b57cec5SDimitry Andric E.LowPC += BaseAddr->Address;
950b57cec5SDimitry Andric E.HighPC += BaseAddr->Address;
960b57cec5SDimitry Andric if (E.SectionIndex == -1ULL)
970b57cec5SDimitry Andric E.SectionIndex = BaseAddr->SectionIndex;
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric Res.push_back(E);
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric return Res;
1020b57cec5SDimitry Andric }
103