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/ArrayRef.h" 13 #include "llvm/ADT/Optional.h" 14 #include "llvm/ADT/iterator.h" 15 #include "llvm/ADT/iterator_range.h" 16 #include "llvm/BinaryFormat/Dwarf.h" 17 #include "llvm/DebugInfo/DIContext.h" 18 #include "llvm/Support/DataExtractor.h" 19 20 namespace llvm { 21 class DWARFUnit; 22 class MCRegisterInfo; 23 class raw_ostream; 24 25 class DWARFExpression { 26 public: 27 class iterator; 28 29 /// This class represents an Operation in the Expression. Each operation can 30 /// have up to 2 oprerands. 31 /// 32 /// An Operation can be in Error state (check with isError()). This 33 /// means that it couldn't be decoded successfully and if it is the 34 /// case, all others fields contain undefined values. 35 class Operation { 36 public: 37 /// Size and signedness of expression operations' operands. 38 enum Encoding : uint8_t { 39 Size1 = 0, 40 Size2 = 1, 41 Size4 = 2, 42 Size8 = 3, 43 SizeLEB = 4, 44 SizeAddr = 5, 45 SizeRefAddr = 6, 46 SizeBlock = 7, ///< Preceding operand contains block size 47 BaseTypeRef = 8, 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 SizeNA = 0xFF ///< Unused operands get this encoding. 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 Encoding Op[2]; ///< Encoding for Op operands, or SizeNA. 70 71 Description(DwarfVersion Version = DwarfNA, Encoding Op1 = SizeNA, 72 Encoding Op2 = SizeNA) VersionDescription73 : Version(Version) { 74 Op[0] = Op1; 75 Op[1] = Op2; 76 } 77 }; 78 79 private: 80 friend class DWARFExpression::iterator; 81 uint8_t Opcode; ///< The Op Opcode, DW_OP_<something>. 82 Description Desc; 83 bool Error = false; 84 uint64_t EndOffset; 85 uint64_t Operands[2]; 86 uint64_t OperandEndOffsets[2]; 87 88 public: getDescription()89 Description &getDescription() { return Desc; } getCode()90 uint8_t getCode() { return Opcode; } getRawOperand(unsigned Idx)91 uint64_t getRawOperand(unsigned Idx) { return Operands[Idx]; } getOperandEndOffset(unsigned Idx)92 uint64_t getOperandEndOffset(unsigned Idx) { return OperandEndOffsets[Idx]; } getEndOffset()93 uint64_t getEndOffset() { return EndOffset; } 94 bool extract(DataExtractor Data, uint8_t AddressSize, uint64_t Offset, 95 Optional<dwarf::DwarfFormat> Format); isError()96 bool isError() { return Error; } 97 bool print(raw_ostream &OS, DIDumpOptions DumpOpts, 98 const DWARFExpression *Expr, const MCRegisterInfo *RegInfo, 99 DWARFUnit *U, bool isEH); 100 bool verify(DWARFUnit *U); 101 }; 102 103 /// An iterator to go through the expression operations. 104 class iterator 105 : public iterator_facade_base<iterator, std::forward_iterator_tag, 106 Operation> { 107 friend class DWARFExpression; 108 const DWARFExpression *Expr; 109 uint64_t Offset; 110 Operation Op; iterator(const DWARFExpression * Expr,uint64_t Offset)111 iterator(const DWARFExpression *Expr, uint64_t Offset) 112 : Expr(Expr), Offset(Offset) { 113 Op.Error = 114 Offset >= Expr->Data.getData().size() || 115 !Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format); 116 } 117 118 public: 119 class Operation &operator++() { 120 Offset = Op.isError() ? Expr->Data.getData().size() : Op.EndOffset; 121 Op.Error = 122 Offset >= Expr->Data.getData().size() || 123 !Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format); 124 return Op; 125 } 126 127 class Operation &operator*() { 128 return Op; 129 } 130 skipBytes(uint64_t Add)131 iterator skipBytes(uint64_t Add) { 132 return iterator(Expr, Op.EndOffset + Add); 133 } 134 135 // Comparison operators are provided out of line. 136 friend bool operator==(const iterator &, const iterator &); 137 }; 138 139 DWARFExpression(DataExtractor Data, uint8_t AddressSize, 140 Optional<dwarf::DwarfFormat> Format = None) Data(Data)141 : Data(Data), AddressSize(AddressSize), Format(Format) { 142 assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2); 143 } 144 begin()145 iterator begin() const { return iterator(this, 0); } end()146 iterator end() const { return iterator(this, Data.getData().size()); } 147 148 void print(raw_ostream &OS, DIDumpOptions DumpOpts, 149 const MCRegisterInfo *RegInfo, 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, const MCRegisterInfo &RegInfo); 157 158 bool verify(DWARFUnit *U); 159 160 bool operator==(const DWARFExpression &RHS) const; 161 162 private: 163 DataExtractor Data; 164 uint8_t AddressSize; 165 Optional<dwarf::DwarfFormat> Format; 166 }; 167 168 inline bool operator==(const DWARFExpression::iterator &LHS, 169 const DWARFExpression::iterator &RHS) { 170 return LHS.Expr == RHS.Expr && LHS.Offset == RHS.Offset; 171 } 172 } 173 #endif 174