1cfca06d7SDimitry Andric //===-- PostfixExpression.cpp ---------------------------------------------===//
25f29bb8aSDimitry Andric //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f29bb8aSDimitry Andric //
75f29bb8aSDimitry Andric //===----------------------------------------------------------------------===//
85f29bb8aSDimitry Andric //
95f29bb8aSDimitry Andric // This file implements support for postfix expressions found in several symbol
105f29bb8aSDimitry Andric // file formats, and their conversion to DWARF.
115f29bb8aSDimitry Andric //
125f29bb8aSDimitry Andric //===----------------------------------------------------------------------===//
135f29bb8aSDimitry Andric
145f29bb8aSDimitry Andric #include "lldb/Symbol/PostfixExpression.h"
155f29bb8aSDimitry Andric #include "lldb/Core/dwarf.h"
165f29bb8aSDimitry Andric #include "lldb/Utility/Stream.h"
175f29bb8aSDimitry Andric #include "llvm/ADT/StringExtras.h"
18e3b55780SDimitry Andric #include <optional>
195f29bb8aSDimitry Andric
205f29bb8aSDimitry Andric using namespace lldb_private;
215f29bb8aSDimitry Andric using namespace lldb_private::postfix;
22145449b1SDimitry Andric using namespace lldb_private::dwarf;
235f29bb8aSDimitry Andric
24e3b55780SDimitry Andric static std::optional<BinaryOpNode::OpType>
GetBinaryOpType(llvm::StringRef token)255f29bb8aSDimitry Andric GetBinaryOpType(llvm::StringRef token) {
265f29bb8aSDimitry Andric if (token.size() != 1)
27e3b55780SDimitry Andric return std::nullopt;
285f29bb8aSDimitry Andric switch (token[0]) {
295f29bb8aSDimitry Andric case '@':
305f29bb8aSDimitry Andric return BinaryOpNode::Align;
315f29bb8aSDimitry Andric case '-':
325f29bb8aSDimitry Andric return BinaryOpNode::Minus;
335f29bb8aSDimitry Andric case '+':
345f29bb8aSDimitry Andric return BinaryOpNode::Plus;
355f29bb8aSDimitry Andric }
36e3b55780SDimitry Andric return std::nullopt;
375f29bb8aSDimitry Andric }
385f29bb8aSDimitry Andric
39e3b55780SDimitry Andric static std::optional<UnaryOpNode::OpType>
GetUnaryOpType(llvm::StringRef token)405f29bb8aSDimitry Andric GetUnaryOpType(llvm::StringRef token) {
415f29bb8aSDimitry Andric if (token == "^")
425f29bb8aSDimitry Andric return UnaryOpNode::Deref;
43e3b55780SDimitry Andric return std::nullopt;
445f29bb8aSDimitry Andric }
455f29bb8aSDimitry Andric
ParseOneExpression(llvm::StringRef expr,llvm::BumpPtrAllocator & alloc)46ead24645SDimitry Andric Node *postfix::ParseOneExpression(llvm::StringRef expr,
47ead24645SDimitry Andric llvm::BumpPtrAllocator &alloc) {
485f29bb8aSDimitry Andric llvm::SmallVector<Node *, 4> stack;
495f29bb8aSDimitry Andric
505f29bb8aSDimitry Andric llvm::StringRef token;
515f29bb8aSDimitry Andric while (std::tie(token, expr) = getToken(expr), !token.empty()) {
525f29bb8aSDimitry Andric if (auto op_type = GetBinaryOpType(token)) {
535f29bb8aSDimitry Andric // token is binary operator
545f29bb8aSDimitry Andric if (stack.size() < 2)
555f29bb8aSDimitry Andric return nullptr;
565f29bb8aSDimitry Andric
575f29bb8aSDimitry Andric Node *right = stack.pop_back_val();
585f29bb8aSDimitry Andric Node *left = stack.pop_back_val();
595f29bb8aSDimitry Andric stack.push_back(MakeNode<BinaryOpNode>(alloc, *op_type, *left, *right));
605f29bb8aSDimitry Andric continue;
615f29bb8aSDimitry Andric }
625f29bb8aSDimitry Andric
635f29bb8aSDimitry Andric if (auto op_type = GetUnaryOpType(token)) {
645f29bb8aSDimitry Andric // token is unary operator
655f29bb8aSDimitry Andric if (stack.empty())
665f29bb8aSDimitry Andric return nullptr;
675f29bb8aSDimitry Andric
685f29bb8aSDimitry Andric Node *operand = stack.pop_back_val();
695f29bb8aSDimitry Andric stack.push_back(MakeNode<UnaryOpNode>(alloc, *op_type, *operand));
705f29bb8aSDimitry Andric continue;
715f29bb8aSDimitry Andric }
725f29bb8aSDimitry Andric
735f29bb8aSDimitry Andric int64_t value;
745f29bb8aSDimitry Andric if (to_integer(token, value, 10)) {
755f29bb8aSDimitry Andric // token is integer literal
765f29bb8aSDimitry Andric stack.push_back(MakeNode<IntegerNode>(alloc, value));
775f29bb8aSDimitry Andric continue;
785f29bb8aSDimitry Andric }
795f29bb8aSDimitry Andric
805f29bb8aSDimitry Andric stack.push_back(MakeNode<SymbolNode>(alloc, token));
815f29bb8aSDimitry Andric }
825f29bb8aSDimitry Andric
835f29bb8aSDimitry Andric if (stack.size() != 1)
845f29bb8aSDimitry Andric return nullptr;
855f29bb8aSDimitry Andric
865f29bb8aSDimitry Andric return stack.back();
875f29bb8aSDimitry Andric }
885f29bb8aSDimitry Andric
89ead24645SDimitry Andric std::vector<std::pair<llvm::StringRef, Node *>>
ParseFPOProgram(llvm::StringRef prog,llvm::BumpPtrAllocator & alloc)90ead24645SDimitry Andric postfix::ParseFPOProgram(llvm::StringRef prog, llvm::BumpPtrAllocator &alloc) {
91ead24645SDimitry Andric llvm::SmallVector<llvm::StringRef, 4> exprs;
92ead24645SDimitry Andric prog.split(exprs, '=');
93ead24645SDimitry Andric if (exprs.empty() || !exprs.back().trim().empty())
94ead24645SDimitry Andric return {};
95ead24645SDimitry Andric exprs.pop_back();
96ead24645SDimitry Andric
97ead24645SDimitry Andric std::vector<std::pair<llvm::StringRef, Node *>> result;
98ead24645SDimitry Andric for (llvm::StringRef expr : exprs) {
99ead24645SDimitry Andric llvm::StringRef lhs;
100ead24645SDimitry Andric std::tie(lhs, expr) = getToken(expr);
101ead24645SDimitry Andric Node *rhs = ParseOneExpression(expr, alloc);
102ead24645SDimitry Andric if (!rhs)
103ead24645SDimitry Andric return {};
104ead24645SDimitry Andric result.emplace_back(lhs, rhs);
105ead24645SDimitry Andric }
106ead24645SDimitry Andric return result;
107ead24645SDimitry Andric }
108ead24645SDimitry Andric
1095f29bb8aSDimitry Andric namespace {
1105f29bb8aSDimitry Andric class SymbolResolver : public Visitor<bool> {
1115f29bb8aSDimitry Andric public:
SymbolResolver(llvm::function_ref<Node * (SymbolNode & symbol)> replacer)1125f29bb8aSDimitry Andric SymbolResolver(llvm::function_ref<Node *(SymbolNode &symbol)> replacer)
1135f29bb8aSDimitry Andric : m_replacer(replacer) {}
1145f29bb8aSDimitry Andric
1155f29bb8aSDimitry Andric using Visitor<bool>::Dispatch;
1165f29bb8aSDimitry Andric
1175f29bb8aSDimitry Andric private:
Visit(BinaryOpNode & binary,Node * &)1185f29bb8aSDimitry Andric bool Visit(BinaryOpNode &binary, Node *&) override {
1195f29bb8aSDimitry Andric return Dispatch(binary.Left()) && Dispatch(binary.Right());
1205f29bb8aSDimitry Andric }
1215f29bb8aSDimitry Andric
Visit(InitialValueNode &,Node * &)1225f29bb8aSDimitry Andric bool Visit(InitialValueNode &, Node *&) override { return true; }
Visit(IntegerNode &,Node * &)1235f29bb8aSDimitry Andric bool Visit(IntegerNode &, Node *&) override { return true; }
Visit(RegisterNode &,Node * &)1245f29bb8aSDimitry Andric bool Visit(RegisterNode &, Node *&) override { return true; }
1255f29bb8aSDimitry Andric
Visit(SymbolNode & symbol,Node * & ref)1265f29bb8aSDimitry Andric bool Visit(SymbolNode &symbol, Node *&ref) override {
1275f29bb8aSDimitry Andric if (Node *replacement = m_replacer(symbol)) {
1285f29bb8aSDimitry Andric ref = replacement;
1295f29bb8aSDimitry Andric if (replacement != &symbol)
1305f29bb8aSDimitry Andric return Dispatch(ref);
1315f29bb8aSDimitry Andric return true;
1325f29bb8aSDimitry Andric }
1335f29bb8aSDimitry Andric return false;
1345f29bb8aSDimitry Andric }
1355f29bb8aSDimitry Andric
Visit(UnaryOpNode & unary,Node * &)1365f29bb8aSDimitry Andric bool Visit(UnaryOpNode &unary, Node *&) override {
1375f29bb8aSDimitry Andric return Dispatch(unary.Operand());
1385f29bb8aSDimitry Andric }
1395f29bb8aSDimitry Andric
1405f29bb8aSDimitry Andric llvm::function_ref<Node *(SymbolNode &symbol)> m_replacer;
1415f29bb8aSDimitry Andric };
1425f29bb8aSDimitry Andric
1435f29bb8aSDimitry Andric class DWARFCodegen : public Visitor<> {
1445f29bb8aSDimitry Andric public:
DWARFCodegen(Stream & stream)1455f29bb8aSDimitry Andric DWARFCodegen(Stream &stream) : m_out_stream(stream) {}
1465f29bb8aSDimitry Andric
1475f29bb8aSDimitry Andric using Visitor<>::Dispatch;
1485f29bb8aSDimitry Andric
1495f29bb8aSDimitry Andric private:
1505f29bb8aSDimitry Andric void Visit(BinaryOpNode &binary, Node *&) override;
1515f29bb8aSDimitry Andric
1525f29bb8aSDimitry Andric void Visit(InitialValueNode &val, Node *&) override;
1535f29bb8aSDimitry Andric
Visit(IntegerNode & integer,Node * &)1545f29bb8aSDimitry Andric void Visit(IntegerNode &integer, Node *&) override {
1555f29bb8aSDimitry Andric m_out_stream.PutHex8(DW_OP_consts);
1565f29bb8aSDimitry Andric m_out_stream.PutSLEB128(integer.GetValue());
1575f29bb8aSDimitry Andric ++m_stack_depth;
1585f29bb8aSDimitry Andric }
1595f29bb8aSDimitry Andric
1605f29bb8aSDimitry Andric void Visit(RegisterNode ®, Node *&) override;
1615f29bb8aSDimitry Andric
Visit(SymbolNode & symbol,Node * &)1625f29bb8aSDimitry Andric void Visit(SymbolNode &symbol, Node *&) override {
1635f29bb8aSDimitry Andric llvm_unreachable("Symbols should have been resolved by now!");
1645f29bb8aSDimitry Andric }
1655f29bb8aSDimitry Andric
1665f29bb8aSDimitry Andric void Visit(UnaryOpNode &unary, Node *&) override;
1675f29bb8aSDimitry Andric
1685f29bb8aSDimitry Andric Stream &m_out_stream;
1695f29bb8aSDimitry Andric
1705f29bb8aSDimitry Andric /// The number keeping track of the evaluation stack depth at any given
1715f29bb8aSDimitry Andric /// moment. Used for implementing InitialValueNodes. We start with
1725f29bb8aSDimitry Andric /// m_stack_depth = 1, assuming that the initial value is already on the
1735f29bb8aSDimitry Andric /// stack. This initial value will be the value of all InitialValueNodes. If
1745f29bb8aSDimitry Andric /// the expression does not contain InitialValueNodes, then m_stack_depth is
1755f29bb8aSDimitry Andric /// not used, and the generated expression will run correctly even without an
1765f29bb8aSDimitry Andric /// initial value.
1775f29bb8aSDimitry Andric size_t m_stack_depth = 1;
1785f29bb8aSDimitry Andric };
1795f29bb8aSDimitry Andric } // namespace
1805f29bb8aSDimitry Andric
Visit(BinaryOpNode & binary,Node * &)1815f29bb8aSDimitry Andric void DWARFCodegen::Visit(BinaryOpNode &binary, Node *&) {
1825f29bb8aSDimitry Andric Dispatch(binary.Left());
1835f29bb8aSDimitry Andric Dispatch(binary.Right());
1845f29bb8aSDimitry Andric
1855f29bb8aSDimitry Andric switch (binary.GetOpType()) {
1865f29bb8aSDimitry Andric case BinaryOpNode::Plus:
1875f29bb8aSDimitry Andric m_out_stream.PutHex8(DW_OP_plus);
1885f29bb8aSDimitry Andric // NOTE: can be optimized by using DW_OP_plus_uconst opcpode
1895f29bb8aSDimitry Andric // if right child node is constant value
1905f29bb8aSDimitry Andric break;
1915f29bb8aSDimitry Andric case BinaryOpNode::Minus:
1925f29bb8aSDimitry Andric m_out_stream.PutHex8(DW_OP_minus);
1935f29bb8aSDimitry Andric break;
1945f29bb8aSDimitry Andric case BinaryOpNode::Align:
1955f29bb8aSDimitry Andric // emit align operator a @ b as
1965f29bb8aSDimitry Andric // a & ~(b - 1)
1975f29bb8aSDimitry Andric // NOTE: implicitly assuming that b is power of 2
1985f29bb8aSDimitry Andric m_out_stream.PutHex8(DW_OP_lit1);
1995f29bb8aSDimitry Andric m_out_stream.PutHex8(DW_OP_minus);
2005f29bb8aSDimitry Andric m_out_stream.PutHex8(DW_OP_not);
2015f29bb8aSDimitry Andric
2025f29bb8aSDimitry Andric m_out_stream.PutHex8(DW_OP_and);
2035f29bb8aSDimitry Andric break;
2045f29bb8aSDimitry Andric }
2055f29bb8aSDimitry Andric --m_stack_depth; // Two pops, one push.
2065f29bb8aSDimitry Andric }
2075f29bb8aSDimitry Andric
Visit(InitialValueNode &,Node * &)2085f29bb8aSDimitry Andric void DWARFCodegen::Visit(InitialValueNode &, Node *&) {
2095f29bb8aSDimitry Andric // We never go below the initial stack, so we can pick the initial value from
2105f29bb8aSDimitry Andric // the bottom of the stack at any moment.
2115f29bb8aSDimitry Andric assert(m_stack_depth >= 1);
2125f29bb8aSDimitry Andric m_out_stream.PutHex8(DW_OP_pick);
2135f29bb8aSDimitry Andric m_out_stream.PutHex8(m_stack_depth - 1);
2145f29bb8aSDimitry Andric ++m_stack_depth;
2155f29bb8aSDimitry Andric }
2165f29bb8aSDimitry Andric
Visit(RegisterNode & reg,Node * &)2175f29bb8aSDimitry Andric void DWARFCodegen::Visit(RegisterNode ®, Node *&) {
2185f29bb8aSDimitry Andric uint32_t reg_num = reg.GetRegNum();
2195f29bb8aSDimitry Andric assert(reg_num != LLDB_INVALID_REGNUM);
2205f29bb8aSDimitry Andric
2215f29bb8aSDimitry Andric if (reg_num > 31) {
2225f29bb8aSDimitry Andric m_out_stream.PutHex8(DW_OP_bregx);
2235f29bb8aSDimitry Andric m_out_stream.PutULEB128(reg_num);
2245f29bb8aSDimitry Andric } else
2255f29bb8aSDimitry Andric m_out_stream.PutHex8(DW_OP_breg0 + reg_num);
2265f29bb8aSDimitry Andric
2275f29bb8aSDimitry Andric m_out_stream.PutSLEB128(0);
2285f29bb8aSDimitry Andric ++m_stack_depth;
2295f29bb8aSDimitry Andric }
2305f29bb8aSDimitry Andric
Visit(UnaryOpNode & unary,Node * &)2315f29bb8aSDimitry Andric void DWARFCodegen::Visit(UnaryOpNode &unary, Node *&) {
2325f29bb8aSDimitry Andric Dispatch(unary.Operand());
2335f29bb8aSDimitry Andric
2345f29bb8aSDimitry Andric switch (unary.GetOpType()) {
2355f29bb8aSDimitry Andric case UnaryOpNode::Deref:
2365f29bb8aSDimitry Andric m_out_stream.PutHex8(DW_OP_deref);
2375f29bb8aSDimitry Andric break;
2385f29bb8aSDimitry Andric }
2395f29bb8aSDimitry Andric // Stack depth unchanged.
2405f29bb8aSDimitry Andric }
2415f29bb8aSDimitry Andric
ResolveSymbols(Node * & node,llvm::function_ref<Node * (SymbolNode &)> replacer)2425f29bb8aSDimitry Andric bool postfix::ResolveSymbols(
2435f29bb8aSDimitry Andric Node *&node, llvm::function_ref<Node *(SymbolNode &)> replacer) {
2445f29bb8aSDimitry Andric return SymbolResolver(replacer).Dispatch(node);
2455f29bb8aSDimitry Andric }
2465f29bb8aSDimitry Andric
ToDWARF(Node & node,Stream & stream)2475f29bb8aSDimitry Andric void postfix::ToDWARF(Node &node, Stream &stream) {
2485f29bb8aSDimitry Andric Node *ptr = &node;
2495f29bb8aSDimitry Andric DWARFCodegen(stream).Dispatch(ptr);
2505f29bb8aSDimitry Andric }
251