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>
71       Description(DwarfVersion Version, Ts... Op)
72           : Version(Version), Op{Op...} {}
73       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:
87     const Description &getDescription() const { return Desc; }
88     uint8_t getCode() const { return Opcode; }
89     std::optional<unsigned> getSubCode() const;
90     uint64_t getNumOperands() const { return Operands.size(); }
91     ArrayRef<uint64_t> getRawOperands() const { return Operands; };
92     uint64_t getRawOperand(unsigned Idx) const { return Operands[Idx]; }
93     ArrayRef<uint64_t> getOperandEndOffsets() const {
94       return OperandEndOffsets;
95     }
96     uint64_t getOperandEndOffset(unsigned Idx) const {
97       return OperandEndOffsets[Idx];
98     }
99     uint64_t getEndOffset() const { return EndOffset; }
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;
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 
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)
148       : Data(Data), AddressSize(AddressSize), Format(Format) {
149     assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2);
150   }
151 
152   iterator begin() const { return iterator(this, 0); }
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 
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