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