|
| 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_DWARFDATAEXTRACTORSIMPLE_H |
| 10 | +#define LLVM_DEBUGINFO_DWARF_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: |
| 27 | + DWARFDataExtractorBase(StringRef Data, bool IsLittleEndian, |
| 28 | + uint8_t AddressSize) |
| 29 | + : DataExtractor(Data, IsLittleEndian, 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 |
| 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 | + LLVM_ABI 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 | + LLVM_ABI 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 | + LLVM_ABI uint64_t getRelocatedAddress(uint64_t *Off, |
| 56 | + uint64_t *SecIx = nullptr) const { |
| 57 | + return getRelocatedValue(getAddressSize(), Off, SecIx); |
| 58 | + } |
| 59 | + |
| 60 | + LLVM_ABI uint64_t getRelocatedAddress(Cursor &C, |
| 61 | + uint64_t *SecIx = nullptr) const { |
| 62 | + return getRelocatedValue(getAddressSize(), &getOffset(C), SecIx, |
| 63 | + &getError(C)); |
| 64 | + } |
| 65 | + |
| 66 | + /// Extracts the DWARF "initial length" field, which can either be a 32-bit |
| 67 | + /// value smaller than 0xfffffff0, or the value 0xffffffff followed by a |
| 68 | + /// 64-bit length. Returns the actual length, and the DWARF format which is |
| 69 | + /// encoded in the field. In case of errors, it returns {0, DWARF32} and |
| 70 | + /// leaves the offset unchanged. |
| 71 | + LLVM_ABI std::pair<uint64_t, dwarf::DwarfFormat> |
| 72 | + getInitialLength(uint64_t *Off, Error *Err = nullptr) const { |
| 73 | + ErrorAsOutParameter ErrAsOut(Err); |
| 74 | + if (Err && *Err) |
| 75 | + return {0, dwarf::DWARF32}; |
| 76 | + |
| 77 | + Cursor C(*Off); |
| 78 | + uint64_t Length = getRelocatedValue(C, 4); |
| 79 | + dwarf::DwarfFormat Format = dwarf::DWARF32; |
| 80 | + if (Length == dwarf::DW_LENGTH_DWARF64) { |
| 81 | + Length = getRelocatedValue(C, 8); |
| 82 | + Format = dwarf::DWARF64; |
| 83 | + } else if (Length >= dwarf::DW_LENGTH_lo_reserved) { |
| 84 | + cantFail(C.takeError()); |
| 85 | + if (Err) |
| 86 | + *Err = createStringError( |
| 87 | + std::errc::invalid_argument, |
| 88 | + "unsupported reserved unit length of value 0x%8.8" PRIx64, Length); |
| 89 | + return {0, dwarf::DWARF32}; |
| 90 | + } |
| 91 | + |
| 92 | + if (C) { |
| 93 | + *Off = C.tell(); |
| 94 | + return {Length, Format}; |
| 95 | + } |
| 96 | + if (Err) |
| 97 | + *Err = C.takeError(); |
| 98 | + else |
| 99 | + consumeError(C.takeError()); |
| 100 | + return {0, dwarf::DWARF32}; |
| 101 | + } |
| 102 | + |
| 103 | + LLVM_ABI std::pair<uint64_t, dwarf::DwarfFormat> |
| 104 | + getInitialLength(Cursor &C) const { |
| 105 | + return getInitialLength(&getOffset(C), &getError(C)); |
| 106 | + } |
| 107 | + |
| 108 | + /// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding. |
| 109 | + /// There is a DWARF encoding that uses a PC-relative adjustment. |
| 110 | + /// For these values, \p AbsPosOffset is used to fix them, which should |
| 111 | + /// reflect the absolute address of this pointer. |
| 112 | + LLVM_ABI std::optional<uint64_t> |
| 113 | + getEncodedPointer(uint64_t *Offset, uint8_t Encoding, |
| 114 | + uint64_t PCRelOffset) const { |
| 115 | + if (Encoding == dwarf::DW_EH_PE_omit) |
| 116 | + return std::nullopt; |
| 117 | + |
| 118 | + uint64_t Result = 0; |
| 119 | + uint64_t OldOffset = *Offset; |
| 120 | + // First get value |
| 121 | + switch (Encoding & 0x0F) { |
| 122 | + case dwarf::DW_EH_PE_absptr: |
| 123 | + switch (getAddressSize()) { |
| 124 | + case 2: |
| 125 | + case 4: |
| 126 | + case 8: |
| 127 | + Result = getUnsigned(Offset, getAddressSize()); |
| 128 | + break; |
| 129 | + default: |
| 130 | + return std::nullopt; |
| 131 | + } |
| 132 | + break; |
| 133 | + case dwarf::DW_EH_PE_uleb128: |
| 134 | + Result = getULEB128(Offset); |
| 135 | + break; |
| 136 | + case dwarf::DW_EH_PE_sleb128: |
| 137 | + Result = getSLEB128(Offset); |
| 138 | + break; |
| 139 | + case dwarf::DW_EH_PE_udata2: |
| 140 | + Result = getUnsigned(Offset, 2); |
| 141 | + break; |
| 142 | + case dwarf::DW_EH_PE_udata4: |
| 143 | + Result = getUnsigned(Offset, 4); |
| 144 | + break; |
| 145 | + case dwarf::DW_EH_PE_udata8: |
| 146 | + Result = getUnsigned(Offset, 8); |
| 147 | + break; |
| 148 | + case dwarf::DW_EH_PE_sdata2: |
| 149 | + Result = getSigned(Offset, 2); |
| 150 | + break; |
| 151 | + case dwarf::DW_EH_PE_sdata4: |
| 152 | + Result = SignExtend64<32>(getRelocatedValue(4, Offset)); |
| 153 | + break; |
| 154 | + case dwarf::DW_EH_PE_sdata8: |
| 155 | + Result = getRelocatedValue(8, Offset); |
| 156 | + break; |
| 157 | + default: |
| 158 | + return std::nullopt; |
| 159 | + } |
| 160 | + // Then add relative offset, if required |
| 161 | + switch (Encoding & 0x70) { |
| 162 | + case dwarf::DW_EH_PE_absptr: |
| 163 | + // do nothing |
| 164 | + break; |
| 165 | + case dwarf::DW_EH_PE_pcrel: |
| 166 | + Result += PCRelOffset; |
| 167 | + break; |
| 168 | + case dwarf::DW_EH_PE_datarel: |
| 169 | + case dwarf::DW_EH_PE_textrel: |
| 170 | + case dwarf::DW_EH_PE_funcrel: |
| 171 | + case dwarf::DW_EH_PE_aligned: |
| 172 | + default: |
| 173 | + *Offset = OldOffset; |
| 174 | + return std::nullopt; |
| 175 | + } |
| 176 | + |
| 177 | + return Result; |
| 178 | + } |
| 179 | +}; |
| 180 | + |
| 181 | +// Non relocating, low-level dwarf-data extractor. Suitable for use from |
| 182 | +// libraries that cannot have build-time dependencies on relocation providers. |
| 183 | + |
| 184 | +class DWARFDataExtractorSimple |
| 185 | + : public DWARFDataExtractorBase<DWARFDataExtractorSimple> { |
| 186 | + using DWARFDataExtractorBase::DWARFDataExtractorBase; |
| 187 | + |
| 188 | + LLVM_ABI uint64_t getRelocatedValueImpl(uint32_t Size, uint64_t *Off, |
| 189 | + uint64_t *SectionIndex = nullptr, |
| 190 | + Error *Err = nullptr) const { |
| 191 | + assert(SectionIndex == nullptr && |
| 192 | + "DWARFDATAExtractorSimple cannot take section indices."); |
| 193 | + return getUnsigned(Off, Size, Err); |
| 194 | + } |
| 195 | +}; |
| 196 | + |
| 197 | +} // end namespace llvm |
| 198 | +#endif // LLVM_DEBUGINFO_DWARF_DWARFDATAEXTRACTOR_H |
0 commit comments