1 //===-- PostfixExpression.cpp ---------------------------------------------===//
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"
20 using namespace lldb_private
;
21 using namespace lldb_private::postfix
;
22 using namespace lldb_private::dwarf
;
24 static std::optional
<BinaryOpNode::OpType
>
25 GetBinaryOpType(llvm::StringRef token
) {
26 if (token
.size() != 1)
30 return BinaryOpNode::Align
;
32 return BinaryOpNode::Minus
;
34 return BinaryOpNode::Plus
;
39 static std::optional
<UnaryOpNode::OpType
>
40 GetUnaryOpType(llvm::StringRef token
) {
42 return UnaryOpNode::Deref
;
46 Node
*postfix::ParseOneExpression(llvm::StringRef expr
,
47 llvm::BumpPtrAllocator
&alloc
) {
48 llvm::SmallVector
<Node
*, 4> stack
;
50 llvm::StringRef token
;
51 while (std::tie(token
, expr
) = getToken(expr
), !token
.empty()) {
52 if (auto op_type
= GetBinaryOpType(token
)) {
53 // token is binary operator
57 Node
*right
= stack
.pop_back_val();
58 Node
*left
= stack
.pop_back_val();
59 stack
.push_back(MakeNode
<BinaryOpNode
>(alloc
, *op_type
, *left
, *right
));
63 if (auto op_type
= GetUnaryOpType(token
)) {
64 // token is unary operator
68 Node
*operand
= stack
.pop_back_val();
69 stack
.push_back(MakeNode
<UnaryOpNode
>(alloc
, *op_type
, *operand
));
74 if (to_integer(token
, value
, 10)) {
75 // token is integer literal
76 stack
.push_back(MakeNode
<IntegerNode
>(alloc
, value
));
80 stack
.push_back(MakeNode
<SymbolNode
>(alloc
, token
));
83 if (stack
.size() != 1)
89 std::vector
<std::pair
<llvm::StringRef
, Node
*>>
90 postfix::ParseFPOProgram(llvm::StringRef prog
, llvm::BumpPtrAllocator
&alloc
) {
91 llvm::SmallVector
<llvm::StringRef
, 4> exprs
;
92 prog
.split(exprs
, '=');
93 if (exprs
.empty() || !exprs
.back().trim().empty())
97 std::vector
<std::pair
<llvm::StringRef
, Node
*>> result
;
98 for (llvm::StringRef expr
: exprs
) {
100 std::tie(lhs
, expr
) = getToken(expr
);
101 Node
*rhs
= ParseOneExpression(expr
, alloc
);
104 result
.emplace_back(lhs
, rhs
);
110 class SymbolResolver
: public Visitor
<bool> {
112 SymbolResolver(llvm::function_ref
<Node
*(SymbolNode
&symbol
)> replacer
)
113 : m_replacer(replacer
) {}
115 using Visitor
<bool>::Dispatch
;
118 bool Visit(BinaryOpNode
&binary
, Node
*&) override
{
119 return Dispatch(binary
.Left()) && Dispatch(binary
.Right());
122 bool Visit(InitialValueNode
&, Node
*&) override
{ return true; }
123 bool Visit(IntegerNode
&, Node
*&) override
{ return true; }
124 bool Visit(RegisterNode
&, Node
*&) override
{ return true; }
126 bool Visit(SymbolNode
&symbol
, Node
*&ref
) override
{
127 if (Node
*replacement
= m_replacer(symbol
)) {
129 if (replacement
!= &symbol
)
130 return Dispatch(ref
);
136 bool Visit(UnaryOpNode
&unary
, Node
*&) override
{
137 return Dispatch(unary
.Operand());
140 llvm::function_ref
<Node
*(SymbolNode
&symbol
)> m_replacer
;
143 class DWARFCodegen
: public Visitor
<> {
145 DWARFCodegen(Stream
&stream
) : m_out_stream(stream
) {}
147 using Visitor
<>::Dispatch
;
150 void Visit(BinaryOpNode
&binary
, Node
*&) override
;
152 void Visit(InitialValueNode
&val
, Node
*&) override
;
154 void Visit(IntegerNode
&integer
, Node
*&) override
{
155 m_out_stream
.PutHex8(DW_OP_consts
);
156 m_out_stream
.PutSLEB128(integer
.GetValue());
160 void Visit(RegisterNode
®
, Node
*&) override
;
162 void Visit(SymbolNode
&symbol
, Node
*&) override
{
163 llvm_unreachable("Symbols should have been resolved by now!");
166 void Visit(UnaryOpNode
&unary
, Node
*&) override
;
168 Stream
&m_out_stream
;
170 /// The number keeping track of the evaluation stack depth at any given
171 /// moment. Used for implementing InitialValueNodes. We start with
172 /// m_stack_depth = 1, assuming that the initial value is already on the
173 /// stack. This initial value will be the value of all InitialValueNodes. If
174 /// the expression does not contain InitialValueNodes, then m_stack_depth is
175 /// not used, and the generated expression will run correctly even without an
177 size_t m_stack_depth
= 1;
181 void DWARFCodegen::Visit(BinaryOpNode
&binary
, Node
*&) {
182 Dispatch(binary
.Left());
183 Dispatch(binary
.Right());
185 switch (binary
.GetOpType()) {
186 case BinaryOpNode::Plus
:
187 m_out_stream
.PutHex8(DW_OP_plus
);
188 // NOTE: can be optimized by using DW_OP_plus_uconst opcpode
189 // if right child node is constant value
191 case BinaryOpNode::Minus
:
192 m_out_stream
.PutHex8(DW_OP_minus
);
194 case BinaryOpNode::Align
:
195 // emit align operator a @ b as
197 // NOTE: implicitly assuming that b is power of 2
198 m_out_stream
.PutHex8(DW_OP_lit1
);
199 m_out_stream
.PutHex8(DW_OP_minus
);
200 m_out_stream
.PutHex8(DW_OP_not
);
202 m_out_stream
.PutHex8(DW_OP_and
);
205 --m_stack_depth
; // Two pops, one push.
208 void DWARFCodegen::Visit(InitialValueNode
&, Node
*&) {
209 // We never go below the initial stack, so we can pick the initial value from
210 // the bottom of the stack at any moment.
211 assert(m_stack_depth
>= 1);
212 m_out_stream
.PutHex8(DW_OP_pick
);
213 m_out_stream
.PutHex8(m_stack_depth
- 1);
217 void DWARFCodegen::Visit(RegisterNode
®
, Node
*&) {
218 uint32_t reg_num
= reg
.GetRegNum();
219 assert(reg_num
!= LLDB_INVALID_REGNUM
);
222 m_out_stream
.PutHex8(DW_OP_bregx
);
223 m_out_stream
.PutULEB128(reg_num
);
225 m_out_stream
.PutHex8(DW_OP_breg0
+ reg_num
);
227 m_out_stream
.PutSLEB128(0);
231 void DWARFCodegen::Visit(UnaryOpNode
&unary
, Node
*&) {
232 Dispatch(unary
.Operand());
234 switch (unary
.GetOpType()) {
235 case UnaryOpNode::Deref
:
236 m_out_stream
.PutHex8(DW_OP_deref
);
239 // Stack depth unchanged.
242 bool postfix::ResolveSymbols(
243 Node
*&node
, llvm::function_ref
<Node
*(SymbolNode
&)> replacer
) {
244 return SymbolResolver(replacer
).Dispatch(node
);
247 void postfix::ToDWARF(Node
&node
, Stream
&stream
) {
249 DWARFCodegen(stream
).Dispatch(ptr
);