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 &reg, 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 &reg, 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 &reg, 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 &reg, 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

Reply via email to