Index: lldb/trunk/include/lldb/Symbol/PostfixExpression.h =================================================================== --- lldb/trunk/include/lldb/Symbol/PostfixExpression.h +++ lldb/trunk/include/lldb/Symbol/PostfixExpression.h @@ -29,6 +29,7 @@ public: enum Kind { BinaryOp, + InitialValue, Integer, Register, Symbol, @@ -73,6 +74,16 @@ Node *m_right; }; +/// A node representing the canonical frame address. +class InitialValueNode: public Node { +public: + InitialValueNode() : Node(InitialValue) {} + + static bool classof(const Node *node) { + return node->GetKind() == InitialValue; + } +}; + /// A node representing an integer literal. class IntegerNode : public Node { public: @@ -153,6 +164,7 @@ virtual ~Visitor() = default; virtual ResultT Visit(BinaryOpNode &binary, Node *&ref) = 0; + virtual ResultT Visit(InitialValueNode &val, 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 +176,8 @@ switch (node->GetKind()) { case Node::BinaryOp: return Visit(llvm::cast(*node), node); + case Node::InitialValue: + return Visit(llvm::cast(*node), node); case Node::Integer: return Visit(llvm::cast(*node), node); case Node::Register: @@ -200,7 +214,10 @@ 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. If the expression +/// contains InitialValueNodes, the generated expression will assume that their +/// value will be provided as the top value of the initial evaluation stack (as +/// is the case with the CFA value in register eh_unwind rules). void ToDWARF(Node &node, Stream &stream); } // namespace postfix Index: lldb/trunk/source/Symbol/PostfixExpression.cpp =================================================================== --- lldb/trunk/source/Symbol/PostfixExpression.cpp +++ lldb/trunk/source/Symbol/PostfixExpression.cpp @@ -96,8 +96,9 @@ return Dispatch(binary.Left()) && Dispatch(binary.Right()); } - bool Visit(IntegerNode &integer, Node *&) override { return true; } - bool Visit(RegisterNode ®, Node *&) override { return true; } + bool Visit(InitialValueNode &, Node *&) override { return true; } + bool Visit(IntegerNode &, Node *&) override { return true; } + bool Visit(RegisterNode &, Node *&) override { return true; } bool Visit(SymbolNode &symbol, Node *&ref) override { if (Node *replacement = m_replacer(symbol)) { @@ -125,9 +126,12 @@ private: void Visit(BinaryOpNode &binary, Node *&); + void Visit(InitialValueNode &val, 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,15 @@ void Visit(UnaryOpNode &unary, Node *&); Stream &m_out_stream; + + /// The number keeping track of the evaluation stack depth at any given + /// moment. Used for implementing InitialValueNodes. We start with + /// m_stack_depth = 1, assuming that the initial value is already on the + /// stack. This initial value will be the value of all InitialValueNodes. If + /// the expression does not contain InitialValueNodes, then m_stack_depth is + /// not used, and the generated expression will run correctly even without an + /// initial value. + size_t m_stack_depth = 1; }; } // namespace @@ -166,6 +179,16 @@ m_out_stream.PutHex8(DW_OP_and); break; } + --m_stack_depth; // Two pops, one push. +} + +void DWARFCodegen::Visit(InitialValueNode &, Node *&) { + // We never go below the initial stack, so we can pick the initial 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 +202,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 +213,7 @@ m_out_stream.PutHex8(DW_OP_deref); break; } + // Stack depth unchanged. } bool postfix::ResolveSymbols( Index: lldb/trunk/unittests/Symbol/PostfixExpressionTest.cpp =================================================================== --- lldb/trunk/unittests/Symbol/PostfixExpressionTest.cpp +++ lldb/trunk/unittests/Symbol/PostfixExpressionTest.cpp @@ -44,6 +44,8 @@ Dispatch(binary.Left()), Dispatch(binary.Right())); } + std::string Visit(InitialValueNode &, Node *&) override { return "InitialValue"; } + 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() == "INIT") + 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("INIT")); + + EXPECT_EQ("DW_OP_pick 0x00, DW_OP_pick 0x01, DW_OP_plus ", + ParseAndGenerateDWARF("INIT INIT +")); + + EXPECT_EQ("DW_OP_breg1 +0, DW_OP_pick 0x01, DW_OP_plus ", + ParseAndGenerateDWARF("R1 INIT +")); + + EXPECT_EQ("DW_OP_constu 0x1, DW_OP_pick 0x01, DW_OP_deref , DW_OP_plus ", + ParseAndGenerateDWARF("1 INIT ^ +")); + EXPECT_EQ("DW_OP_constu 0x4, DW_OP_constu 0x5, DW_OP_plus ", ParseAndGenerateDWARF("4 5 +"));