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