xref: /freebsd/contrib/llvm-project/llvm/include/llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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_LOWLEVEL_DWARFEXPRESSION_H
10 #define LLVM_DEBUGINFO_DWARF_LOWLEVEL_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/Compiler.h"
16 #include "llvm/Support/DataExtractor.h"
17 
18 namespace llvm {
19 class DWARFUnit;
20 struct DIDumpOptions;
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.
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       /// The operand is a ULEB128 encoded SubOpcode. This is only valid
47       /// for the first operand of an operation.
48       SizeSubOpLEB = 9,
49       WasmLocationArg = 30,
50       SignBit = 0x80,
51       SignedSize1 = SignBit | Size1,
52       SignedSize2 = SignBit | Size2,
53       SignedSize4 = SignBit | Size4,
54       SignedSize8 = SignBit | Size8,
55       SignedSizeLEB = SignBit | SizeLEB,
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       SmallVector<Encoding> Op; ///< Encoding for Op operands.
70 
71       template <typename... Ts>
DescriptionDescription72       Description(DwarfVersion Version, Ts... Op)
73           : Version(Version), Op{Op...} {}
DescriptionDescription74       Description() : Description(DwarfNA) {}
75       ~Description() = default;
76     };
77 
78   private:
79     friend class DWARFExpression::iterator;
80     friend class DWARFVerifier;
81 
82     uint8_t Opcode; ///< The Op Opcode, DW_OP_<something>.
83     Description Desc;
84     bool Error = false;
85     uint64_t EndOffset;
86     SmallVector<uint64_t> Operands;
87     SmallVector<uint64_t> OperandEndOffsets;
88 
89   public:
getDescription()90     const Description &getDescription() const { return Desc; }
getCode()91     uint8_t getCode() const { return Opcode; }
92     LLVM_ABI std::optional<unsigned> getSubCode() const;
getNumOperands()93     uint64_t getNumOperands() const { return Operands.size(); }
getRawOperands()94     ArrayRef<uint64_t> getRawOperands() const { return Operands; };
getRawOperand(unsigned Idx)95     uint64_t getRawOperand(unsigned Idx) const { return Operands[Idx]; }
getOperandEndOffsets()96     ArrayRef<uint64_t> getOperandEndOffsets() const {
97       return OperandEndOffsets;
98     }
getOperandEndOffset(unsigned Idx)99     uint64_t getOperandEndOffset(unsigned Idx) const {
100       return OperandEndOffsets[Idx];
101     }
getEndOffset()102     uint64_t getEndOffset() const { return EndOffset; }
isError()103     bool isError() const { return Error; }
104 
105   private:
106     LLVM_ABI bool extract(DataExtractor Data, uint8_t AddressSize,
107                           uint64_t Offset,
108                           std::optional<dwarf::DwarfFormat> Format);
109   };
110 
111   /// An iterator to go through the expression operations.
112   class iterator
113       : public iterator_facade_base<iterator, std::forward_iterator_tag,
114                                     const Operation> {
115     friend class DWARFExpression;
116     const DWARFExpression *Expr;
117     uint64_t Offset;
118     Operation Op;
iterator(const DWARFExpression * Expr,uint64_t Offset)119     iterator(const DWARFExpression *Expr, uint64_t Offset)
120         : Expr(Expr), Offset(Offset) {
121       Op.Error =
122           Offset >= Expr->Data.getData().size() ||
123           !Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format);
124     }
125 
126   public:
127     iterator &operator++() {
128       Offset = Op.isError() ? Expr->Data.getData().size() : Op.EndOffset;
129       Op.Error =
130           Offset >= Expr->Data.getData().size() ||
131           !Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format);
132       return *this;
133     }
134 
135     const Operation &operator*() const { return Op; }
136 
skipBytes(uint64_t Add)137     iterator skipBytes(uint64_t Add) const {
138       return iterator(Expr, Op.EndOffset + Add);
139     }
140 
141     // Comparison operators are provided out of line.
142     friend bool operator==(const iterator &, const iterator &);
143   };
144 
145   DWARFExpression(DataExtractor Data, uint8_t AddressSize,
146                   std::optional<dwarf::DwarfFormat> Format = std::nullopt)
Data(Data)147       : Data(Data), AddressSize(AddressSize), Format(Format) {
148     assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2);
149   }
150 
begin()151   iterator begin() const { return iterator(this, 0); }
end()152   iterator end() const { return iterator(this, Data.getData().size()); }
153 
154   LLVM_ABI bool operator==(const DWARFExpression &RHS) const;
155 
getData()156   StringRef getData() const { return Data.getData(); }
157 
158   friend class DWARFVerifier;
159 
160 private:
161   DataExtractor Data;
162   uint8_t AddressSize;
163   std::optional<dwarf::DwarfFormat> Format;
164 };
165 
166 inline bool operator==(const DWARFExpression::iterator &LHS,
167                        const DWARFExpression::iterator &RHS) {
168   return LHS.Expr == RHS.Expr && LHS.Offset == RHS.Offset;
169 }
170 
171 } // end namespace llvm
172 
173 #endif // LLVM_DEBUGINFO_DWARF_LOWLEVEL_DWARFEXPRESSION_H
174