Index: include/lldb/Symbol/PostfixExpression.h =================================================================== --- include/lldb/Symbol/PostfixExpression.h +++ include/lldb/Symbol/PostfixExpression.h @@ -29,6 +29,7 @@ public: enum Kind { BinaryOp, + CFA, Integer, Register, Symbol, @@ -73,6 +74,14 @@ Node *m_right; }; +/// A node representing the canonical frame address. +class CFANode: public Node { +public: + CFANode() : Node(CFA) {} + + static bool classof(const Node *node) { return node->GetKind() == CFA; } +}; + /// A node representing an integer literal. class IntegerNode : public Node { public: @@ -153,6 +162,7 @@ virtual ~Visitor() = default; virtual ResultT Visit(BinaryOpNode &binary, Node *&ref) = 0; + virtual ResultT Visit(CFANode &cfa, Node *&ref) = 0; virtual ResultT Visit(IntegerNode &integer, Node *&) = 0; virtual ResultT Visit(RegisterNode ®, Node *&) = 0; virtual ResultT Visit(SymbolNode &symbol, Node *&ref) = 0; @@ -164,6 +174,8 @@ switch (node->GetKind()) { case Node::BinaryOp: return Visit(llvm::cast(*node), node); + case Node::CFA: + return Visit(llvm::cast(*node), node); case Node::Integer: return Visit(llvm::cast(*node), node); case Node::Register: @@ -200,7 +212,12 @@ Node *Parse(llvm::StringRef expr, llvm::BumpPtrAllocator &alloc); /// Serialize the given expression tree as DWARF. The result is written into the -/// given stream. The AST should not contain any SymbolNodes. +/// given stream. The AST should not contain any SymbolNodes. The value for +/// CFANodes is assumed to be provided via the top value of the initial +/// evaluation stack. +/// PS: If the CFANodes are ever used in variable location lists, then this will +/// need to be made configurable (as there, we should reference CFA values via +/// DW_OP_call_frame_cfa). void ToDWARF(Node &node, Stream &stream); } // namespace postfix Index: source/Symbol/PostfixExpression.cpp =================================================================== --- source/Symbol/PostfixExpression.cpp +++ source/Symbol/PostfixExpression.cpp @@ -96,6 +96,7 @@ return Dispatch(binary.Left()) && Dispatch(binary.Right()); } + bool Visit(CFANode &cfa, Node *&) override { return true; } bool Visit(IntegerNode &integer, Node *&) override { return true; } bool Visit(RegisterNode ®, Node *&) override { return true; } @@ -125,9 +126,12 @@ private: void Visit(BinaryOpNode &binary, Node *&); + void Visit(CFANode &cfa, Node *&); + void Visit(IntegerNode &integer, Node *&) { m_out_stream.PutHex8(DW_OP_constu); m_out_stream.PutULEB128(integer.GetValue()); + ++m_stack_depth; } void Visit(RegisterNode ®, Node *&); @@ -139,6 +143,11 @@ void Visit(UnaryOpNode &unary, Node *&); Stream &m_out_stream; + + /// The number keeping track of the virtual evaluation stack depth at the + /// given moment. We assume CFA is given via the top of the initial stack, + /// hence the initial value is 1. + size_t m_stack_depth = 1; }; } // namespace @@ -166,6 +175,16 @@ m_out_stream.PutHex8(DW_OP_and); break; } + --m_stack_depth; // Two pops, one push. +} + +void DWARFCodegen::Visit(CFANode &, Node *&) { + // We never go below the initial stack, so we can pick the initial CFA value + // from the bottom of the stack at any moment. + assert(m_stack_depth >= 1); + m_out_stream.PutHex8(DW_OP_pick); + m_out_stream.PutHex8(m_stack_depth - 1); + ++m_stack_depth; } void DWARFCodegen::Visit(RegisterNode ®, Node *&) { @@ -179,6 +198,7 @@ m_out_stream.PutHex8(DW_OP_breg0 + reg_num); m_out_stream.PutSLEB128(0); + ++m_stack_depth; } void DWARFCodegen::Visit(UnaryOpNode &unary, Node *&) { @@ -189,6 +209,7 @@ m_out_stream.PutHex8(DW_OP_deref); break; } + // Stack depth unchanged. } bool postfix::ResolveSymbols( Index: unittests/Symbol/PostfixExpressionTest.cpp =================================================================== --- unittests/Symbol/PostfixExpressionTest.cpp +++ unittests/Symbol/PostfixExpressionTest.cpp @@ -44,6 +44,8 @@ Dispatch(binary.Left()), Dispatch(binary.Right())); } + std::string Visit(CFANode &, Node *&) override { return "CFA"; } + std::string Visit(IntegerNode &integer, Node *&) override { return llvm::formatv("int({0})", integer.GetValue()); } @@ -105,6 +107,9 @@ if (!ast) return "Parse failed."; if (!ResolveSymbols(ast, [&](SymbolNode &symbol) -> Node * { + if (symbol.GetName() == "CFA") + return MakeNode(alloc); + uint32_t num; if (to_integer(symbol.GetName().drop_front(), num)) return MakeNode(alloc, num); @@ -138,6 +143,17 @@ EXPECT_EQ("DW_OP_bregx 65 0", ParseAndGenerateDWARF("R65")); + EXPECT_EQ("DW_OP_pick 0x00", ParseAndGenerateDWARF("CFA")); + + EXPECT_EQ("DW_OP_pick 0x00, DW_OP_pick 0x01, DW_OP_plus ", + ParseAndGenerateDWARF("CFA CFA +")); + + EXPECT_EQ("DW_OP_breg1 +0, DW_OP_pick 0x01, DW_OP_plus ", + ParseAndGenerateDWARF("R1 CFA +")); + + EXPECT_EQ("DW_OP_constu 0x1, DW_OP_pick 0x01, DW_OP_deref , DW_OP_plus ", + ParseAndGenerateDWARF("1 CFA ^ +")); + EXPECT_EQ("DW_OP_constu 0x4, DW_OP_constu 0x5, DW_OP_plus ", ParseAndGenerateDWARF("4 5 +"));