Some eh_frame unwind instructions will define a return address register;

when you want to find the caller's saved pc, you look up the return address
register and use that.  On arm, for instance, this would be the contents of
the link register (lr).

If the eh_frame CIE defines an RA, record that fact in the UnwindPlan.

When we're finding a saved register, if it's the pc, lok for the location
of the return address register instead.

<rdar://problem/12062310> 

llvm-svn: 162167
This commit is contained in:
Jason Molenda 2012-08-18 06:53:34 +00:00
parent 0128f9bad7
commit 8eba46c68a
4 changed files with 50 additions and 13 deletions

View File

@ -75,7 +75,7 @@ private:
lldb_private::UnwindPlan::Row initial_row;
CIE(dw_offset_t offset) : cie_offset(offset), version (-1), code_align (0),
data_align (0), return_addr_reg_num (-1), inst_offset (0),
data_align (0), return_addr_reg_num (LLDB_INVALID_REGNUM), inst_offset (0),
inst_length (0), ptr_encoding (0), initial_row() {}
};

View File

@ -348,6 +348,7 @@ public:
m_row_list (),
m_plan_valid_address_range (),
m_register_kind (reg_kind),
m_return_addr_register (LLDB_INVALID_REGNUM),
m_source_name ()
{
}
@ -381,6 +382,18 @@ public:
m_register_kind = kind;
}
void
SetReturnAddressRegister (uint32_t regnum)
{
m_return_addr_register = regnum;
}
uint32_t
GetReturnAddressRegister (void)
{
return m_return_addr_register;
}
uint32_t
GetInitialCFARegister () const
{
@ -441,7 +454,9 @@ private:
collection m_row_list;
AddressRange m_plan_valid_address_range;
lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers are in terms of - will need to be
// translated to lldb native reg nums at unwind time
// translated to lldb native reg nums at unwind time
uint32_t m_return_addr_register; // The register that has the return address for the caller frame
// e.g. the lr on arm
lldb_private::ConstString m_source_name; // for logging, where this UnwindPlan originated from
}; // class UnwindPlan

View File

@ -1034,6 +1034,12 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
return true;
}
uint32_t pc_regnum;
if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, eRegisterKindLLDB, pc_regnum))
{
pc_regnum = LLDB_INVALID_REGNUM;
}
// Look through the available UnwindPlans for the register location.
UnwindPlan::Row::RegisterLocation unwindplan_regloc;
@ -1078,20 +1084,35 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind ();
uint32_t row_regnum;
if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
// If we're fetching the saved pc and this UnwindPlan defines a ReturnAddress register (e.g. lr on arm),
// look for the return address register number in the UnwindPlan's row.
if (lldb_regnum == pc_regnum && m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM)
{
if (log)
row_regnum = m_full_unwind_plan_sp->GetReturnAddressRegister();
if (log)
{
log->Printf("%*sFrame %u requested caller's saved PC but this UnwindPlan uses a RA reg; getting reg %d instead",
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, row_regnum);
}
}
else
{
if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
{
if (unwindplan_registerkind == eRegisterKindGeneric)
log->Printf("%*sFrame %u could not convert lldb regnum %d into eRegisterKindGeneric reg numbering scheme",
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
lldb_regnum);
else
log->Printf("%*sFrame %u could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
lldb_regnum, (int) unwindplan_registerkind);
if (log)
{
if (unwindplan_registerkind == eRegisterKindGeneric)
log->Printf("%*sFrame %u could not convert lldb regnum %d into eRegisterKindGeneric reg numbering scheme",
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
lldb_regnum);
else
log->Printf("%*sFrame %u could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
lldb_regnum, (int) unwindplan_registerkind);
}
return false;
}
return false;
}
if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))

View File

@ -407,6 +407,7 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t offset, Address startaddr, Unwi
UnwindPlan::RowSP row(cie_initial_row);
unwind_plan.SetRegisterKind (m_reg_kind);
unwind_plan.SetReturnAddressRegister (cie->return_addr_reg_num);
UnwindPlan::Row::RegisterLocation reg_location;
while (m_cfi_data.ValidOffset(offset) && offset < end_offset)