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