1 //===--- DWARFExpression.h - DWARF Expression handling ----------*- 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_DWARFEXPRESSION_H 10 #define LLVM_DEBUGINFO_DWARF_LOWLEVEL_DWARFEXPRESSION_H 11 12 #include "llvm/ADT/StringRef.h" 13 #include "llvm/ADT/iterator.h" 14 #include "llvm/BinaryFormat/Dwarf.h" 15 #include "llvm/Support/Compiler.h" 16 #include "llvm/Support/DataExtractor.h" 17 18 namespace llvm { 19 class DWARFUnit; 20 struct DIDumpOptions; 21 class MCRegisterInfo; 22 class raw_ostream; 23 24 class DWARFExpression { 25 public: 26 class iterator; 27 28 /// This class represents an Operation in the Expression. 29 /// 30 /// An Operation can be in Error state (check with isError()). This 31 /// means that it couldn't be decoded successfully and if it is the 32 /// case, all others fields contain undefined values. 33 class Operation { 34 public: 35 /// Size and signedness of expression operations' operands. 36 enum Encoding : uint8_t { 37 Size1 = 0, 38 Size2 = 1, 39 Size4 = 2, 40 Size8 = 3, 41 SizeLEB = 4, 42 SizeAddr = 5, 43 SizeRefAddr = 6, 44 SizeBlock = 7, ///< Preceding operand contains block size 45 BaseTypeRef = 8, 46 /// The operand is a ULEB128 encoded SubOpcode. This is only valid 47 /// for the first operand of an operation. 48 SizeSubOpLEB = 9, 49 WasmLocationArg = 30, 50 SignBit = 0x80, 51 SignedSize1 = SignBit | Size1, 52 SignedSize2 = SignBit | Size2, 53 SignedSize4 = SignBit | Size4, 54 SignedSize8 = SignBit | Size8, 55 SignedSizeLEB = SignBit | SizeLEB, 56 }; 57 58 enum DwarfVersion : uint8_t { 59 DwarfNA, ///< Serves as a marker for unused entries 60 Dwarf2 = 2, 61 Dwarf3, 62 Dwarf4, 63 Dwarf5 64 }; 65 66 /// Description of the encoding of one expression Op. 67 struct Description { 68 DwarfVersion Version; ///< Dwarf version where the Op was introduced. 69 SmallVector<Encoding> Op; ///< Encoding for Op operands. 70 71 template <typename... Ts> DescriptionDescription72 Description(DwarfVersion Version, Ts... Op) 73 : Version(Version), Op{Op...} {} DescriptionDescription74 Description() : Description(DwarfNA) {} 75 ~Description() = default; 76 }; 77 78 private: 79 friend class DWARFExpression::iterator; 80 friend class DWARFVerifier; 81 82 uint8_t Opcode; ///< The Op Opcode, DW_OP_<something>. 83 Description Desc; 84 bool Error = false; 85 uint64_t EndOffset; 86 SmallVector<uint64_t> Operands; 87 SmallVector<uint64_t> OperandEndOffsets; 88 89 public: getDescription()90 const Description &getDescription() const { return Desc; } getCode()91 uint8_t getCode() const { return Opcode; } 92 LLVM_ABI std::optional<unsigned> getSubCode() const; getNumOperands()93 uint64_t getNumOperands() const { return Operands.size(); } getRawOperands()94 ArrayRef<uint64_t> getRawOperands() const { return Operands; }; getRawOperand(unsigned Idx)95 uint64_t getRawOperand(unsigned Idx) const { return Operands[Idx]; } getOperandEndOffsets()96 ArrayRef<uint64_t> getOperandEndOffsets() const { 97 return OperandEndOffsets; 98 } getOperandEndOffset(unsigned Idx)99 uint64_t getOperandEndOffset(unsigned Idx) const { 100 return OperandEndOffsets[Idx]; 101 } getEndOffset()102 uint64_t getEndOffset() const { return EndOffset; } isError()103 bool isError() const { return Error; } 104 105 private: 106 LLVM_ABI bool extract(DataExtractor Data, uint8_t AddressSize, 107 uint64_t Offset, 108 std::optional<dwarf::DwarfFormat> Format); 109 }; 110 111 /// An iterator to go through the expression operations. 112 class iterator 113 : public iterator_facade_base<iterator, std::forward_iterator_tag, 114 const Operation> { 115 friend class DWARFExpression; 116 const DWARFExpression *Expr; 117 uint64_t Offset; 118 Operation Op; iterator(const DWARFExpression * Expr,uint64_t Offset)119 iterator(const DWARFExpression *Expr, uint64_t Offset) 120 : Expr(Expr), Offset(Offset) { 121 Op.Error = 122 Offset >= Expr->Data.getData().size() || 123 !Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format); 124 } 125 126 public: 127 iterator &operator++() { 128 Offset = Op.isError() ? Expr->Data.getData().size() : Op.EndOffset; 129 Op.Error = 130 Offset >= Expr->Data.getData().size() || 131 !Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format); 132 return *this; 133 } 134 135 const Operation &operator*() const { return Op; } 136 skipBytes(uint64_t Add)137 iterator skipBytes(uint64_t Add) const { 138 return iterator(Expr, Op.EndOffset + Add); 139 } 140 141 // Comparison operators are provided out of line. 142 friend bool operator==(const iterator &, const iterator &); 143 }; 144 145 DWARFExpression(DataExtractor Data, uint8_t AddressSize, 146 std::optional<dwarf::DwarfFormat> Format = std::nullopt) Data(Data)147 : Data(Data), AddressSize(AddressSize), Format(Format) { 148 assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2); 149 } 150 begin()151 iterator begin() const { return iterator(this, 0); } end()152 iterator end() const { return iterator(this, Data.getData().size()); } 153 154 LLVM_ABI bool operator==(const DWARFExpression &RHS) const; 155 getData()156 StringRef getData() const { return Data.getData(); } 157 158 friend class DWARFVerifier; 159 160 private: 161 DataExtractor Data; 162 uint8_t AddressSize; 163 std::optional<dwarf::DwarfFormat> Format; 164 }; 165 166 inline bool operator==(const DWARFExpression::iterator &LHS, 167 const DWARFExpression::iterator &RHS) { 168 return LHS.Expr == RHS.Expr && LHS.Offset == RHS.Offset; 169 } 170 171 } // end namespace llvm 172 173 #endif // LLVM_DEBUGINFO_DWARF_LOWLEVEL_DWARFEXPRESSION_H 174