Coverage Report

Created: 2023-09-21 18:56

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Symbol/PostfixExpression.h
Line
Count
Source (jump to first uncovered line)
1
//===-- PostfixExpression.h -------------------------------------*- 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
//  This file implements support for postfix expressions found in several symbol
10
//  file formats, and their conversion to DWARF.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#ifndef LLDB_SYMBOL_POSTFIXEXPRESSION_H
15
#define LLDB_SYMBOL_POSTFIXEXPRESSION_H
16
17
#include "llvm/ADT/StringRef.h"
18
#include "llvm/Support/Allocator.h"
19
#include "llvm/Support/Casting.h"
20
#include <vector>
21
22
namespace lldb_private {
23
24
class Stream;
25
26
namespace postfix {
27
28
/// The base class for all nodes in the parsed postfix tree.
29
class Node {
30
public:
31
  enum Kind {
32
    BinaryOp,
33
    InitialValue,
34
    Integer,
35
    Register,
36
    Symbol,
37
    UnaryOp,
38
  };
39
40
protected:
41
319
  Node(Kind kind) : m_kind(kind) {}
42
43
public:
44
921
  Kind GetKind() const { return m_kind; }
45
46
private:
47
  Kind m_kind;
48
};
49
50
/// A node representing a binary expression.
51
class BinaryOpNode : public Node {
52
public:
53
  enum OpType {
54
    Align, // alignDown(a, b)
55
    Minus, // a - b
56
    Plus,  // a + b
57
  };
58
59
  BinaryOpNode(OpType op_type, Node &left, Node &right)
60
49
      : Node(BinaryOp), m_op_type(op_type), m_left(&left), m_right(&right) {}
61
62
43
  OpType GetOpType() const { return m_op_type; }
63
64
0
  const Node *Left() const { return m_left; }
65
79
  Node *&Left() { return m_left; }
66
67
0
  const Node *Right() const { return m_right; }
68
76
  Node *&Right() { return m_right; }
69
70
79
  static bool classof(const Node *node) { return node->GetKind() == BinaryOp; }
71
72
private:
73
  OpType m_op_type;
74
  Node *m_left;
75
  Node *m_right;
76
};
77
78
/// A node representing the canonical frame address.
79
class InitialValueNode: public Node {
80
public:
81
29
  InitialValueNode() : Node(InitialValue) {}
82
83
84
  static bool classof(const Node *node) {
84
84
    return node->GetKind() == InitialValue;
85
84
  }
86
};
87
88
/// A node representing an integer literal.
89
class IntegerNode : public Node {
90
public:
91
81
  IntegerNode(int64_t value) : Node(Integer), m_value(value) {}
92
93
60
  int64_t GetValue() const { return m_value; }
94
95
102
  static bool classof(const Node *node) { return node->GetKind() == Integer; }
96
97
private:
98
  int64_t m_value;
99
};
100
101
/// A node representing the value of a register with the given register number.
102
/// The register kind (RegisterKind enum) used for the specifying the register
103
/// number is implicit and assumed to be the same for all Register nodes in a
104
/// given tree.
105
class RegisterNode : public Node {
106
public:
107
24
  RegisterNode(uint32_t reg_num) : Node(Register), m_reg_num(reg_num) {}
108
109
24
  uint32_t GetRegNum() const { return m_reg_num; }
110
111
49
  static bool classof(const Node *node) { return node->GetKind() == Register; }
112
113
private:
114
  uint32_t m_reg_num;
115
};
116
117
/// A node representing a symbolic reference to a named entity. This may be a
118
/// register, which hasn't yet been resolved to a RegisterNode.
119
class SymbolNode : public Node {
120
public:
121
103
  SymbolNode(llvm::StringRef name) : Node(Symbol), m_name(name) {}
122
123
103
  llvm::StringRef GetName() const { return m_name; }
124
125
100
  static bool classof(const Node *node) { return node->GetKind() == Symbol; }
126
127
private:
128
  llvm::StringRef m_name;
129
};
130
131
/// A node representing a unary operation.
132
class UnaryOpNode : public Node {
133
public:
134
  enum OpType {
135
    Deref, // *a
136
  };
137
138
  UnaryOpNode(OpType op_type, Node &operand)
139
33
      : Node(UnaryOp), m_op_type(op_type), m_operand(&operand) {}
140
141
30
  OpType GetOpType() const { return m_op_type; }
142
143
0
  const Node *Operand() const { return m_operand; }
144
55
  Node *&Operand() { return m_operand; }
145
146
55
  static bool classof(const Node *node) { return node->GetKind() == UnaryOp; }
147
148
private:
149
  OpType m_op_type;
150
  Node *m_operand;
151
};
152
153
/// A template class implementing a visitor pattern, but with a couple of
154
/// twists:
155
/// - It uses type switch instead of virtual double dispatch. This allows the
156
//    node classes to be vtable-free and trivially destructible.
157
/// - The Visit functions get an extra Node *& parameter, which refers to the
158
///   child pointer of the parent of the node we are currently visiting. This
159
///   allows mutating algorithms, which replace the currently visited node with
160
///   a different one.
161
/// - The class is templatized on the return type of the Visit functions, which
162
///   means it's possible to return values from them.
163
template <typename ResultT = void> class Visitor {
164
protected:
165
157
  virtual ~Visitor() = default;
lldb_private::postfix::Visitor<bool>::~Visitor()
Line
Count
Source
165
87
  virtual ~Visitor() = default;
lldb_private::postfix::Visitor<void>::~Visitor()
Line
Count
Source
165
70
  virtual ~Visitor() = default;
166
167
  virtual ResultT Visit(BinaryOpNode &binary, Node *&ref) = 0;
168
  virtual ResultT Visit(InitialValueNode &val, Node *&ref) = 0;
169
  virtual ResultT Visit(IntegerNode &integer, Node *&) = 0;
170
  virtual ResultT Visit(RegisterNode &reg, Node *&) = 0;
171
  virtual ResultT Visit(SymbolNode &symbol, Node *&ref) = 0;
172
  virtual ResultT Visit(UnaryOpNode &unary, Node *&ref) = 0;
173
174
  /// Invoke the correct Visit function based on the dynamic type of the given
175
  /// node.
176
410
  ResultT Dispatch(Node *&node) {
177
410
    switch (node->GetKind()) {
178
68
    case Node::BinaryOp:
179
68
      return Visit(llvm::cast<BinaryOpNode>(*node), node);
180
84
    case Node::InitialValue:
181
84
      return Visit(llvm::cast<InitialValueNode>(*node), node);
182
78
    case Node::Integer:
183
78
      return Visit(llvm::cast<IntegerNode>(*node), node);
184
49
    case Node::Register:
185
49
      return Visit(llvm::cast<RegisterNode>(*node), node);
186
81
    case Node::Symbol:
187
81
      return Visit(llvm::cast<SymbolNode>(*node), node);
188
50
    case Node::UnaryOp:
189
50
      return Visit(llvm::cast<UnaryOpNode>(*node), node);
190
410
    }
191
0
    llvm_unreachable("Fully covered switch!");
192
0
  }
lldb_private::postfix::Visitor<bool>::Dispatch(lldb_private::postfix::Node*&)
Line
Count
Source
176
251
  ResultT Dispatch(Node *&node) {
177
251
    switch (node->GetKind()) {
178
36
    case Node::BinaryOp:
179
36
      return Visit(llvm::cast<BinaryOpNode>(*node), node);
180
42
    case Node::InitialValue:
181
42
      return Visit(llvm::cast<InitialValueNode>(*node), node);
182
42
    case Node::Integer:
183
42
      return Visit(llvm::cast<IntegerNode>(*node), node);
184
25
    case Node::Register:
185
25
      return Visit(llvm::cast<RegisterNode>(*node), node);
186
81
    case Node::Symbol:
187
81
      return Visit(llvm::cast<SymbolNode>(*node), node);
188
25
    case Node::UnaryOp:
189
25
      return Visit(llvm::cast<UnaryOpNode>(*node), node);
190
251
    }
191
0
    llvm_unreachable("Fully covered switch!");
192
0
  }
lldb_private::postfix::Visitor<void>::Dispatch(lldb_private::postfix::Node*&)
Line
Count
Source
176
159
  ResultT Dispatch(Node *&node) {
177
159
    switch (node->GetKind()) {
178
32
    case Node::BinaryOp:
179
32
      return Visit(llvm::cast<BinaryOpNode>(*node), node);
180
42
    case Node::InitialValue:
181
42
      return Visit(llvm::cast<InitialValueNode>(*node), node);
182
36
    case Node::Integer:
183
36
      return Visit(llvm::cast<IntegerNode>(*node), node);
184
24
    case Node::Register:
185
24
      return Visit(llvm::cast<RegisterNode>(*node), node);
186
0
    case Node::Symbol:
187
0
      return Visit(llvm::cast<SymbolNode>(*node), node);
188
25
    case Node::UnaryOp:
189
25
      return Visit(llvm::cast<UnaryOpNode>(*node), node);
190
159
    }
191
0
    llvm_unreachable("Fully covered switch!");
192
0
  }
193
};
194
195
/// A utility function for "resolving" SymbolNodes. It traverses a tree and
196
/// calls the callback function for all SymbolNodes it encountered. The
197
/// replacement function should return the node it wished to replace the current
198
/// SymbolNode with (this can also be the original node), or nullptr in case of
199
/// an error. The nodes returned by the callback are inspected and replaced
200
/// recursively, *except* for the case when the function returns the exact same
201
/// node as the input one. It returns true if all SymbolNodes were replaced
202
/// successfully.
203
bool ResolveSymbols(Node *&node,
204
                    llvm::function_ref<Node *(SymbolNode &symbol)> replacer);
205
206
template <typename T, typename... Args>
207
319
inline T *MakeNode(llvm::BumpPtrAllocator &alloc, Args &&... args) {
208
319
  static_assert(std::is_trivially_destructible<T>::value,
209
319
                "This object will not be destroyed!");
210
319
  return new (alloc.Allocate<T>()) T(std::forward<Args>(args)...);
211
319
}
lldb_private::postfix::BinaryOpNode* lldb_private::postfix::MakeNode<lldb_private::postfix::BinaryOpNode, lldb_private::postfix::BinaryOpNode::OpType&, lldb_private::postfix::Node&, lldb_private::postfix::Node&>(llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>&, lldb_private::postfix::BinaryOpNode::OpType&, lldb_private::postfix::Node&, lldb_private::postfix::Node&)
Line
Count
Source
207
49
inline T *MakeNode(llvm::BumpPtrAllocator &alloc, Args &&... args) {
208
49
  static_assert(std::is_trivially_destructible<T>::value,
209
49
                "This object will not be destroyed!");
210
49
  return new (alloc.Allocate<T>()) T(std::forward<Args>(args)...);
211
49
}
lldb_private::postfix::UnaryOpNode* lldb_private::postfix::MakeNode<lldb_private::postfix::UnaryOpNode, lldb_private::postfix::UnaryOpNode::OpType&, lldb_private::postfix::Node&>(llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>&, lldb_private::postfix::UnaryOpNode::OpType&, lldb_private::postfix::Node&)
Line
Count
Source
207
33
inline T *MakeNode(llvm::BumpPtrAllocator &alloc, Args &&... args) {
208
33
  static_assert(std::is_trivially_destructible<T>::value,
209
33
                "This object will not be destroyed!");
210
33
  return new (alloc.Allocate<T>()) T(std::forward<Args>(args)...);
211
33
}
lldb_private::postfix::IntegerNode* lldb_private::postfix::MakeNode<lldb_private::postfix::IntegerNode, long long&>(llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>&, long long&)
Line
Count
Source
207
81
inline T *MakeNode(llvm::BumpPtrAllocator &alloc, Args &&... args) {
208
81
  static_assert(std::is_trivially_destructible<T>::value,
209
81
                "This object will not be destroyed!");
210
81
  return new (alloc.Allocate<T>()) T(std::forward<Args>(args)...);
211
81
}
lldb_private::postfix::SymbolNode* lldb_private::postfix::MakeNode<lldb_private::postfix::SymbolNode, llvm::StringRef&>(llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>&, llvm::StringRef&)
Line
Count
Source
207
103
inline T *MakeNode(llvm::BumpPtrAllocator &alloc, Args &&... args) {
208
103
  static_assert(std::is_trivially_destructible<T>::value,
209
103
                "This object will not be destroyed!");
210
103
  return new (alloc.Allocate<T>()) T(std::forward<Args>(args)...);
211
103
}
lldb_private::postfix::RegisterNode* lldb_private::postfix::MakeNode<lldb_private::postfix::RegisterNode, unsigned int&>(llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>&, unsigned int&)
Line
Count
Source
207
6
inline T *MakeNode(llvm::BumpPtrAllocator &alloc, Args &&... args) {
208
6
  static_assert(std::is_trivially_destructible<T>::value,
209
6
                "This object will not be destroyed!");
210
6
  return new (alloc.Allocate<T>()) T(std::forward<Args>(args)...);
211
6
}
lldb_private::postfix::InitialValueNode* lldb_private::postfix::MakeNode<lldb_private::postfix::InitialValueNode>(llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>&)
Line
Count
Source
207
29
inline T *MakeNode(llvm::BumpPtrAllocator &alloc, Args &&... args) {
208
29
  static_assert(std::is_trivially_destructible<T>::value,
209
29
                "This object will not be destroyed!");
210
29
  return new (alloc.Allocate<T>()) T(std::forward<Args>(args)...);
211
29
}
lldb_private::postfix::RegisterNode* lldb_private::postfix::MakeNode<lldb_private::postfix::RegisterNode, unsigned int const&>(llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>&, unsigned int const&)
Line
Count
Source
207
18
inline T *MakeNode(llvm::BumpPtrAllocator &alloc, Args &&... args) {
208
18
  static_assert(std::is_trivially_destructible<T>::value,
209
18
                "This object will not be destroyed!");
210
18
  return new (alloc.Allocate<T>()) T(std::forward<Args>(args)...);
211
18
}
212
213
/// Parse the given postfix expression. The parsed nodes are placed into the
214
/// provided allocator.
215
Node *ParseOneExpression(llvm::StringRef expr, llvm::BumpPtrAllocator &alloc);
216
217
std::vector<std::pair<llvm::StringRef, Node *>>
218
ParseFPOProgram(llvm::StringRef prog, llvm::BumpPtrAllocator &alloc);
219
220
/// Serialize the given expression tree as DWARF. The result is written into the
221
/// given stream. The AST should not contain any SymbolNodes. If the expression
222
/// contains InitialValueNodes, the generated expression will assume that their
223
/// value will be provided as the top value of the initial evaluation stack (as
224
/// is the case with the CFA value in register eh_unwind rules).
225
void ToDWARF(Node &node, Stream &stream);
226
227
} // namespace postfix
228
} // namespace lldb_private
229
230
#endif // LLDB_SYMBOL_POSTFIXEXPRESSION_H