10b57cec5SDimitry Andric //===--- DWARFExpression.h - DWARF Expression handling ----------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
9fe6060f1SDimitry Andric #ifndef LLVM_DEBUGINFO_DWARF_DWARFEXPRESSION_H
10fe6060f1SDimitry Andric #define LLVM_DEBUGINFO_DWARF_DWARFEXPRESSION_H
110b57cec5SDimitry Andric 
1281ad6265SDimitry Andric #include "llvm/ADT/StringRef.h"
130b57cec5SDimitry Andric #include "llvm/ADT/iterator.h"
145ffd83dbSDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
150b57cec5SDimitry Andric #include "llvm/Support/DataExtractor.h"
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric namespace llvm {
180b57cec5SDimitry Andric class DWARFUnit;
1981ad6265SDimitry Andric struct DIDumpOptions;
200b57cec5SDimitry Andric class MCRegisterInfo;
210b57cec5SDimitry Andric class raw_ostream;
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric class DWARFExpression {
240b57cec5SDimitry Andric public:
250b57cec5SDimitry Andric   class iterator;
260b57cec5SDimitry Andric 
2706c3fb27SDimitry Andric   /// This class represents an Operation in the Expression.
280b57cec5SDimitry Andric   ///
290b57cec5SDimitry Andric   /// An Operation can be in Error state (check with isError()). This
300b57cec5SDimitry Andric   /// means that it couldn't be decoded successfully and if it is the
310b57cec5SDimitry Andric   /// case, all others fields contain undefined values.
320b57cec5SDimitry Andric   class Operation {
330b57cec5SDimitry Andric   public:
340b57cec5SDimitry Andric     /// Size and signedness of expression operations' operands.
350b57cec5SDimitry Andric     enum Encoding : uint8_t {
360b57cec5SDimitry Andric       Size1 = 0,
370b57cec5SDimitry Andric       Size2 = 1,
380b57cec5SDimitry Andric       Size4 = 2,
390b57cec5SDimitry Andric       Size8 = 3,
400b57cec5SDimitry Andric       SizeLEB = 4,
410b57cec5SDimitry Andric       SizeAddr = 5,
420b57cec5SDimitry Andric       SizeRefAddr = 6,
430b57cec5SDimitry Andric       SizeBlock = 7, ///< Preceding operand contains block size
440b57cec5SDimitry Andric       BaseTypeRef = 8,
4506c3fb27SDimitry Andric       /// The operand is a ULEB128 encoded SubOpcode. This is only valid
4606c3fb27SDimitry Andric       /// for the first operand of an operation.
4706c3fb27SDimitry Andric       SizeSubOpLEB = 9,
485ffd83dbSDimitry Andric       WasmLocationArg = 30,
490b57cec5SDimitry Andric       SignBit = 0x80,
500b57cec5SDimitry Andric       SignedSize1 = SignBit | Size1,
510b57cec5SDimitry Andric       SignedSize2 = SignBit | Size2,
520b57cec5SDimitry Andric       SignedSize4 = SignBit | Size4,
530b57cec5SDimitry Andric       SignedSize8 = SignBit | Size8,
540b57cec5SDimitry Andric       SignedSizeLEB = SignBit | SizeLEB,
550b57cec5SDimitry Andric     };
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric     enum DwarfVersion : uint8_t {
580b57cec5SDimitry Andric       DwarfNA, ///< Serves as a marker for unused entries
590b57cec5SDimitry Andric       Dwarf2 = 2,
600b57cec5SDimitry Andric       Dwarf3,
610b57cec5SDimitry Andric       Dwarf4,
620b57cec5SDimitry Andric       Dwarf5
630b57cec5SDimitry Andric     };
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric     /// Description of the encoding of one expression Op.
660b57cec5SDimitry Andric     struct Description {
670b57cec5SDimitry Andric       DwarfVersion Version; ///< Dwarf version where the Op was introduced.
6806c3fb27SDimitry Andric       SmallVector<Encoding> Op; ///< Encoding for Op operands.
690b57cec5SDimitry Andric 
7006c3fb27SDimitry Andric       template <typename... Ts>
DescriptionDescription7106c3fb27SDimitry Andric       Description(DwarfVersion Version, Ts... Op)
7206c3fb27SDimitry Andric           : Version(Version), Op{Op...} {}
DescriptionDescription7306c3fb27SDimitry Andric       Description() : Description(DwarfNA) {}
7406c3fb27SDimitry Andric       ~Description() = default;
750b57cec5SDimitry Andric     };
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   private:
780b57cec5SDimitry Andric     friend class DWARFExpression::iterator;
790b57cec5SDimitry Andric     uint8_t Opcode; ///< The Op Opcode, DW_OP_<something>.
800b57cec5SDimitry Andric     Description Desc;
81fe6060f1SDimitry Andric     bool Error = false;
828bcb0991SDimitry Andric     uint64_t EndOffset;
8306c3fb27SDimitry Andric     SmallVector<uint64_t> Operands;
8406c3fb27SDimitry Andric     SmallVector<uint64_t> OperandEndOffsets;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   public:
getDescription()87349cc55cSDimitry Andric     const Description &getDescription() const { return Desc; }
getCode()88349cc55cSDimitry Andric     uint8_t getCode() const { return Opcode; }
8906c3fb27SDimitry Andric     std::optional<unsigned> getSubCode() const;
getNumOperands()9006c3fb27SDimitry Andric     uint64_t getNumOperands() const { return Operands.size(); }
getRawOperands()9106c3fb27SDimitry Andric     ArrayRef<uint64_t> getRawOperands() const { return Operands; };
getRawOperand(unsigned Idx)92349cc55cSDimitry Andric     uint64_t getRawOperand(unsigned Idx) const { return Operands[Idx]; }
getOperandEndOffsets()9306c3fb27SDimitry Andric     ArrayRef<uint64_t> getOperandEndOffsets() const {
9406c3fb27SDimitry Andric       return OperandEndOffsets;
9506c3fb27SDimitry Andric     }
getOperandEndOffset(unsigned Idx)96349cc55cSDimitry Andric     uint64_t getOperandEndOffset(unsigned Idx) const {
97349cc55cSDimitry Andric       return OperandEndOffsets[Idx];
98349cc55cSDimitry Andric     }
getEndOffset()99349cc55cSDimitry Andric     uint64_t getEndOffset() const { return EndOffset; }
isError()100349cc55cSDimitry Andric     bool isError() const { return Error; }
101e8d8bef9SDimitry Andric     bool print(raw_ostream &OS, DIDumpOptions DumpOpts,
102bdd1243dSDimitry Andric                const DWARFExpression *Expr, DWARFUnit *U) const;
103349cc55cSDimitry Andric 
104349cc55cSDimitry Andric     /// Verify \p Op. Does not affect the return of \a isError().
105349cc55cSDimitry Andric     static bool verify(const Operation &Op, DWARFUnit *U);
106349cc55cSDimitry Andric 
107349cc55cSDimitry Andric   private:
108349cc55cSDimitry Andric     bool extract(DataExtractor Data, uint8_t AddressSize, uint64_t Offset,
109bdd1243dSDimitry Andric                  std::optional<dwarf::DwarfFormat> Format);
1100b57cec5SDimitry Andric   };
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   /// An iterator to go through the expression operations.
1130b57cec5SDimitry Andric   class iterator
1140b57cec5SDimitry Andric       : public iterator_facade_base<iterator, std::forward_iterator_tag,
115349cc55cSDimitry Andric                                     const Operation> {
1160b57cec5SDimitry Andric     friend class DWARFExpression;
1170b57cec5SDimitry Andric     const DWARFExpression *Expr;
1188bcb0991SDimitry Andric     uint64_t Offset;
1190b57cec5SDimitry Andric     Operation Op;
iterator(const DWARFExpression * Expr,uint64_t Offset)1208bcb0991SDimitry Andric     iterator(const DWARFExpression *Expr, uint64_t Offset)
1210b57cec5SDimitry Andric         : Expr(Expr), Offset(Offset) {
1220b57cec5SDimitry Andric       Op.Error =
1230b57cec5SDimitry Andric           Offset >= Expr->Data.getData().size() ||
1245ffd83dbSDimitry Andric           !Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format);
1250b57cec5SDimitry Andric     }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   public:
128349cc55cSDimitry Andric     iterator &operator++() {
1290b57cec5SDimitry Andric       Offset = Op.isError() ? Expr->Data.getData().size() : Op.EndOffset;
1300b57cec5SDimitry Andric       Op.Error =
1310b57cec5SDimitry Andric           Offset >= Expr->Data.getData().size() ||
1325ffd83dbSDimitry Andric           !Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format);
133349cc55cSDimitry Andric       return *this;
1340b57cec5SDimitry Andric     }
1350b57cec5SDimitry Andric 
136349cc55cSDimitry Andric     const Operation &operator*() const { return Op; }
1370b57cec5SDimitry Andric 
skipBytes(uint64_t Add)138349cc55cSDimitry Andric     iterator skipBytes(uint64_t Add) const {
1395ffd83dbSDimitry Andric       return iterator(Expr, Op.EndOffset + Add);
1405ffd83dbSDimitry Andric     }
1415ffd83dbSDimitry Andric 
1420b57cec5SDimitry Andric     // Comparison operators are provided out of line.
1430b57cec5SDimitry Andric     friend bool operator==(const iterator &, const iterator &);
1440b57cec5SDimitry Andric   };
1450b57cec5SDimitry Andric 
1465ffd83dbSDimitry Andric   DWARFExpression(DataExtractor Data, uint8_t AddressSize,
147bdd1243dSDimitry Andric                   std::optional<dwarf::DwarfFormat> Format = std::nullopt)
Data(Data)1485ffd83dbSDimitry Andric       : Data(Data), AddressSize(AddressSize), Format(Format) {
1490b57cec5SDimitry Andric     assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2);
1500b57cec5SDimitry Andric   }
1510b57cec5SDimitry Andric 
begin()1520b57cec5SDimitry Andric   iterator begin() const { return iterator(this, 0); }
end()1530b57cec5SDimitry Andric   iterator end() const { return iterator(this, Data.getData().size()); }
1540b57cec5SDimitry Andric 
155bdd1243dSDimitry Andric   void print(raw_ostream &OS, DIDumpOptions DumpOpts, DWARFUnit *U,
1560b57cec5SDimitry Andric              bool IsEH = false) const;
1570b57cec5SDimitry Andric 
1585ffd83dbSDimitry Andric   /// Print the expression in a format intended to be compact and useful to a
1595ffd83dbSDimitry Andric   /// user, but not perfectly unambiguous, or capable of representing every
1605ffd83dbSDimitry Andric   /// valid DWARF expression. Returns true if the expression was sucessfully
1615ffd83dbSDimitry Andric   /// printed.
162bdd1243dSDimitry Andric   bool printCompact(raw_ostream &OS,
163bdd1243dSDimitry Andric                     std::function<StringRef(uint64_t RegNum, bool IsEH)>
164bdd1243dSDimitry Andric                         GetNameForDWARFReg = nullptr);
1655ffd83dbSDimitry Andric 
1660b57cec5SDimitry Andric   bool verify(DWARFUnit *U);
1670b57cec5SDimitry Andric 
168fe6060f1SDimitry Andric   bool operator==(const DWARFExpression &RHS) const;
169fe6060f1SDimitry Andric 
getData()170349cc55cSDimitry Andric   StringRef getData() const { return Data.getData(); }
171349cc55cSDimitry Andric 
172bdd1243dSDimitry Andric   static bool prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS,
173bdd1243dSDimitry Andric                                     DIDumpOptions DumpOpts, uint8_t Opcode,
17406c3fb27SDimitry Andric                                     const ArrayRef<uint64_t> Operands);
175bdd1243dSDimitry Andric 
1760b57cec5SDimitry Andric private:
1770b57cec5SDimitry Andric   DataExtractor Data;
1780b57cec5SDimitry Andric   uint8_t AddressSize;
179bdd1243dSDimitry Andric   std::optional<dwarf::DwarfFormat> Format;
1800b57cec5SDimitry Andric };
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric inline bool operator==(const DWARFExpression::iterator &LHS,
1830b57cec5SDimitry Andric                        const DWARFExpression::iterator &RHS) {
1840b57cec5SDimitry Andric   return LHS.Expr == RHS.Expr && LHS.Offset == RHS.Offset;
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric #endif
188