180814287SRaphael Isemann //===-- PostfixExpression.cpp ---------------------------------------------===//
288813103SPavel Labath //
388813103SPavel Labath // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
488813103SPavel Labath // See https://llvm.org/LICENSE.txt for license information.
588813103SPavel Labath // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
688813103SPavel Labath //
788813103SPavel Labath //===----------------------------------------------------------------------===//
888813103SPavel Labath //
988813103SPavel Labath //  This file implements support for postfix expressions found in several symbol
1088813103SPavel Labath //  file formats, and their conversion to DWARF.
1188813103SPavel Labath //
1288813103SPavel Labath //===----------------------------------------------------------------------===//
1388813103SPavel Labath 
1488813103SPavel Labath #include "lldb/Symbol/PostfixExpression.h"
150eadd988SPavel Labath #include "lldb/Core/dwarf.h"
160eadd988SPavel Labath #include "lldb/Utility/Stream.h"
1788813103SPavel Labath #include "llvm/ADT/StringExtras.h"
1888813103SPavel Labath 
1988813103SPavel Labath using namespace lldb_private;
2088813103SPavel Labath using namespace lldb_private::postfix;
21*ae869d44SShafik Yaghmour using namespace lldb_private::dwarf;
2288813103SPavel Labath 
2388813103SPavel Labath static llvm::Optional<BinaryOpNode::OpType>
GetBinaryOpType(llvm::StringRef token)2488813103SPavel Labath GetBinaryOpType(llvm::StringRef token) {
2588813103SPavel Labath   if (token.size() != 1)
2688813103SPavel Labath     return llvm::None;
2788813103SPavel Labath   switch (token[0]) {
2888813103SPavel Labath   case '@':
2988813103SPavel Labath     return BinaryOpNode::Align;
3088813103SPavel Labath   case '-':
3188813103SPavel Labath     return BinaryOpNode::Minus;
3288813103SPavel Labath   case '+':
3388813103SPavel Labath     return BinaryOpNode::Plus;
3488813103SPavel Labath   }
3588813103SPavel Labath   return llvm::None;
3688813103SPavel Labath }
3788813103SPavel Labath 
3888813103SPavel Labath static llvm::Optional<UnaryOpNode::OpType>
GetUnaryOpType(llvm::StringRef token)3988813103SPavel Labath GetUnaryOpType(llvm::StringRef token) {
4088813103SPavel Labath   if (token == "^")
4188813103SPavel Labath     return UnaryOpNode::Deref;
4288813103SPavel Labath   return llvm::None;
4388813103SPavel Labath }
4488813103SPavel Labath 
ParseOneExpression(llvm::StringRef expr,llvm::BumpPtrAllocator & alloc)45c7deb7f8SPavel Labath Node *postfix::ParseOneExpression(llvm::StringRef expr,
46c7deb7f8SPavel Labath                                   llvm::BumpPtrAllocator &alloc) {
4788813103SPavel Labath   llvm::SmallVector<Node *, 4> stack;
4888813103SPavel Labath 
4988813103SPavel Labath   llvm::StringRef token;
5088813103SPavel Labath   while (std::tie(token, expr) = getToken(expr), !token.empty()) {
5188813103SPavel Labath     if (auto op_type = GetBinaryOpType(token)) {
5288813103SPavel Labath       // token is binary operator
5388813103SPavel Labath       if (stack.size() < 2)
5488813103SPavel Labath         return nullptr;
5588813103SPavel Labath 
5688813103SPavel Labath       Node *right = stack.pop_back_val();
5788813103SPavel Labath       Node *left = stack.pop_back_val();
5888813103SPavel Labath       stack.push_back(MakeNode<BinaryOpNode>(alloc, *op_type, *left, *right));
5988813103SPavel Labath       continue;
6088813103SPavel Labath     }
6188813103SPavel Labath 
6288813103SPavel Labath     if (auto op_type = GetUnaryOpType(token)) {
6388813103SPavel Labath       // token is unary operator
6488813103SPavel Labath       if (stack.empty())
6588813103SPavel Labath         return nullptr;
6688813103SPavel Labath 
6788813103SPavel Labath       Node *operand = stack.pop_back_val();
6888813103SPavel Labath       stack.push_back(MakeNode<UnaryOpNode>(alloc, *op_type, *operand));
6988813103SPavel Labath       continue;
7088813103SPavel Labath     }
7188813103SPavel Labath 
720ff89dacSPavel Labath     int64_t value;
7388813103SPavel Labath     if (to_integer(token, value, 10)) {
7488813103SPavel Labath       // token is integer literal
7588813103SPavel Labath       stack.push_back(MakeNode<IntegerNode>(alloc, value));
7688813103SPavel Labath       continue;
7788813103SPavel Labath     }
7888813103SPavel Labath 
7988813103SPavel Labath     stack.push_back(MakeNode<SymbolNode>(alloc, token));
8088813103SPavel Labath   }
8188813103SPavel Labath 
8288813103SPavel Labath   if (stack.size() != 1)
8388813103SPavel Labath     return nullptr;
8488813103SPavel Labath 
8588813103SPavel Labath   return stack.back();
8688813103SPavel Labath }
870eadd988SPavel Labath 
88c7deb7f8SPavel Labath std::vector<std::pair<llvm::StringRef, Node *>>
ParseFPOProgram(llvm::StringRef prog,llvm::BumpPtrAllocator & alloc)89c7deb7f8SPavel Labath postfix::ParseFPOProgram(llvm::StringRef prog, llvm::BumpPtrAllocator &alloc) {
90c7deb7f8SPavel Labath   llvm::SmallVector<llvm::StringRef, 4> exprs;
91c7deb7f8SPavel Labath   prog.split(exprs, '=');
92c7deb7f8SPavel Labath   if (exprs.empty() || !exprs.back().trim().empty())
93c7deb7f8SPavel Labath     return {};
94c7deb7f8SPavel Labath   exprs.pop_back();
95c7deb7f8SPavel Labath 
96c7deb7f8SPavel Labath   std::vector<std::pair<llvm::StringRef, Node *>> result;
97c7deb7f8SPavel Labath   for (llvm::StringRef expr : exprs) {
98c7deb7f8SPavel Labath     llvm::StringRef lhs;
99c7deb7f8SPavel Labath     std::tie(lhs, expr) = getToken(expr);
100c7deb7f8SPavel Labath     Node *rhs = ParseOneExpression(expr, alloc);
101c7deb7f8SPavel Labath     if (!rhs)
102c7deb7f8SPavel Labath       return {};
103c7deb7f8SPavel Labath     result.emplace_back(lhs, rhs);
104c7deb7f8SPavel Labath   }
105c7deb7f8SPavel Labath   return result;
106c7deb7f8SPavel Labath }
107c7deb7f8SPavel Labath 
1080eadd988SPavel Labath namespace {
1090eadd988SPavel Labath class SymbolResolver : public Visitor<bool> {
1100eadd988SPavel Labath public:
SymbolResolver(llvm::function_ref<Node * (SymbolNode & symbol)> replacer)1110eadd988SPavel Labath   SymbolResolver(llvm::function_ref<Node *(SymbolNode &symbol)> replacer)
1120eadd988SPavel Labath       : m_replacer(replacer) {}
1130eadd988SPavel Labath 
1140eadd988SPavel Labath   using Visitor<bool>::Dispatch;
1150eadd988SPavel Labath 
1160eadd988SPavel Labath private:
Visit(BinaryOpNode & binary,Node * &)1170eadd988SPavel Labath   bool Visit(BinaryOpNode &binary, Node *&) override {
1180eadd988SPavel Labath     return Dispatch(binary.Left()) && Dispatch(binary.Right());
1190eadd988SPavel Labath   }
1200eadd988SPavel Labath 
Visit(InitialValueNode &,Node * &)12103db32b3SPavel Labath   bool Visit(InitialValueNode &, Node *&) override { return true; }
Visit(IntegerNode &,Node * &)12203db32b3SPavel Labath   bool Visit(IntegerNode &, Node *&) override { return true; }
Visit(RegisterNode &,Node * &)12303db32b3SPavel Labath   bool Visit(RegisterNode &, Node *&) override { return true; }
1240eadd988SPavel Labath 
Visit(SymbolNode & symbol,Node * & ref)1250eadd988SPavel Labath   bool Visit(SymbolNode &symbol, Node *&ref) override {
1260eadd988SPavel Labath     if (Node *replacement = m_replacer(symbol)) {
1270eadd988SPavel Labath       ref = replacement;
1280eadd988SPavel Labath       if (replacement != &symbol)
1290eadd988SPavel Labath         return Dispatch(ref);
1300eadd988SPavel Labath       return true;
1310eadd988SPavel Labath     }
1320eadd988SPavel Labath     return false;
1330eadd988SPavel Labath   }
1340eadd988SPavel Labath 
Visit(UnaryOpNode & unary,Node * &)1350eadd988SPavel Labath   bool Visit(UnaryOpNode &unary, Node *&) override {
1360eadd988SPavel Labath     return Dispatch(unary.Operand());
1370eadd988SPavel Labath   }
1380eadd988SPavel Labath 
1390eadd988SPavel Labath   llvm::function_ref<Node *(SymbolNode &symbol)> m_replacer;
1400eadd988SPavel Labath };
1410eadd988SPavel Labath 
1420eadd988SPavel Labath class DWARFCodegen : public Visitor<> {
1430eadd988SPavel Labath public:
DWARFCodegen(Stream & stream)1440eadd988SPavel Labath   DWARFCodegen(Stream &stream) : m_out_stream(stream) {}
1450eadd988SPavel Labath 
1460eadd988SPavel Labath   using Visitor<>::Dispatch;
1470eadd988SPavel Labath 
1480eadd988SPavel Labath private:
1491756630dSRaphael Isemann   void Visit(BinaryOpNode &binary, Node *&) override;
1500eadd988SPavel Labath 
1511756630dSRaphael Isemann   void Visit(InitialValueNode &val, Node *&) override;
15203db32b3SPavel Labath 
Visit(IntegerNode & integer,Node * &)1531756630dSRaphael Isemann   void Visit(IntegerNode &integer, Node *&) override {
1540ff89dacSPavel Labath     m_out_stream.PutHex8(DW_OP_consts);
1550ff89dacSPavel Labath     m_out_stream.PutSLEB128(integer.GetValue());
15603db32b3SPavel Labath     ++m_stack_depth;
1570eadd988SPavel Labath   }
1580eadd988SPavel Labath 
1591756630dSRaphael Isemann   void Visit(RegisterNode &reg, Node *&) override;
1600eadd988SPavel Labath 
Visit(SymbolNode & symbol,Node * &)1611756630dSRaphael Isemann   void Visit(SymbolNode &symbol, Node *&) override {
1620eadd988SPavel Labath     llvm_unreachable("Symbols should have been resolved by now!");
1630eadd988SPavel Labath   }
1640eadd988SPavel Labath 
1651756630dSRaphael Isemann   void Visit(UnaryOpNode &unary, Node *&) override;
1660eadd988SPavel Labath 
1670eadd988SPavel Labath   Stream &m_out_stream;
16803db32b3SPavel Labath 
16903db32b3SPavel Labath   /// The number keeping track of the evaluation stack depth at any given
17003db32b3SPavel Labath   /// moment. Used for implementing InitialValueNodes. We start with
17103db32b3SPavel Labath   /// m_stack_depth = 1, assuming that the initial value is already on the
17203db32b3SPavel Labath   /// stack. This initial value will be the value of all InitialValueNodes. If
17303db32b3SPavel Labath   /// the expression does not contain InitialValueNodes, then m_stack_depth is
17403db32b3SPavel Labath   /// not used, and the generated expression will run correctly even without an
17503db32b3SPavel Labath   /// initial value.
17603db32b3SPavel Labath   size_t m_stack_depth = 1;
1770eadd988SPavel Labath };
1780eadd988SPavel Labath } // namespace
1790eadd988SPavel Labath 
Visit(BinaryOpNode & binary,Node * &)1800eadd988SPavel Labath void DWARFCodegen::Visit(BinaryOpNode &binary, Node *&) {
1810eadd988SPavel Labath   Dispatch(binary.Left());
1820eadd988SPavel Labath   Dispatch(binary.Right());
1830eadd988SPavel Labath 
1840eadd988SPavel Labath   switch (binary.GetOpType()) {
1850eadd988SPavel Labath   case BinaryOpNode::Plus:
1860eadd988SPavel Labath     m_out_stream.PutHex8(DW_OP_plus);
1870eadd988SPavel Labath     // NOTE: can be optimized by using DW_OP_plus_uconst opcpode
1880eadd988SPavel Labath     //       if right child node is constant value
1890eadd988SPavel Labath     break;
1900eadd988SPavel Labath   case BinaryOpNode::Minus:
1910eadd988SPavel Labath     m_out_stream.PutHex8(DW_OP_minus);
1920eadd988SPavel Labath     break;
1930eadd988SPavel Labath   case BinaryOpNode::Align:
1940eadd988SPavel Labath     // emit align operator a @ b as
1950eadd988SPavel Labath     // a & ~(b - 1)
1960eadd988SPavel Labath     // NOTE: implicitly assuming that b is power of 2
1970eadd988SPavel Labath     m_out_stream.PutHex8(DW_OP_lit1);
1980eadd988SPavel Labath     m_out_stream.PutHex8(DW_OP_minus);
1990eadd988SPavel Labath     m_out_stream.PutHex8(DW_OP_not);
2000eadd988SPavel Labath 
2010eadd988SPavel Labath     m_out_stream.PutHex8(DW_OP_and);
2020eadd988SPavel Labath     break;
2030eadd988SPavel Labath   }
20403db32b3SPavel Labath   --m_stack_depth; // Two pops, one push.
20503db32b3SPavel Labath }
20603db32b3SPavel Labath 
Visit(InitialValueNode &,Node * &)20703db32b3SPavel Labath void DWARFCodegen::Visit(InitialValueNode &, Node *&) {
20803db32b3SPavel Labath   // We never go below the initial stack, so we can pick the initial value from
20903db32b3SPavel Labath   // the bottom of the stack at any moment.
21003db32b3SPavel Labath   assert(m_stack_depth >= 1);
21103db32b3SPavel Labath   m_out_stream.PutHex8(DW_OP_pick);
21203db32b3SPavel Labath   m_out_stream.PutHex8(m_stack_depth - 1);
21303db32b3SPavel Labath   ++m_stack_depth;
2140eadd988SPavel Labath }
2150eadd988SPavel Labath 
Visit(RegisterNode & reg,Node * &)2160eadd988SPavel Labath void DWARFCodegen::Visit(RegisterNode &reg, Node *&) {
2170eadd988SPavel Labath   uint32_t reg_num = reg.GetRegNum();
2180eadd988SPavel Labath   assert(reg_num != LLDB_INVALID_REGNUM);
2190eadd988SPavel Labath 
2200eadd988SPavel Labath   if (reg_num > 31) {
2210eadd988SPavel Labath     m_out_stream.PutHex8(DW_OP_bregx);
2220eadd988SPavel Labath     m_out_stream.PutULEB128(reg_num);
2230eadd988SPavel Labath   } else
2240eadd988SPavel Labath     m_out_stream.PutHex8(DW_OP_breg0 + reg_num);
2250eadd988SPavel Labath 
2260eadd988SPavel Labath   m_out_stream.PutSLEB128(0);
22703db32b3SPavel Labath   ++m_stack_depth;
2280eadd988SPavel Labath }
2290eadd988SPavel Labath 
Visit(UnaryOpNode & unary,Node * &)2300eadd988SPavel Labath void DWARFCodegen::Visit(UnaryOpNode &unary, Node *&) {
2310eadd988SPavel Labath   Dispatch(unary.Operand());
2320eadd988SPavel Labath 
2330eadd988SPavel Labath   switch (unary.GetOpType()) {
2340eadd988SPavel Labath   case UnaryOpNode::Deref:
2350eadd988SPavel Labath     m_out_stream.PutHex8(DW_OP_deref);
2360eadd988SPavel Labath     break;
2370eadd988SPavel Labath   }
23803db32b3SPavel Labath   // Stack depth unchanged.
2390eadd988SPavel Labath }
2400eadd988SPavel Labath 
ResolveSymbols(Node * & node,llvm::function_ref<Node * (SymbolNode &)> replacer)2410eadd988SPavel Labath bool postfix::ResolveSymbols(
2420eadd988SPavel Labath     Node *&node, llvm::function_ref<Node *(SymbolNode &)> replacer) {
2430eadd988SPavel Labath   return SymbolResolver(replacer).Dispatch(node);
2440eadd988SPavel Labath }
2450eadd988SPavel Labath 
ToDWARF(Node & node,Stream & stream)2460eadd988SPavel Labath void postfix::ToDWARF(Node &node, Stream &stream) {
2470eadd988SPavel Labath   Node *ptr = &node;
2480eadd988SPavel Labath   DWARFCodegen(stream).Dispatch(ptr);
2490eadd988SPavel Labath }
250