Hi jasonmolenda,

PowerPC handles the stack chain with the current stack pointer being a pointer
to the backchain (CFA).  LLDB currently has no way of handling this, so this
adds a "CFA is dereferenced from a register" type.

Discussed with Jason Molenda, who also provided the initial patch for this.

http://reviews.llvm.org/D6182

Files:
  include/lldb/Symbol/UnwindPlan.h
  source/Plugins/Process/Utility/RegisterContextLLDB.cpp
  source/Plugins/Process/Utility/RegisterContextLLDB.h
  source/Symbol/UnwindPlan.cpp
Index: include/lldb/Symbol/UnwindPlan.h
===================================================================
--- include/lldb/Symbol/UnwindPlan.h
+++ include/lldb/Symbol/UnwindPlan.h
@@ -58,13 +58,13 @@
                     atDWARFExpression,  // reg = deref(eval(dwarf_expr))
                     isDWARFExpression   // reg = eval(dwarf_expr)
                 };
-    
+
             RegisterLocation() : 
                 m_type(unspecified), 
                 m_location() 
             {
             }
-    
+
             bool
             operator == (const RegisterLocation& rhs) const;
     
@@ -242,8 +242,10 @@
     
         Row (const UnwindPlan::Row& rhs) : 
             m_offset             (rhs.m_offset),
+            m_cfa_type           (rhs.m_cfa_type),
             m_cfa_reg_num        (rhs.m_cfa_reg_num),
             m_cfa_offset         (rhs.m_cfa_offset),
+            m_cfa_deref_reg_num  (rhs.m_cfa_deref_reg_num),
             m_register_locations (rhs.m_register_locations)
         {
         }
@@ -275,12 +277,64 @@
             m_offset += offset;
         }
 
+        // How we can reconstruct the CFA address for this stack frame, at this location
+        enum CFAType
+        {
+            CFAIsRegisterPlusOffset,   // the CFA value in a register plus (or minus) an offset
+            CFAIsRegisterDereferenced  // the address in a register is dereferenced to get CFA value
+        };
+
+        CFAType
+        GetCFAType () const
+        {
+            return m_cfa_type;
+        }
+
+        void
+        SetCFAType (CFAType cfa_type)
+        {
+            m_cfa_type = cfa_type;
+        }
+
+        // This should be used when GetCFAType() returns CFAIsRegisterPlusOffset
         uint32_t
         GetCFARegister () const
         {
             return m_cfa_reg_num;
         }
         
+        // This should be used when GetCFAType() is set to CFAIsRegisterPlusOffset
+        void
+        SetCFARegister (uint32_t reg_num);
+
+        // This should be used when GetCFAType() returns CFAIsRegisterPlusOffset
+        int32_t
+        GetCFAOffset () const
+        {
+            return m_cfa_offset;
+        }
+
+        // This should be used when GetCFAType() is set to CFAIsRegisterPlusOffset
+        void
+        SetCFAOffset (int32_t offset)
+        {
+            m_cfa_offset = offset;
+        }
+
+        // This should be used when GetCFAType() returns CFAIsRegisterDereferenced
+        uint32_t
+        GetCFARegisterNumberToDereference () const
+        {
+            return m_cfa_deref_reg_num;
+        }
+
+        // This should be used when GetCFAType() is set to CFAIsRegisterDereferenced
+        void
+        SetCFARegisterNumberToDereference (uint32_t reg_num) 
+        {
+            m_cfa_deref_reg_num = reg_num;
+        }
+
         bool
         SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num, 
                                               int32_t offset, 
@@ -309,23 +363,6 @@
         SetRegisterLocationToSame (uint32_t reg_num, 
                                    bool must_replace);
 
-
-
-        void
-        SetCFARegister (uint32_t reg_num);
-
-        int32_t
-        GetCFAOffset () const
-        {
-            return m_cfa_offset;
-        }
-
-        void
-        SetCFAOffset (int32_t offset)
-        {
-            m_cfa_offset = offset;
-        }
-
         void
         Clear ();
 
