Add an additional check to UnwindAssembly_x86::AugmentUnwindPlanFromCallSite

which will verify if the eh_frame instructions include details about
the prologue or not.  Both clang and gcc include prologue instructions
but there's no requirement for them to do so -- and I'm sure we'll
have to interoperate with a compiler that doesn't generate prologue
info at some point.

I don't have any compilers that omit the prologue instructions so the
testing was of the "makre sure augmented unwind info is still created".
With an eh_frame without prologue, this code should reject the 
augmentation scheme altogether and we should fall back to using assembly
instruction profiling.

llvm-svn: 225771
This commit is contained in:
Jason Molenda 2015-01-13 06:07:07 +00:00
parent 34549b8f75
commit 91805e6f56
3 changed files with 45 additions and 17 deletions

View File

@ -38,6 +38,9 @@ public:
bool bool
operator == (RegisterNumber &rhs); operator == (RegisterNumber &rhs);
bool
operator != (RegisterNumber &rhs);
bool bool
IsValid () const; IsValid () const;

View File

@ -1229,16 +1229,42 @@ UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& t
UnwindPlan::RowSP first_row = unwind_plan.GetRowForFunctionOffset (0); UnwindPlan::RowSP first_row = unwind_plan.GetRowForFunctionOffset (0);
UnwindPlan::RowSP last_row = unwind_plan.GetRowForFunctionOffset (-1); UnwindPlan::RowSP last_row = unwind_plan.GetRowForFunctionOffset (-1);
// If the UnwindPlan correctly describes the prologue and the epilogue, then int wordsize = 8;
// we shouldn't do any augmentation (and risk messing up correct unwind instructions) ProcessSP process_sp (thread.GetProcess());
if (process_sp)
{
wordsize = process_sp->GetTarget().GetArchitecture().GetAddressByteSize();
}
// See if the first row (which should be the register state on function entry) RegisterNumber sp_regnum (thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
// and the last row (which should be the register state on function exit) match. RegisterNumber pc_regnum (thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
// Does this UnwindPlan describe the prologue? I want to see that the CFA is set
// in terms of the stack pointer plus an offset, and I want to see that rip is
// retrieved at the CFA-wordsize.
// If there is no description of the prologue, don't try to augment this eh_frame
// unwinder code, fall back to assembly parsing instead.
if (first_row->GetCFAType() != UnwindPlan::Row::CFAType::CFAIsRegisterPlusOffset
|| RegisterNumber (thread, unwind_plan.GetRegisterKind(), first_row->GetCFARegister()) != sp_regnum
|| first_row->GetCFAOffset() != wordsize)
{
return false;
}
UnwindPlan::Row::RegisterLocation first_row_pc_loc;
if (first_row->GetRegisterInfo (pc_regnum.GetAsKind (unwind_plan.GetRegisterKind()), first_row_pc_loc) == false
|| first_row_pc_loc.IsAtCFAPlusOffset() == false
|| first_row_pc_loc.GetOffset() != -wordsize)
{
return false;
}
// It looks like the prologue is described. Now check to see if the epilogue has the same
// unwind state.
if (first_row != last_row && first_row->GetOffset() != last_row->GetOffset()) if (first_row != last_row && first_row->GetOffset() != last_row->GetOffset())
{ {
RegisterNumber sp_regnum (thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
// The first & last row have the same CFA register // The first & last row have the same CFA register
// and the same CFA offset value // and the same CFA offset value
// and the CFA register is esp/rsp (the stack pointer). // and the CFA register is esp/rsp (the stack pointer).
@ -1246,23 +1272,16 @@ UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& t
// We're checking that both of them have an unwind rule like "CFA=esp+4" or CFA+rsp+8". // We're checking that both of them have an unwind rule like "CFA=esp+4" or CFA+rsp+8".
if (first_row->GetCFAType() == last_row->GetCFAType() if (first_row->GetCFAType() == last_row->GetCFAType()
&& first_row->GetCFAType() == UnwindPlan::Row::CFAType::CFAIsRegisterPlusOffset
&& first_row->GetCFARegister() == last_row->GetCFARegister() && first_row->GetCFARegister() == last_row->GetCFARegister()
&& first_row->GetCFAOffset() == last_row->GetCFAOffset() && first_row->GetCFAOffset() == last_row->GetCFAOffset())
&& RegisterNumber (thread, unwind_plan.GetRegisterKind(), first_row->GetCFARegister()) == sp_regnum)
{ {
RegisterNumber pc_regnum (thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
// Get the register locations for eip/rip from the first & last rows. // Get the register locations for eip/rip from the first & last rows.
// Are they both CFA plus an offset? Is it the same offset? // Are they both CFA plus an offset? Is it the same offset?
UnwindPlan::Row::RegisterLocation first_row_pc_loc;
UnwindPlan::Row::RegisterLocation last_row_pc_loc; UnwindPlan::Row::RegisterLocation last_row_pc_loc;
if (first_row->GetRegisterInfo (pc_regnum.GetAsKind (unwind_plan.GetRegisterKind()), first_row_pc_loc) if (last_row->GetRegisterInfo (pc_regnum.GetAsKind (unwind_plan.GetRegisterKind()), last_row_pc_loc))
&& last_row->GetRegisterInfo (pc_regnum.GetAsKind (unwind_plan.GetRegisterKind()), last_row_pc_loc))
{ {
if (first_row_pc_loc.IsAtCFAPlusOffset() if (last_row_pc_loc.IsAtCFAPlusOffset()
&& last_row_pc_loc.IsAtCFAPlusOffset()
&& first_row_pc_loc.GetOffset() == last_row_pc_loc.GetOffset()) && first_row_pc_loc.GetOffset() == last_row_pc_loc.GetOffset())
{ {
@ -1272,7 +1291,7 @@ UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& t
// If so, we have an UnwindPlan that already describes the epilogue and we don't need // If so, we have an UnwindPlan that already describes the epilogue and we don't need
// to modify it at all. // to modify it at all.
if (first_row_pc_loc.GetOffset() == -4 || first_row_pc_loc.GetOffset() == -8) if (first_row_pc_loc.GetOffset() == -wordsize)
{ {
do_augment_unwindplan = false; do_augment_unwindplan = false;
} }

View File

@ -100,6 +100,12 @@ RegisterNumber::operator == (RegisterNumber &rhs)
return false; return false;
} }
bool
RegisterNumber::operator != (RegisterNumber &rhs)
{
return !(*this == rhs);
}
bool bool
RegisterNumber::IsValid () const RegisterNumber::IsValid () const
{ {