109467b48Spatrick //===- DWARFDebugRnglists.cpp ---------------------------------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick
909467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
1009467b48Spatrick #include "llvm/BinaryFormat/Dwarf.h"
1173471bf0Spatrick #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
1209467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
1309467b48Spatrick #include "llvm/Support/Errc.h"
1409467b48Spatrick #include "llvm/Support/Error.h"
1509467b48Spatrick #include "llvm/Support/Format.h"
1609467b48Spatrick #include "llvm/Support/raw_ostream.h"
1709467b48Spatrick
1809467b48Spatrick using namespace llvm;
1909467b48Spatrick
extract(DWARFDataExtractor Data,uint64_t * OffsetPtr)2073471bf0Spatrick Error RangeListEntry::extract(DWARFDataExtractor Data, uint64_t *OffsetPtr) {
2109467b48Spatrick Offset = *OffsetPtr;
2209467b48Spatrick SectionIndex = -1ULL;
2309467b48Spatrick // The caller should guarantee that we have at least 1 byte available, so
2409467b48Spatrick // we just assert instead of revalidate.
2573471bf0Spatrick assert(*OffsetPtr < Data.size() &&
2609467b48Spatrick "not enough space to extract a rangelist encoding");
2709467b48Spatrick uint8_t Encoding = Data.getU8(OffsetPtr);
2809467b48Spatrick
2973471bf0Spatrick DataExtractor::Cursor C(*OffsetPtr);
3009467b48Spatrick switch (Encoding) {
3109467b48Spatrick case dwarf::DW_RLE_end_of_list:
3209467b48Spatrick Value0 = Value1 = 0;
3309467b48Spatrick break;
3409467b48Spatrick // TODO: Support other encodings.
3509467b48Spatrick case dwarf::DW_RLE_base_addressx: {
3673471bf0Spatrick Value0 = Data.getULEB128(C);
3709467b48Spatrick break;
3809467b48Spatrick }
3909467b48Spatrick case dwarf::DW_RLE_startx_endx:
4073471bf0Spatrick Value0 = Data.getULEB128(C);
4173471bf0Spatrick Value1 = Data.getULEB128(C);
4273471bf0Spatrick break;
4309467b48Spatrick case dwarf::DW_RLE_startx_length: {
4473471bf0Spatrick Value0 = Data.getULEB128(C);
4573471bf0Spatrick Value1 = Data.getULEB128(C);
4609467b48Spatrick break;
4709467b48Spatrick }
4809467b48Spatrick case dwarf::DW_RLE_offset_pair: {
4973471bf0Spatrick Value0 = Data.getULEB128(C);
5073471bf0Spatrick Value1 = Data.getULEB128(C);
5109467b48Spatrick break;
5209467b48Spatrick }
5309467b48Spatrick case dwarf::DW_RLE_base_address: {
5473471bf0Spatrick Value0 = Data.getRelocatedAddress(C, &SectionIndex);
5509467b48Spatrick break;
5609467b48Spatrick }
5709467b48Spatrick case dwarf::DW_RLE_start_end: {
5873471bf0Spatrick Value0 = Data.getRelocatedAddress(C, &SectionIndex);
5973471bf0Spatrick Value1 = Data.getRelocatedAddress(C);
6009467b48Spatrick break;
6109467b48Spatrick }
6209467b48Spatrick case dwarf::DW_RLE_start_length: {
6373471bf0Spatrick Value0 = Data.getRelocatedAddress(C, &SectionIndex);
6473471bf0Spatrick Value1 = Data.getULEB128(C);
6509467b48Spatrick break;
6609467b48Spatrick }
6709467b48Spatrick default:
6873471bf0Spatrick consumeError(C.takeError());
6909467b48Spatrick return createStringError(errc::not_supported,
7009467b48Spatrick "unknown rnglists encoding 0x%" PRIx32
7109467b48Spatrick " at offset 0x%" PRIx64,
7273471bf0Spatrick uint32_t(Encoding), Offset);
7309467b48Spatrick }
7409467b48Spatrick
7573471bf0Spatrick if (!C) {
7673471bf0Spatrick consumeError(C.takeError());
7773471bf0Spatrick return createStringError(
7873471bf0Spatrick errc::invalid_argument,
7973471bf0Spatrick "read past end of table when reading %s encoding at offset 0x%" PRIx64,
8073471bf0Spatrick dwarf::RLEString(Encoding).data(), Offset);
8173471bf0Spatrick }
8273471bf0Spatrick
8373471bf0Spatrick *OffsetPtr = C.tell();
8409467b48Spatrick EntryKind = Encoding;
8509467b48Spatrick return Error::success();
8609467b48Spatrick }
8709467b48Spatrick
getAbsoluteRanges(std::optional<object::SectionedAddress> BaseAddr,DWARFUnit & U) const8809467b48Spatrick DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
89*d415bd75Srobert std::optional<object::SectionedAddress> BaseAddr, DWARFUnit &U) const {
9073471bf0Spatrick return getAbsoluteRanges(
9173471bf0Spatrick BaseAddr, U.getAddressByteSize(),
9273471bf0Spatrick [&](uint32_t Index) { return U.getAddrOffsetSectionItem(Index); });
9309467b48Spatrick }
9409467b48Spatrick
getAbsoluteRanges(std::optional<object::SectionedAddress> BaseAddr,uint8_t AddressByteSize,function_ref<std::optional<object::SectionedAddress> (uint32_t)> LookupPooledAddress) const9509467b48Spatrick DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
96*d415bd75Srobert std::optional<object::SectionedAddress> BaseAddr, uint8_t AddressByteSize,
97*d415bd75Srobert function_ref<std::optional<object::SectionedAddress>(uint32_t)>
9809467b48Spatrick LookupPooledAddress) const {
9909467b48Spatrick DWARFAddressRangesVector Res;
10073471bf0Spatrick uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressByteSize);
10109467b48Spatrick for (const RangeListEntry &RLE : Entries) {
10209467b48Spatrick if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
10309467b48Spatrick break;
10409467b48Spatrick if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) {
10509467b48Spatrick BaseAddr = LookupPooledAddress(RLE.Value0);
10609467b48Spatrick if (!BaseAddr)
10709467b48Spatrick BaseAddr = {RLE.Value0, -1ULL};
10809467b48Spatrick continue;
10909467b48Spatrick }
11009467b48Spatrick if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
11109467b48Spatrick BaseAddr = {RLE.Value0, RLE.SectionIndex};
11209467b48Spatrick continue;
11309467b48Spatrick }
11409467b48Spatrick
11509467b48Spatrick DWARFAddressRange E;
11609467b48Spatrick E.SectionIndex = RLE.SectionIndex;
11709467b48Spatrick if (BaseAddr && E.SectionIndex == -1ULL)
11809467b48Spatrick E.SectionIndex = BaseAddr->SectionIndex;
11909467b48Spatrick
12009467b48Spatrick switch (RLE.EntryKind) {
12109467b48Spatrick case dwarf::DW_RLE_offset_pair:
12209467b48Spatrick E.LowPC = RLE.Value0;
12373471bf0Spatrick if (E.LowPC == Tombstone)
12473471bf0Spatrick continue;
12509467b48Spatrick E.HighPC = RLE.Value1;
12609467b48Spatrick if (BaseAddr) {
12773471bf0Spatrick if (BaseAddr->Address == Tombstone)
12873471bf0Spatrick continue;
12909467b48Spatrick E.LowPC += BaseAddr->Address;
13009467b48Spatrick E.HighPC += BaseAddr->Address;
13109467b48Spatrick }
13209467b48Spatrick break;
13309467b48Spatrick case dwarf::DW_RLE_start_end:
13409467b48Spatrick E.LowPC = RLE.Value0;
13509467b48Spatrick E.HighPC = RLE.Value1;
13609467b48Spatrick break;
13709467b48Spatrick case dwarf::DW_RLE_start_length:
13809467b48Spatrick E.LowPC = RLE.Value0;
13909467b48Spatrick E.HighPC = E.LowPC + RLE.Value1;
14009467b48Spatrick break;
14109467b48Spatrick case dwarf::DW_RLE_startx_length: {
14209467b48Spatrick auto Start = LookupPooledAddress(RLE.Value0);
14309467b48Spatrick if (!Start)
14409467b48Spatrick Start = {0, -1ULL};
14509467b48Spatrick E.SectionIndex = Start->SectionIndex;
14609467b48Spatrick E.LowPC = Start->Address;
14709467b48Spatrick E.HighPC = E.LowPC + RLE.Value1;
14809467b48Spatrick break;
14909467b48Spatrick }
15073471bf0Spatrick case dwarf::DW_RLE_startx_endx: {
15173471bf0Spatrick auto Start = LookupPooledAddress(RLE.Value0);
15273471bf0Spatrick if (!Start)
15373471bf0Spatrick Start = {0, -1ULL};
15473471bf0Spatrick auto End = LookupPooledAddress(RLE.Value1);
15573471bf0Spatrick if (!End)
15673471bf0Spatrick End = {0, -1ULL};
15773471bf0Spatrick // FIXME: Some error handling if Start.SectionIndex != End.SectionIndex
15873471bf0Spatrick E.SectionIndex = Start->SectionIndex;
15973471bf0Spatrick E.LowPC = Start->Address;
16073471bf0Spatrick E.HighPC = End->Address;
16173471bf0Spatrick break;
16273471bf0Spatrick }
16309467b48Spatrick default:
16409467b48Spatrick // Unsupported encodings should have been reported during extraction,
16509467b48Spatrick // so we should not run into any here.
16609467b48Spatrick llvm_unreachable("Unsupported range list encoding");
16709467b48Spatrick }
16873471bf0Spatrick if (E.LowPC == Tombstone)
16973471bf0Spatrick continue;
17009467b48Spatrick Res.push_back(E);
17109467b48Spatrick }
17209467b48Spatrick return Res;
17309467b48Spatrick }
17409467b48Spatrick
dump(raw_ostream & OS,uint8_t AddrSize,uint8_t MaxEncodingStringLength,uint64_t & CurrentBase,DIDumpOptions DumpOpts,llvm::function_ref<std::optional<object::SectionedAddress> (uint32_t)> LookupPooledAddress) const17509467b48Spatrick void RangeListEntry::dump(
17609467b48Spatrick raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength,
17709467b48Spatrick uint64_t &CurrentBase, DIDumpOptions DumpOpts,
178*d415bd75Srobert llvm::function_ref<std::optional<object::SectionedAddress>(uint32_t)>
17909467b48Spatrick LookupPooledAddress) const {
18009467b48Spatrick auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
18109467b48Spatrick uint8_t AddrSize, DIDumpOptions DumpOpts) {
18209467b48Spatrick if (DumpOpts.Verbose) {
18309467b48Spatrick DumpOpts.DisplayRawContents = true;
18409467b48Spatrick DWARFAddressRange(Entry.Value0, Entry.Value1)
18509467b48Spatrick .dump(OS, AddrSize, DumpOpts);
18609467b48Spatrick OS << " => ";
18709467b48Spatrick }
18809467b48Spatrick };
18909467b48Spatrick
19009467b48Spatrick if (DumpOpts.Verbose) {
19109467b48Spatrick // Print the section offset in verbose mode.
19209467b48Spatrick OS << format("0x%8.8" PRIx64 ":", Offset);
19309467b48Spatrick auto EncodingString = dwarf::RangeListEncodingString(EntryKind);
19409467b48Spatrick // Unsupported encodings should have been reported during parsing.
19509467b48Spatrick assert(!EncodingString.empty() && "Unknown range entry encoding");
19609467b48Spatrick OS << format(" [%s%*c", EncodingString.data(),
19709467b48Spatrick MaxEncodingStringLength - EncodingString.size() + 1, ']');
19809467b48Spatrick if (EntryKind != dwarf::DW_RLE_end_of_list)
19909467b48Spatrick OS << ": ";
20009467b48Spatrick }
20109467b48Spatrick
20273471bf0Spatrick uint64_t Tombstone = dwarf::computeTombstoneAddress(AddrSize);
20373471bf0Spatrick
20409467b48Spatrick switch (EntryKind) {
20509467b48Spatrick case dwarf::DW_RLE_end_of_list:
20609467b48Spatrick OS << (DumpOpts.Verbose ? "" : "<End of list>");
20709467b48Spatrick break;
20809467b48Spatrick case dwarf::DW_RLE_base_addressx: {
20909467b48Spatrick if (auto SA = LookupPooledAddress(Value0))
21009467b48Spatrick CurrentBase = SA->Address;
21109467b48Spatrick else
21209467b48Spatrick CurrentBase = Value0;
21309467b48Spatrick if (!DumpOpts.Verbose)
21409467b48Spatrick return;
21573471bf0Spatrick DWARFFormValue::dumpAddress(OS << ' ', AddrSize, Value0);
21609467b48Spatrick break;
21709467b48Spatrick }
21809467b48Spatrick case dwarf::DW_RLE_base_address:
21909467b48Spatrick // In non-verbose mode we do not print anything for this entry.
22009467b48Spatrick CurrentBase = Value0;
22109467b48Spatrick if (!DumpOpts.Verbose)
22209467b48Spatrick return;
22373471bf0Spatrick DWARFFormValue::dumpAddress(OS << ' ', AddrSize, Value0);
22409467b48Spatrick break;
22509467b48Spatrick case dwarf::DW_RLE_start_length:
22609467b48Spatrick PrintRawEntry(OS, *this, AddrSize, DumpOpts);
22709467b48Spatrick DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
22809467b48Spatrick break;
22909467b48Spatrick case dwarf::DW_RLE_offset_pair:
23009467b48Spatrick PrintRawEntry(OS, *this, AddrSize, DumpOpts);
23173471bf0Spatrick if (CurrentBase != Tombstone)
23209467b48Spatrick DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
23309467b48Spatrick .dump(OS, AddrSize, DumpOpts);
23473471bf0Spatrick else
23573471bf0Spatrick OS << "dead code";
23609467b48Spatrick break;
23709467b48Spatrick case dwarf::DW_RLE_start_end:
23809467b48Spatrick DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts);
23909467b48Spatrick break;
24009467b48Spatrick case dwarf::DW_RLE_startx_length: {
24109467b48Spatrick PrintRawEntry(OS, *this, AddrSize, DumpOpts);
24209467b48Spatrick uint64_t Start = 0;
24309467b48Spatrick if (auto SA = LookupPooledAddress(Value0))
24409467b48Spatrick Start = SA->Address;
24509467b48Spatrick DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts);
24609467b48Spatrick break;
24709467b48Spatrick }
24873471bf0Spatrick case dwarf::DW_RLE_startx_endx: {
24973471bf0Spatrick PrintRawEntry(OS, *this, AddrSize, DumpOpts);
25073471bf0Spatrick uint64_t Start = 0;
25173471bf0Spatrick if (auto SA = LookupPooledAddress(Value0))
25273471bf0Spatrick Start = SA->Address;
25373471bf0Spatrick uint64_t End = 0;
25473471bf0Spatrick if (auto SA = LookupPooledAddress(Value1))
25573471bf0Spatrick End = SA->Address;
25673471bf0Spatrick DWARFAddressRange(Start, End).dump(OS, AddrSize, DumpOpts);
25773471bf0Spatrick break;
25873471bf0Spatrick }
25909467b48Spatrick default:
26009467b48Spatrick llvm_unreachable("Unsupported range list encoding");
26109467b48Spatrick }
26209467b48Spatrick OS << "\n";
26309467b48Spatrick }
264