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)
71           : 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:
87     const Description &getDescription() const { return Desc; }
88     uint8_t getCode() const { return Opcode; }
89     uint64_t getRawOperand(unsigned Idx) const { return Operands[Idx]; }
90     uint64_t getOperandEndOffset(unsigned Idx) const {
91       return OperandEndOffsets[Idx];
92     }
93     uint64_t getEndOffset() const { return EndOffset; }
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;
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 
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)
142       : Data(Data), AddressSize(AddressSize), Format(Format) {
143     assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2);
144   }
145 
146   iterator begin() const { return iterator(this, 0); }
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 
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