1//===- DWARFDebugRnglists.cpp ---------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
10#include "llvm/BinaryFormat/Dwarf.h"
11#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
12#include "llvm/Support/Errc.h"
13#include "llvm/Support/Error.h"
14#include "llvm/Support/Format.h"
15#include "llvm/Support/raw_ostream.h"
16
17using namespace llvm;
18
19Error RangeListEntry::extract(DWARFDataExtractor Data, uint64_t End,
20                              uint64_t *OffsetPtr) {
21  Offset = *OffsetPtr;
22  SectionIndex = -1ULL;
23  // The caller should guarantee that we have at least 1 byte available, so
24  // we just assert instead of revalidate.
25  assert(*OffsetPtr < End &&
26         "not enough space to extract a rangelist encoding");
27  uint8_t Encoding = Data.getU8(OffsetPtr);
28
29  switch (Encoding) {
30  case dwarf::DW_RLE_end_of_list:
31    Value0 = Value1 = 0;
32    break;
33  // TODO: Support other encodings.
34  case dwarf::DW_RLE_base_addressx: {
35    uint64_t PreviousOffset = *OffsetPtr - 1;
36    Value0 = Data.getULEB128(OffsetPtr);
37    if (End < *OffsetPtr)
38      return createStringError(
39          errc::invalid_argument,
40          "read past end of table when reading "
41          "DW_RLE_base_addressx encoding at offset 0x%" PRIx64,
42          PreviousOffset);
43    break;
44  }
45  case dwarf::DW_RLE_startx_endx:
46    return createStringError(errc::not_supported,
47                       "unsupported rnglists encoding DW_RLE_startx_endx at "
48                       "offset 0x%" PRIx64,
49                       *OffsetPtr - 1);
50  case dwarf::DW_RLE_startx_length: {
51    uint64_t PreviousOffset = *OffsetPtr - 1;
52    Value0 = Data.getULEB128(OffsetPtr);
53    Value1 = Data.getULEB128(OffsetPtr);
54    if (End < *OffsetPtr)
55      return createStringError(
56          errc::invalid_argument,
57          "read past end of table when reading "
58          "DW_RLE_startx_length encoding at offset 0x%" PRIx64,
59          PreviousOffset);
60    break;
61  }
62  case dwarf::DW_RLE_offset_pair: {
63    uint64_t PreviousOffset = *OffsetPtr - 1;
64    Value0 = Data.getULEB128(OffsetPtr);
65    Value1 = Data.getULEB128(OffsetPtr);
66    if (End < *OffsetPtr)
67      return createStringError(errc::invalid_argument,
68                         "read past end of table when reading "
69                         "DW_RLE_offset_pair encoding at offset 0x%" PRIx64,
70                         PreviousOffset);
71    break;
72  }
73  case dwarf::DW_RLE_base_address: {
74    if ((End - *OffsetPtr) < Data.getAddressSize())
75      return createStringError(errc::invalid_argument,
76                         "insufficient space remaining in table for "
77                         "DW_RLE_base_address encoding at offset 0x%" PRIx64,
78                         *OffsetPtr - 1);
79    Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
80    break;
81  }
82  case dwarf::DW_RLE_start_end: {
83    if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2))
84      return createStringError(errc::invalid_argument,
85                         "insufficient space remaining in table for "
86                         "DW_RLE_start_end encoding "
87                         "at offset 0x%" PRIx64,
88                         *OffsetPtr - 1);
89    Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
90    Value1 = Data.getRelocatedAddress(OffsetPtr);
91    break;
92  }
93  case dwarf::DW_RLE_start_length: {
94    uint64_t PreviousOffset = *OffsetPtr - 1;
95    Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
96    Value1 = Data.getULEB128(OffsetPtr);
97    if (End < *OffsetPtr)
98      return createStringError(errc::invalid_argument,
99                         "read past end of table when reading "
100                         "DW_RLE_start_length encoding at offset 0x%" PRIx64,
101                         PreviousOffset);
102    break;
103  }
104  default:
105    return createStringError(errc::not_supported,
106                       "unknown rnglists encoding 0x%" PRIx32
107                       " at offset 0x%" PRIx64,
108                       uint32_t(Encoding), *OffsetPtr - 1);
109  }
110
111  EntryKind = Encoding;
112  return Error::success();
113}
114
115DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
116    llvm::Optional<object::SectionedAddress> BaseAddr, DWARFUnit &U) const {
117  return getAbsoluteRanges(BaseAddr, [&](uint32_t Index) {
118    return U.getAddrOffsetSectionItem(Index);
119  });
120}
121
122DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
123    Optional<object::SectionedAddress> BaseAddr,
124    function_ref<Optional<object::SectionedAddress>(uint32_t)>
125        LookupPooledAddress) const {
126  DWARFAddressRangesVector Res;
127  for (const RangeListEntry &RLE : Entries) {
128    if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
129      break;
130    if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) {
131      BaseAddr = LookupPooledAddress(RLE.Value0);
132      if (!BaseAddr)
133        BaseAddr = {RLE.Value0, -1ULL};
134      continue;
135    }
136    if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
137      BaseAddr = {RLE.Value0, RLE.SectionIndex};
138      continue;
139    }
140
141    DWARFAddressRange E;
142    E.SectionIndex = RLE.SectionIndex;
143    if (BaseAddr && E.SectionIndex == -1ULL)
144      E.SectionIndex = BaseAddr->SectionIndex;
145
146    switch (RLE.EntryKind) {
147    case dwarf::DW_RLE_offset_pair:
148      E.LowPC = RLE.Value0;
149      E.HighPC = RLE.Value1;
150      if (BaseAddr) {
151        E.LowPC += BaseAddr->Address;
152        E.HighPC += BaseAddr->Address;
153      }
154      break;
155    case dwarf::DW_RLE_start_end:
156      E.LowPC = RLE.Value0;
157      E.HighPC = RLE.Value1;
158      break;
159    case dwarf::DW_RLE_start_length:
160      E.LowPC = RLE.Value0;
161      E.HighPC = E.LowPC + RLE.Value1;
162      break;
163    case dwarf::DW_RLE_startx_length: {
164      auto Start = LookupPooledAddress(RLE.Value0);
165      if (!Start)
166        Start = {0, -1ULL};
167      E.SectionIndex = Start->SectionIndex;
168      E.LowPC = Start->Address;
169      E.HighPC = E.LowPC + RLE.Value1;
170      break;
171    }
172    default:
173      // Unsupported encodings should have been reported during extraction,
174      // so we should not run into any here.
175      llvm_unreachable("Unsupported range list encoding");
176    }
177    Res.push_back(E);
178  }
179  return Res;
180}
181
182void RangeListEntry::dump(
183    raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength,
184    uint64_t &CurrentBase, DIDumpOptions DumpOpts,
185    llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
186        LookupPooledAddress) const {
187  auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
188                          uint8_t AddrSize, DIDumpOptions DumpOpts) {
189    if (DumpOpts.Verbose) {
190      DumpOpts.DisplayRawContents = true;
191      DWARFAddressRange(Entry.Value0, Entry.Value1)
192          .dump(OS, AddrSize, DumpOpts);
193      OS << " => ";
194    }
195  };
196
197  if (DumpOpts.Verbose) {
198    // Print the section offset in verbose mode.
199    OS << format("0x%8.8" PRIx64 ":", Offset);
200    auto EncodingString = dwarf::RangeListEncodingString(EntryKind);
201    // Unsupported encodings should have been reported during parsing.
202    assert(!EncodingString.empty() && "Unknown range entry encoding");
203    OS << format(" [%s%*c", EncodingString.data(),
204                 MaxEncodingStringLength - EncodingString.size() + 1, ']');
205    if (EntryKind != dwarf::DW_RLE_end_of_list)
206      OS << ": ";
207  }
208
209  switch (EntryKind) {
210  case dwarf::DW_RLE_end_of_list:
211    OS << (DumpOpts.Verbose ? "" : "<End of list>");
212    break;
213  case dwarf::DW_RLE_base_addressx: {
214    if (auto SA = LookupPooledAddress(Value0))
215      CurrentBase = SA->Address;
216    else
217      CurrentBase = Value0;
218    if (!DumpOpts.Verbose)
219      return;
220    OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
221    break;
222  }
223  case dwarf::DW_RLE_base_address:
224    // In non-verbose mode we do not print anything for this entry.
225    CurrentBase = Value0;
226    if (!DumpOpts.Verbose)
227      return;
228    OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
229    break;
230  case dwarf::DW_RLE_start_length:
231    PrintRawEntry(OS, *this, AddrSize, DumpOpts);
232    DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
233    break;
234  case dwarf::DW_RLE_offset_pair:
235    PrintRawEntry(OS, *this, AddrSize, DumpOpts);
236    DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
237        .dump(OS, AddrSize, DumpOpts);
238    break;
239  case dwarf::DW_RLE_start_end:
240    DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts);
241    break;
242  case dwarf::DW_RLE_startx_length: {
243    PrintRawEntry(OS, *this, AddrSize, DumpOpts);
244    uint64_t Start = 0;
245    if (auto SA = LookupPooledAddress(Value0))
246      Start = SA->Address;
247    DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts);
248    break;
249  }
250  default:
251    llvm_unreachable("Unsupported range list encoding");
252  }
253  OS << "\n";
254}
255