@@ -335,8 +372,16 @@
     protected:
         typedef std::map<uint32_t, RegisterLocation> collection;
         lldb::addr_t m_offset;      // Offset into the function for this row
+
+        CFAType m_cfa_type;
+
+        // If m_cfa_type == CFAIsRegisterPlusOffset, the following ivars are used
         uint32_t m_cfa_reg_num;     // The Call Frame Address register number
         int32_t  m_cfa_offset;      // The offset from the CFA for this row
+
+        // if m_cfa_type == CFAIsRegisterDereferenced, the following is used
+        uint32_t m_cfa_deref_reg_num;
+
         collection m_register_locations;
     }; // class Row
 
Index: source/Plugins/Process/Utility/RegisterContextLLDB.cpp
===================================================================
--- source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -240,7 +240,7 @@
 
 
     addr_t cfa_regval = LLDB_INVALID_ADDRESS;
-    if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
+    if (!ReadCFAValueForRow (row_register_kind, active_row, cfa_regval))
     {
         UnwindLogMsg ("could not read CFA register for this frame.");
         m_frame_type = eNotAValidFrame;
@@ -370,7 +370,7 @@
             {
                 uint32_t cfa_regnum = row->GetCFARegister();
                 int cfa_offset = row->GetCFAOffset();
-                if (!ReadGPRValue (row_register_kind, cfa_regnum, cfa_regval))
+                if (!ReadCFAValueForRow (row_register_kind, row, cfa_regval))
                 {
                     UnwindLogMsg ("failed to get cfa value");
                     if (m_frame_type != eSkipFrame)   // don't override eSkipFrame
@@ -565,7 +565,7 @@
     }
 
     addr_t cfa_regval = LLDB_INVALID_ADDRESS;
-    if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
+    if (!ReadCFAValueForRow (row_register_kind, active_row, cfa_regval))
     {
         UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister());
         m_frame_type = eNotAValidFrame;
@@ -1419,8 +1419,9 @@
     {
         m_registers.clear();
         m_full_unwind_plan_sp = m_fallback_unwind_plan_sp;
+        uint32_t cfa_regnum = active_row->GetCFARegister();
         addr_t cfa_regval = LLDB_INVALID_ADDRESS;
-        if (ReadGPRValue (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval))
+        if (ReadCFAValueForRow(m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, cfa_regval))
         {
             m_cfa = cfa_regval + active_row->GetCFAOffset ();
         }
@@ -1434,6 +1435,37 @@
     return true;
 }
 
+bool
+RegisterContextLLDB::ReadCFAValueForRow (lldb::RegisterKind row_register_kind,
+                                         const UnwindPlan::RowSP &row,
+                                         addr_t &value)
+{
+    uint32_t cfa_regnum = row->GetCFARegister();
+    RegisterValue reg_value;
+    addr_t tmp;
+
+    value = LLDB_INVALID_ADDRESS;
+
+    if (ReadGPRValue (row_register_kind, cfa_regnum, value))
+    {
+        if (row->GetCFAType() == UnwindPlan::Row::CFAIsRegisterDereferenced)
+        {
+            tmp = value;
+            const RegisterInfo *reg_info = GetRegisterInfoAtIndex(cfa_regnum);
+            RegisterValue reg_value;
+            Error error = ReadRegisterValueFromMemory(reg_info,
+                                                      value,
+                                                      reg_info->byte_size,
+                                                      reg_value);
+            value = reg_value.GetAsUInt64();
+            UnwindLogMsg("dereferenced address: %p yields: %lx\n", tmp, value);
+            return error.Success();
+        }
+        return true;
+    }
+    return false;
+}
+
 // Retrieve a general purpose register value for THIS frame, as saved by the NEXT frame, i.e. the frame that
 // this frame called.  e.g.
 //
Index: source/Plugins/Process/Utility/RegisterContextLLDB.h
===================================================================
--- source/Plugins/Process/Utility/RegisterContextLLDB.h
+++ source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -186,6 +186,10 @@
     bool
     ReadGPRValue (lldb::RegisterKind register_kind, uint32_t regnum, lldb::addr_t &value);
 
+    // Get the CFA register for a given frame.
+    bool
+    ReadCFAValueForRow (lldb::RegisterKind register_kind, const UnwindPlan::RowSP &row, lldb::addr_t &value);
+
     lldb::UnwindPlanSP
     GetFastUnwindPlanForFrame ();
 
Index: source/Symbol/UnwindPlan.cpp
===================================================================
--- source/Symbol/UnwindPlan.cpp
+++ source/Symbol/UnwindPlan.cpp
@@ -21,30 +21,40 @@
 bool
 UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const
 {
+    bool is_match = true;
+
+    if (m_type != rhs.m_type)
+        is_match = false;
+
     if (m_type == rhs.m_type)
     {
         switch (m_type)
         {
             case unspecified:
             case undefined:
             case same:
-                return true;
+                break;
                 
             case atCFAPlusOffset:
             case isCFAPlusOffset:
-                return m_location.offset == rhs.m_location.offset;
+                if (m_location.offset != rhs.m_location.offset)
+                    is_match = false;
+                break;
 
             case inOtherRegister:
-                return m_location.reg_num == rhs.m_location.reg_num;
+                if (m_location.reg_num != rhs.m_location.reg_num)
+                    is_match = false;
+                break;
             
             case atDWARFExpression:
             case isDWARFExpression:
                 if (m_location.expr.length == rhs.m_location.expr.length)
-                    return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length);
+                    if (memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length) != 0)
+                        is_match = false;
                 break;
         }
     }
-    return false;
+    return is_match;
 }
 
 // This function doesn't copy the dwarf expression bytes; they must remain in allocated
