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