1 //===-- PostfixExpression.cpp -----------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements support for postfix expressions found in several symbol
10 // file formats, and their conversion to DWARF.
12 //===----------------------------------------------------------------------===//
14 #include "lldb/Symbol/PostfixExpression.h"
15 #include "lldb/Core/dwarf.h"
16 #include "lldb/Utility/Stream.h"
17 #include "llvm/ADT/StringExtras.h"
19 using namespace lldb_private;
20 using namespace lldb_private::postfix;
22 static llvm::Optional<BinaryOpNode::OpType>
23 GetBinaryOpType(llvm::StringRef token) {
24 if (token.size() != 1)
28 return BinaryOpNode::Align;
30 return BinaryOpNode::Minus;
32 return BinaryOpNode::Plus;
37 static llvm::Optional<UnaryOpNode::OpType>
38 GetUnaryOpType(llvm::StringRef token) {
40 return UnaryOpNode::Deref;
44 Node *postfix::Parse(llvm::StringRef expr, llvm::BumpPtrAllocator &alloc) {
45 llvm::SmallVector<Node *, 4> stack;
47 llvm::StringRef token;
48 while (std::tie(token, expr) = getToken(expr), !token.empty()) {
49 if (auto op_type = GetBinaryOpType(token)) {
50 // token is binary operator
54 Node *right = stack.pop_back_val();
55 Node *left = stack.pop_back_val();
56 stack.push_back(MakeNode<BinaryOpNode>(alloc, *op_type, *left, *right));
60 if (auto op_type = GetUnaryOpType(token)) {
61 // token is unary operator
65 Node *operand = stack.pop_back_val();
66 stack.push_back(MakeNode<UnaryOpNode>(alloc, *op_type, *operand));
71 if (to_integer(token, value, 10)) {
72 // token is integer literal
73 stack.push_back(MakeNode<IntegerNode>(alloc, value));
77 stack.push_back(MakeNode<SymbolNode>(alloc, token));
80 if (stack.size() != 1)
87 class SymbolResolver : public Visitor<bool> {
89 SymbolResolver(llvm::function_ref<Node *(SymbolNode &symbol)> replacer)
90 : m_replacer(replacer) {}
92 using Visitor<bool>::Dispatch;
95 bool Visit(BinaryOpNode &binary, Node *&) override {
96 return Dispatch(binary.Left()) && Dispatch(binary.Right());
99 bool Visit(InitialValueNode &, Node *&) override { return true; }
100 bool Visit(IntegerNode &, Node *&) override { return true; }
101 bool Visit(RegisterNode &, Node *&) override { return true; }
103 bool Visit(SymbolNode &symbol, Node *&ref) override {
104 if (Node *replacement = m_replacer(symbol)) {
106 if (replacement != &symbol)
107 return Dispatch(ref);
113 bool Visit(UnaryOpNode &unary, Node *&) override {
114 return Dispatch(unary.Operand());
117 llvm::function_ref<Node *(SymbolNode &symbol)> m_replacer;
120 class DWARFCodegen : public Visitor<> {
122 DWARFCodegen(Stream &stream) : m_out_stream(stream) {}
124 using Visitor<>::Dispatch;
127 void Visit(BinaryOpNode &binary, Node *&) override;
129 void Visit(InitialValueNode &val, Node *&) override;
131 void Visit(IntegerNode &integer, Node *&) override {
132 m_out_stream.PutHex8(DW_OP_consts);
133 m_out_stream.PutSLEB128(integer.GetValue());
137 void Visit(RegisterNode ®, Node *&) override;
139 void Visit(SymbolNode &symbol, Node *&) override {
140 llvm_unreachable("Symbols should have been resolved by now!");
143 void Visit(UnaryOpNode &unary, Node *&) override;
145 Stream &m_out_stream;
147 /// The number keeping track of the evaluation stack depth at any given
148 /// moment. Used for implementing InitialValueNodes. We start with
149 /// m_stack_depth = 1, assuming that the initial value is already on the
150 /// stack. This initial value will be the value of all InitialValueNodes. If
151 /// the expression does not contain InitialValueNodes, then m_stack_depth is
152 /// not used, and the generated expression will run correctly even without an
154 size_t m_stack_depth = 1;
158 void DWARFCodegen::Visit(BinaryOpNode &binary, Node *&) {
159 Dispatch(binary.Left());
160 Dispatch(binary.Right());
162 switch (binary.GetOpType()) {
163 case BinaryOpNode::Plus:
164 m_out_stream.PutHex8(DW_OP_plus);
165 // NOTE: can be optimized by using DW_OP_plus_uconst opcpode
166 // if right child node is constant value
168 case BinaryOpNode::Minus:
169 m_out_stream.PutHex8(DW_OP_minus);
171 case BinaryOpNode::Align:
172 // emit align operator a @ b as
174 // NOTE: implicitly assuming that b is power of 2
175 m_out_stream.PutHex8(DW_OP_lit1);
176 m_out_stream.PutHex8(DW_OP_minus);
177 m_out_stream.PutHex8(DW_OP_not);
179 m_out_stream.PutHex8(DW_OP_and);
182 --m_stack_depth; // Two pops, one push.
185 void DWARFCodegen::Visit(InitialValueNode &, Node *&) {
186 // We never go below the initial stack, so we can pick the initial value from
187 // the bottom of the stack at any moment.
188 assert(m_stack_depth >= 1);
189 m_out_stream.PutHex8(DW_OP_pick);
190 m_out_stream.PutHex8(m_stack_depth - 1);
194 void DWARFCodegen::Visit(RegisterNode ®, Node *&) {
195 uint32_t reg_num = reg.GetRegNum();
196 assert(reg_num != LLDB_INVALID_REGNUM);
199 m_out_stream.PutHex8(DW_OP_bregx);
200 m_out_stream.PutULEB128(reg_num);
202 m_out_stream.PutHex8(DW_OP_breg0 + reg_num);
204 m_out_stream.PutSLEB128(0);
208 void DWARFCodegen::Visit(UnaryOpNode &unary, Node *&) {
209 Dispatch(unary.Operand());
211 switch (unary.GetOpType()) {
212 case UnaryOpNode::Deref:
213 m_out_stream.PutHex8(DW_OP_deref);
216 // Stack depth unchanged.
219 bool postfix::ResolveSymbols(
220 Node *&node, llvm::function_ref<Node *(SymbolNode &)> replacer) {
221 return SymbolResolver(replacer).Dispatch(node);
224 void postfix::ToDWARF(Node &node, Stream &stream) {
226 DWARFCodegen(stream).Dispatch(ptr);