@@ -153,9 +163,11 @@
 void
 UnwindPlan::Row::Clear ()
 {
+    m_cfa_type = CFAIsRegisterPlusOffset;
     m_offset = 0;
     m_cfa_reg_num = LLDB_INVALID_REGNUM;
     m_cfa_offset = 0;
+    m_cfa_deref_reg_num = LLDB_INVALID_REGNUM;
     m_register_locations.clear();
 }
 
@@ -189,10 +201,12 @@
 }
 
 UnwindPlan::Row::Row() :
-    m_offset(0),
-    m_cfa_reg_num(LLDB_INVALID_REGNUM),
-    m_cfa_offset(0),
-    m_register_locations()
+    m_offset (0),
+    m_cfa_type (CFAIsRegisterPlusOffset),
+    m_cfa_reg_num (LLDB_INVALID_REGNUM),
+    m_cfa_offset (0),
+    m_cfa_deref_reg_num (LLDB_INVALID_REGNUM),
+    m_register_locations ()
 {
 }
 
@@ -301,6 +315,23 @@
 {
     if (m_offset != rhs.m_offset || m_cfa_reg_num != rhs.m_cfa_reg_num || m_cfa_offset != rhs.m_cfa_offset)
         return false;
+
+    if (m_cfa_type != rhs.m_cfa_type)
+        return false;
+
+    if (m_cfa_type == CFAIsRegisterPlusOffset)
+    {
+        if (m_cfa_reg_num != rhs.m_cfa_reg_num)
+            return false;
+        if (m_cfa_offset != rhs.m_cfa_offset)
+            return false;
+    }
+    if (m_cfa_type == CFAIsRegisterDereferenced)
+    {
+        if (m_cfa_deref_reg_num != rhs.m_cfa_deref_reg_num)
+            return false;
+    }
+
     return m_register_locations == rhs.m_register_locations;
 }
 
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits

Reply via email to