xref: /freebsd/contrib/llvm-project/llvm/include/llvm/DebugInfo/DWARF/LowLevel/DWARFDataExtractorSimple.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- DWARFDataExtractorSimple.h -------------------------------*- C++ -*-===//
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 #ifndef LLVM_DEBUGINFO_DWARF_LOWLEVEL_DWARFDATAEXTRACTORSIMPLE_H
10 #define LLVM_DEBUGINFO_DWARF_LOWLEVEL_DWARFDATAEXTRACTORSIMPLE_H
11 
12 #include "llvm/BinaryFormat/Dwarf.h"
13 #include "llvm/Support/Compiler.h"
14 #include "llvm/Support/DataExtractor.h"
15 #include "llvm/Support/Errc.h"
16 #include "llvm/Support/MathExtras.h"
17 
18 namespace llvm {
19 
20 /// A DataExtractor suitable use for parsing dwarf from memory.  Clients use
21 /// Relocator::getRelocatedValueImpl to relocate values as appropriate.
22 
23 template <typename Relocator>
24 class DWARFDataExtractorBase : public DataExtractor {
25 
26 public:
DWARFDataExtractorBase(StringRef Data,bool IsLittleEndian,uint8_t AddressSize)27   DWARFDataExtractorBase(StringRef Data, bool IsLittleEndian,
28                          uint8_t AddressSize)
29       : DataExtractor(Data, IsLittleEndian, AddressSize) {}
DWARFDataExtractorBase(ArrayRef<uint8_t> Data,bool IsLittleEndian,uint8_t AddressSize)30   DWARFDataExtractorBase(ArrayRef<uint8_t> Data, bool IsLittleEndian,
31                          uint8_t AddressSize)
32       : DataExtractor(
33             StringRef(reinterpret_cast<const char *>(Data.data()), Data.size()),
34             IsLittleEndian, AddressSize) {}
35 
36   /// Truncating constructor
DWARFDataExtractorBase(const DWARFDataExtractorBase & Other,size_t Length)37   DWARFDataExtractorBase(const DWARFDataExtractorBase &Other, size_t Length)
38       : DataExtractor(Other.getData().substr(0, Length), Other.isLittleEndian(),
39                       Other.getAddressSize()) {}
40 
41   /// Extracts a value and returns it as adjusted by the Relocator
42   uint64_t getRelocatedValue(uint32_t Size, uint64_t *Off,
43                              uint64_t *SectionIndex = nullptr,
44                              Error *Err = nullptr) const {
45     return static_cast<const Relocator *>(this)->getRelocatedValueImpl(
46         Size, Off, SectionIndex, Err);
47   }
48 
49   uint64_t getRelocatedValue(Cursor &C, uint32_t Size,
50                              uint64_t *SectionIndex = nullptr) const {
51     return getRelocatedValue(Size, &getOffset(C), SectionIndex, &getError(C));
52   }
53 
54   /// Extracts an address-sized value.
55   uint64_t getRelocatedAddress(uint64_t *Off, uint64_t *SecIx = nullptr) const {
56     return getRelocatedValue(getAddressSize(), Off, SecIx);
57   }
58 
59   uint64_t getRelocatedAddress(Cursor &C, uint64_t *SecIx = nullptr) const {
60     return getRelocatedValue(getAddressSize(), &getOffset(C), SecIx,
61                              &getError(C));
62   }
63 
64   /// Extracts the DWARF "initial length" field, which can either be a 32-bit
65   /// value smaller than 0xfffffff0, or the value 0xffffffff followed by a
66   /// 64-bit length. Returns the actual length, and the DWARF format which is
67   /// encoded in the field. In case of errors, it returns {0, DWARF32} and
68   /// leaves the offset unchanged.
69   std::pair<uint64_t, dwarf::DwarfFormat>
70   getInitialLength(uint64_t *Off, Error *Err = nullptr) const {
71     ErrorAsOutParameter ErrAsOut(Err);
72     if (Err && *Err)
73       return {0, dwarf::DWARF32};
74 
75     Cursor C(*Off);
76     uint64_t Length = getRelocatedValue(C, 4);
77     dwarf::DwarfFormat Format = dwarf::DWARF32;
78     if (Length == dwarf::DW_LENGTH_DWARF64) {
79       Length = getRelocatedValue(C, 8);
80       Format = dwarf::DWARF64;
81     } else if (Length >= dwarf::DW_LENGTH_lo_reserved) {
82       cantFail(C.takeError());
83       if (Err)
84         *Err = createStringError(
85             std::errc::invalid_argument,
86             "unsupported reserved unit length of value 0x%8.8" PRIx64, Length);
87       return {0, dwarf::DWARF32};
88     }
89 
90     if (C) {
91       *Off = C.tell();
92       return {Length, Format};
93     }
94     if (Err)
95       *Err = C.takeError();
96     else
97       consumeError(C.takeError());
98     return {0, dwarf::DWARF32};
99   }
100 
getInitialLength(Cursor & C)101   std::pair<uint64_t, dwarf::DwarfFormat> getInitialLength(Cursor &C) const {
102     return getInitialLength(&getOffset(C), &getError(C));
103   }
104 
105   /// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding.
106   /// There is a DWARF encoding that uses a PC-relative adjustment.
107   /// For these values, \p AbsPosOffset is used to fix them, which should
108   /// reflect the absolute address of this pointer.
getEncodedPointer(uint64_t * Offset,uint8_t Encoding,uint64_t PCRelOffset)109   std::optional<uint64_t> getEncodedPointer(uint64_t *Offset, uint8_t Encoding,
110                                             uint64_t PCRelOffset) const {
111     if (Encoding == dwarf::DW_EH_PE_omit)
112       return std::nullopt;
113 
114     uint64_t Result = 0;
115     uint64_t OldOffset = *Offset;
116     // First get value
117     switch (Encoding & 0x0F) {
118     case dwarf::DW_EH_PE_absptr:
119       switch (getAddressSize()) {
120       case 2:
121       case 4:
122       case 8:
123         Result = getUnsigned(Offset, getAddressSize());
124         break;
125       default:
126         return std::nullopt;
127       }
128       break;
129     case dwarf::DW_EH_PE_uleb128:
130       Result = getULEB128(Offset);
131       break;
132     case dwarf::DW_EH_PE_sleb128:
133       Result = getSLEB128(Offset);
134       break;
135     case dwarf::DW_EH_PE_udata2:
136       Result = getUnsigned(Offset, 2);
137       break;
138     case dwarf::DW_EH_PE_udata4:
139       Result = getUnsigned(Offset, 4);
140       break;
141     case dwarf::DW_EH_PE_udata8:
142       Result = getUnsigned(Offset, 8);
143       break;
144     case dwarf::DW_EH_PE_sdata2:
145       Result = getSigned(Offset, 2);
146       break;
147     case dwarf::DW_EH_PE_sdata4:
148       Result = SignExtend64<32>(getRelocatedValue(4, Offset));
149       break;
150     case dwarf::DW_EH_PE_sdata8:
151       Result = getRelocatedValue(8, Offset);
152       break;
153     default:
154       return std::nullopt;
155     }
156     // Then add relative offset, if required
157     switch (Encoding & 0x70) {
158     case dwarf::DW_EH_PE_absptr:
159       // do nothing
160       break;
161     case dwarf::DW_EH_PE_pcrel:
162       Result += PCRelOffset;
163       break;
164     case dwarf::DW_EH_PE_datarel:
165     case dwarf::DW_EH_PE_textrel:
166     case dwarf::DW_EH_PE_funcrel:
167     case dwarf::DW_EH_PE_aligned:
168     default:
169       *Offset = OldOffset;
170       return std::nullopt;
171     }
172 
173     return Result;
174   }
175 };
176 
177 // Non relocating, low-level dwarf-data extractor. Suitable for use from
178 // libraries that cannot have build-time dependencies on relocation providers.
179 
180 class DWARFDataExtractorSimple
181     : public DWARFDataExtractorBase<DWARFDataExtractorSimple> {
182   using DWARFDataExtractorBase::DWARFDataExtractorBase;
183 
184   LLVM_ABI uint64_t getRelocatedValueImpl(uint32_t Size, uint64_t *Off,
185                                           uint64_t *SectionIndex = nullptr,
186                                           Error *Err = nullptr) const {
187     assert(SectionIndex == nullptr &&
188            "DWARFDATAExtractorSimple cannot take section indices.");
189     return getUnsigned(Off, Size, Err);
190   }
191 };
192 
193 } // end namespace llvm
194 #endif // LLVM_DEBUGINFO_DWARF_LOWLEVEL_DWARFDATAEXTRACTORSIMPLE_H
195