labath created this revision. labath added reviewers: amccarth, clayborg, aleksandr.urakov. Herald added a subscriber: aprantl.
This node represents the "Canonical Frame Address" of the current frame, and is used by various DWARF expressions to express adresses of various objects relative to the frame. The motivation for this is the ability to translate breakpad register unwind rules (strings like: ".cfa 8 - ^") back into dwarf. This patch introduces the new node type, and teaches the dwarf codegen how to handle it. A slight complication here is that the value of CFA is provided differently depending on the context where the dwarf expression is used. In unwind rules, it is made available implicitly via the initial dwarf stack. It variable location expressions, it needs to be referred to explicitly via a special opcode. As currently, the only usage of this is in the unwind rules, I made the dwarf generator use this convention, but this can be easily made configurable, if necessary. The implementation does this via keeping track of the DWARF stack depth an any given point, and then copying the CFA value from the bottom of the stack via the DW_OP_pick opcode. This could be made more efficient for simple expressions, but here I chose to start with the most general implementation possible. https://reviews.llvm.org/D61183 Files: include/lldb/Symbol/PostfixExpression.h source/Symbol/PostfixExpression.cpp unittests/Symbol/PostfixExpressionTest.cpp
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<CFANode>(alloc); + uint32_t num; if (to_integer(symbol.GetName().drop_front(), num)) return MakeNode<RegisterNode>(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 +")); 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: 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<BinaryOpNode>(*node), node); + case Node::CFA: + return Visit(llvm::cast<CFANode>(*node), node); case Node::Integer: return Visit(llvm::cast<IntegerNode>(*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
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits