1dda28197Spatrick //===-- PostfixExpression.cpp ---------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick //
9061da546Spatrick // This file implements support for postfix expressions found in several symbol
10061da546Spatrick // file formats, and their conversion to DWARF.
11061da546Spatrick //
12061da546Spatrick //===----------------------------------------------------------------------===//
13061da546Spatrick
14061da546Spatrick #include "lldb/Symbol/PostfixExpression.h"
15061da546Spatrick #include "lldb/Core/dwarf.h"
16061da546Spatrick #include "lldb/Utility/Stream.h"
17061da546Spatrick #include "llvm/ADT/StringExtras.h"
18*f6aab3d8Srobert #include <optional>
19061da546Spatrick
20061da546Spatrick using namespace lldb_private;
21061da546Spatrick using namespace lldb_private::postfix;
22*f6aab3d8Srobert using namespace lldb_private::dwarf;
23061da546Spatrick
24*f6aab3d8Srobert static std::optional<BinaryOpNode::OpType>
GetBinaryOpType(llvm::StringRef token)25061da546Spatrick GetBinaryOpType(llvm::StringRef token) {
26061da546Spatrick if (token.size() != 1)
27*f6aab3d8Srobert return std::nullopt;
28061da546Spatrick switch (token[0]) {
29061da546Spatrick case '@':
30061da546Spatrick return BinaryOpNode::Align;
31061da546Spatrick case '-':
32061da546Spatrick return BinaryOpNode::Minus;
33061da546Spatrick case '+':
34061da546Spatrick return BinaryOpNode::Plus;
35061da546Spatrick }
36*f6aab3d8Srobert return std::nullopt;
37061da546Spatrick }
38061da546Spatrick
39*f6aab3d8Srobert static std::optional<UnaryOpNode::OpType>
GetUnaryOpType(llvm::StringRef token)40061da546Spatrick GetUnaryOpType(llvm::StringRef token) {
41061da546Spatrick if (token == "^")
42061da546Spatrick return UnaryOpNode::Deref;
43*f6aab3d8Srobert return std::nullopt;
44061da546Spatrick }
45061da546Spatrick
ParseOneExpression(llvm::StringRef expr,llvm::BumpPtrAllocator & alloc)46061da546Spatrick Node *postfix::ParseOneExpression(llvm::StringRef expr,
47061da546Spatrick llvm::BumpPtrAllocator &alloc) {
48061da546Spatrick llvm::SmallVector<Node *, 4> stack;
49061da546Spatrick
50061da546Spatrick llvm::StringRef token;
51061da546Spatrick while (std::tie(token, expr) = getToken(expr), !token.empty()) {
52061da546Spatrick if (auto op_type = GetBinaryOpType(token)) {
53061da546Spatrick // token is binary operator
54061da546Spatrick if (stack.size() < 2)
55061da546Spatrick return nullptr;
56061da546Spatrick
57061da546Spatrick Node *right = stack.pop_back_val();
58061da546Spatrick Node *left = stack.pop_back_val();
59061da546Spatrick stack.push_back(MakeNode<BinaryOpNode>(alloc, *op_type, *left, *right));
60061da546Spatrick continue;
61061da546Spatrick }
62061da546Spatrick
63061da546Spatrick if (auto op_type = GetUnaryOpType(token)) {
64061da546Spatrick // token is unary operator
65061da546Spatrick if (stack.empty())
66061da546Spatrick return nullptr;
67061da546Spatrick
68061da546Spatrick Node *operand = stack.pop_back_val();
69061da546Spatrick stack.push_back(MakeNode<UnaryOpNode>(alloc, *op_type, *operand));
70061da546Spatrick continue;
71061da546Spatrick }
72061da546Spatrick
73061da546Spatrick int64_t value;
74061da546Spatrick if (to_integer(token, value, 10)) {
75061da546Spatrick // token is integer literal
76061da546Spatrick stack.push_back(MakeNode<IntegerNode>(alloc, value));
77061da546Spatrick continue;
78061da546Spatrick }
79061da546Spatrick
80061da546Spatrick stack.push_back(MakeNode<SymbolNode>(alloc, token));
81061da546Spatrick }
82061da546Spatrick
83061da546Spatrick if (stack.size() != 1)
84061da546Spatrick return nullptr;
85061da546Spatrick
86061da546Spatrick return stack.back();
87061da546Spatrick }
88061da546Spatrick
89061da546Spatrick std::vector<std::pair<llvm::StringRef, Node *>>
ParseFPOProgram(llvm::StringRef prog,llvm::BumpPtrAllocator & alloc)90061da546Spatrick postfix::ParseFPOProgram(llvm::StringRef prog, llvm::BumpPtrAllocator &alloc) {
91061da546Spatrick llvm::SmallVector<llvm::StringRef, 4> exprs;
92061da546Spatrick prog.split(exprs, '=');
93061da546Spatrick if (exprs.empty() || !exprs.back().trim().empty())
94061da546Spatrick return {};
95061da546Spatrick exprs.pop_back();
96061da546Spatrick
97061da546Spatrick std::vector<std::pair<llvm::StringRef, Node *>> result;
98061da546Spatrick for (llvm::StringRef expr : exprs) {
99061da546Spatrick llvm::StringRef lhs;
100061da546Spatrick std::tie(lhs, expr) = getToken(expr);
101061da546Spatrick Node *rhs = ParseOneExpression(expr, alloc);
102061da546Spatrick if (!rhs)
103061da546Spatrick return {};
104061da546Spatrick result.emplace_back(lhs, rhs);
105061da546Spatrick }
106061da546Spatrick return result;
107061da546Spatrick }
108061da546Spatrick
109061da546Spatrick namespace {
110061da546Spatrick class SymbolResolver : public Visitor<bool> {
111061da546Spatrick public:
SymbolResolver(llvm::function_ref<Node * (SymbolNode & symbol)> replacer)112061da546Spatrick SymbolResolver(llvm::function_ref<Node *(SymbolNode &symbol)> replacer)
113061da546Spatrick : m_replacer(replacer) {}
114061da546Spatrick
115061da546Spatrick using Visitor<bool>::Dispatch;
116061da546Spatrick
117061da546Spatrick private:
Visit(BinaryOpNode & binary,Node * &)118061da546Spatrick bool Visit(BinaryOpNode &binary, Node *&) override {
119061da546Spatrick return Dispatch(binary.Left()) && Dispatch(binary.Right());
120061da546Spatrick }
121061da546Spatrick
Visit(InitialValueNode &,Node * &)122061da546Spatrick bool Visit(InitialValueNode &, Node *&) override { return true; }
Visit(IntegerNode &,Node * &)123061da546Spatrick bool Visit(IntegerNode &, Node *&) override { return true; }
Visit(RegisterNode &,Node * &)124061da546Spatrick bool Visit(RegisterNode &, Node *&) override { return true; }
125061da546Spatrick
Visit(SymbolNode & symbol,Node * & ref)126061da546Spatrick bool Visit(SymbolNode &symbol, Node *&ref) override {
127061da546Spatrick if (Node *replacement = m_replacer(symbol)) {
128061da546Spatrick ref = replacement;
129061da546Spatrick if (replacement != &symbol)
130061da546Spatrick return Dispatch(ref);
131061da546Spatrick return true;
132061da546Spatrick }
133061da546Spatrick return false;
134061da546Spatrick }
135061da546Spatrick
Visit(UnaryOpNode & unary,Node * &)136061da546Spatrick bool Visit(UnaryOpNode &unary, Node *&) override {
137061da546Spatrick return Dispatch(unary.Operand());
138061da546Spatrick }
139061da546Spatrick
140061da546Spatrick llvm::function_ref<Node *(SymbolNode &symbol)> m_replacer;
141061da546Spatrick };
142061da546Spatrick
143061da546Spatrick class DWARFCodegen : public Visitor<> {
144061da546Spatrick public:
DWARFCodegen(Stream & stream)145061da546Spatrick DWARFCodegen(Stream &stream) : m_out_stream(stream) {}
146061da546Spatrick
147061da546Spatrick using Visitor<>::Dispatch;
148061da546Spatrick
149061da546Spatrick private:
150061da546Spatrick void Visit(BinaryOpNode &binary, Node *&) override;
151061da546Spatrick
152061da546Spatrick void Visit(InitialValueNode &val, Node *&) override;
153061da546Spatrick
Visit(IntegerNode & integer,Node * &)154061da546Spatrick void Visit(IntegerNode &integer, Node *&) override {
155061da546Spatrick m_out_stream.PutHex8(DW_OP_consts);
156061da546Spatrick m_out_stream.PutSLEB128(integer.GetValue());
157061da546Spatrick ++m_stack_depth;
158061da546Spatrick }
159061da546Spatrick
160061da546Spatrick void Visit(RegisterNode ®, Node *&) override;
161061da546Spatrick
Visit(SymbolNode & symbol,Node * &)162061da546Spatrick void Visit(SymbolNode &symbol, Node *&) override {
163061da546Spatrick llvm_unreachable("Symbols should have been resolved by now!");
164061da546Spatrick }
165061da546Spatrick
166061da546Spatrick void Visit(UnaryOpNode &unary, Node *&) override;
167061da546Spatrick
168061da546Spatrick Stream &m_out_stream;
169061da546Spatrick
170061da546Spatrick /// The number keeping track of the evaluation stack depth at any given
171061da546Spatrick /// moment. Used for implementing InitialValueNodes. We start with
172061da546Spatrick /// m_stack_depth = 1, assuming that the initial value is already on the
173061da546Spatrick /// stack. This initial value will be the value of all InitialValueNodes. If
174061da546Spatrick /// the expression does not contain InitialValueNodes, then m_stack_depth is
175061da546Spatrick /// not used, and the generated expression will run correctly even without an
176061da546Spatrick /// initial value.
177061da546Spatrick size_t m_stack_depth = 1;
178061da546Spatrick };
179061da546Spatrick } // namespace
180061da546Spatrick
Visit(BinaryOpNode & binary,Node * &)181061da546Spatrick void DWARFCodegen::Visit(BinaryOpNode &binary, Node *&) {
182061da546Spatrick Dispatch(binary.Left());
183061da546Spatrick Dispatch(binary.Right());
184061da546Spatrick
185061da546Spatrick switch (binary.GetOpType()) {
186061da546Spatrick case BinaryOpNode::Plus:
187061da546Spatrick m_out_stream.PutHex8(DW_OP_plus);
188061da546Spatrick // NOTE: can be optimized by using DW_OP_plus_uconst opcpode
189061da546Spatrick // if right child node is constant value
190061da546Spatrick break;
191061da546Spatrick case BinaryOpNode::Minus:
192061da546Spatrick m_out_stream.PutHex8(DW_OP_minus);
193061da546Spatrick break;
194061da546Spatrick case BinaryOpNode::Align:
195061da546Spatrick // emit align operator a @ b as
196061da546Spatrick // a & ~(b - 1)
197061da546Spatrick // NOTE: implicitly assuming that b is power of 2
198061da546Spatrick m_out_stream.PutHex8(DW_OP_lit1);
199061da546Spatrick m_out_stream.PutHex8(DW_OP_minus);
200061da546Spatrick m_out_stream.PutHex8(DW_OP_not);
201061da546Spatrick
202061da546Spatrick m_out_stream.PutHex8(DW_OP_and);
203061da546Spatrick break;
204061da546Spatrick }
205061da546Spatrick --m_stack_depth; // Two pops, one push.
206061da546Spatrick }
207061da546Spatrick
Visit(InitialValueNode &,Node * &)208061da546Spatrick void DWARFCodegen::Visit(InitialValueNode &, Node *&) {
209061da546Spatrick // We never go below the initial stack, so we can pick the initial value from
210061da546Spatrick // the bottom of the stack at any moment.
211061da546Spatrick assert(m_stack_depth >= 1);
212061da546Spatrick m_out_stream.PutHex8(DW_OP_pick);
213061da546Spatrick m_out_stream.PutHex8(m_stack_depth - 1);
214061da546Spatrick ++m_stack_depth;
215061da546Spatrick }
216061da546Spatrick
Visit(RegisterNode & reg,Node * &)217061da546Spatrick void DWARFCodegen::Visit(RegisterNode ®, Node *&) {
218061da546Spatrick uint32_t reg_num = reg.GetRegNum();
219061da546Spatrick assert(reg_num != LLDB_INVALID_REGNUM);
220061da546Spatrick
221061da546Spatrick if (reg_num > 31) {
222061da546Spatrick m_out_stream.PutHex8(DW_OP_bregx);
223061da546Spatrick m_out_stream.PutULEB128(reg_num);
224061da546Spatrick } else
225061da546Spatrick m_out_stream.PutHex8(DW_OP_breg0 + reg_num);
226061da546Spatrick
227061da546Spatrick m_out_stream.PutSLEB128(0);
228061da546Spatrick ++m_stack_depth;
229061da546Spatrick }
230061da546Spatrick
Visit(UnaryOpNode & unary,Node * &)231061da546Spatrick void DWARFCodegen::Visit(UnaryOpNode &unary, Node *&) {
232061da546Spatrick Dispatch(unary.Operand());
233061da546Spatrick
234061da546Spatrick switch (unary.GetOpType()) {
235061da546Spatrick case UnaryOpNode::Deref:
236061da546Spatrick m_out_stream.PutHex8(DW_OP_deref);
237061da546Spatrick break;
238061da546Spatrick }
239061da546Spatrick // Stack depth unchanged.
240061da546Spatrick }
241061da546Spatrick
ResolveSymbols(Node * & node,llvm::function_ref<Node * (SymbolNode &)> replacer)242061da546Spatrick bool postfix::ResolveSymbols(
243061da546Spatrick Node *&node, llvm::function_ref<Node *(SymbolNode &)> replacer) {
244061da546Spatrick return SymbolResolver(replacer).Dispatch(node);
245061da546Spatrick }
246061da546Spatrick
ToDWARF(Node & node,Stream & stream)247061da546Spatrick void postfix::ToDWARF(Node &node, Stream &stream) {
248061da546Spatrick Node *ptr = &node;
249061da546Spatrick DWARFCodegen(stream).Dispatch(ptr);
250061da546Spatrick }
251