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