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. Each operation can 28 /// have up to 2 oprerands. 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 WasmLocationArg = 30, 47 SignBit = 0x80, 48 SignedSize1 = SignBit | Size1, 49 SignedSize2 = SignBit | Size2, 50 SignedSize4 = SignBit | Size4, 51 SignedSize8 = SignBit | Size8, 52 SignedSizeLEB = SignBit | SizeLEB, 53 SizeNA = 0xFF ///< Unused operands get this encoding. 54 }; 55 56 enum DwarfVersion : uint8_t { 57 DwarfNA, ///< Serves as a marker for unused entries 58 Dwarf2 = 2, 59 Dwarf3, 60 Dwarf4, 61 Dwarf5 62 }; 63 64 /// Description of the encoding of one expression Op. 65 struct Description { 66 DwarfVersion Version; ///< Dwarf version where the Op was introduced. 67 Encoding Op[2]; ///< Encoding for Op operands, or SizeNA. 68 69 Description(DwarfVersion Version = DwarfNA, Encoding Op1 = SizeNA, 70 Encoding Op2 = SizeNA) VersionDescription71 : Version(Version) { 72 Op[0] = Op1; 73 Op[1] = Op2; 74 } 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 uint64_t Operands[2]; 84 uint64_t OperandEndOffsets[2]; 85 86 public: getDescription()87 const Description &getDescription() const { return Desc; } getCode()88 uint8_t getCode() const { return Opcode; } getRawOperand(unsigned Idx)89 uint64_t getRawOperand(unsigned Idx) const { return Operands[Idx]; } getOperandEndOffset(unsigned Idx)90 uint64_t getOperandEndOffset(unsigned Idx) const { 91 return OperandEndOffsets[Idx]; 92 } getEndOffset()93 uint64_t getEndOffset() const { return EndOffset; } isError()94 bool isError() const { return Error; } 95 bool print(raw_ostream &OS, DIDumpOptions DumpOpts, 96 const DWARFExpression *Expr, DWARFUnit *U) const; 97 98 /// Verify \p Op. Does not affect the return of \a isError(). 99 static bool verify(const Operation &Op, DWARFUnit *U); 100 101 private: 102 bool extract(DataExtractor Data, uint8_t AddressSize, uint64_t Offset, 103 std::optional<dwarf::DwarfFormat> Format); 104 }; 105 106 /// An iterator to go through the expression operations. 107 class iterator 108 : public iterator_facade_base<iterator, std::forward_iterator_tag, 109 const Operation> { 110 friend class DWARFExpression; 111 const DWARFExpression *Expr; 112 uint64_t Offset; 113 Operation Op; iterator(const DWARFExpression * Expr,uint64_t Offset)114 iterator(const DWARFExpression *Expr, uint64_t Offset) 115 : Expr(Expr), Offset(Offset) { 116 Op.Error = 117 Offset >= Expr->Data.getData().size() || 118 !Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format); 119 } 120 121 public: 122 iterator &operator++() { 123 Offset = Op.isError() ? Expr->Data.getData().size() : Op.EndOffset; 124 Op.Error = 125 Offset >= Expr->Data.getData().size() || 126 !Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format); 127 return *this; 128 } 129 130 const Operation &operator*() const { return Op; } 131 skipBytes(uint64_t Add)132 iterator skipBytes(uint64_t Add) const { 133 return iterator(Expr, Op.EndOffset + Add); 134 } 135 136 // Comparison operators are provided out of line. 137 friend bool operator==(const iterator &, const iterator &); 138 }; 139 140 DWARFExpression(DataExtractor Data, uint8_t AddressSize, 141 std::optional<dwarf::DwarfFormat> Format = std::nullopt) Data(Data)142 : Data(Data), AddressSize(AddressSize), Format(Format) { 143 assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2); 144 } 145 begin()146 iterator begin() const { return iterator(this, 0); } end()147 iterator end() const { return iterator(this, Data.getData().size()); } 148 149 void print(raw_ostream &OS, DIDumpOptions DumpOpts, DWARFUnit *U, 150 bool IsEH = false) const; 151 152 /// Print the expression in a format intended to be compact and useful to a 153 /// user, but not perfectly unambiguous, or capable of representing every 154 /// valid DWARF expression. Returns true if the expression was sucessfully 155 /// printed. 156 bool printCompact(raw_ostream &OS, 157 std::function<StringRef(uint64_t RegNum, bool IsEH)> 158 GetNameForDWARFReg = nullptr); 159 160 bool verify(DWARFUnit *U); 161 162 bool operator==(const DWARFExpression &RHS) const; 163 getData()164 StringRef getData() const { return Data.getData(); } 165 166 static bool prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS, 167 DIDumpOptions DumpOpts, uint8_t Opcode, 168 const uint64_t Operands[2]); 169 170 private: 171 DataExtractor Data; 172 uint8_t AddressSize; 173 std::optional<dwarf::DwarfFormat> Format; 174 }; 175 176 inline bool operator==(const DWARFExpression::iterator &LHS, 177 const DWARFExpression::iterator &RHS) { 178 return LHS.Expr == RHS.Expr && LHS.Offset == RHS.Offset; 179 } 180 } 181 #endif 182