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