summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Molenda <jmolenda@apple.com>2015-01-13 07:39:03 +0000
committerJason Molenda <jmolenda@apple.com>2015-01-13 07:39:03 +0000
commit30cab7eca247a6d9ed1398d35c613554cabb905a (patch)
treec41884ead7dcf0ee3d8f4a0986b3255137ad4c59
parentfcb91c19dc22f7637e0b2bc2d2008743eb384062 (diff)
Enhance the eh_frame unwind instruction augmenter so that
it will do the right thing on x86 routines with a mid-function epilogue sequence (where the unwind rules need to be reinstalled after the epilogue has completed). <rdar://problem/19417410> git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@225773 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp52
1 files changed, 46 insertions, 6 deletions
diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
index f86c56b44..fa83c19e9 100644
--- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
+++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
@@ -818,10 +818,19 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
row_updated = true;
}
- // FIXME recognize the i386 picbase setup instruction sequence,
- // 0x1f16: call 0x1f1b ; main + 11 at /private/tmp/a.c:3
- // 0x1f1b: popl %eax
- // and record the temporary stack movements if the CFA is not expressed in terms of ebp.
+ // call next instruction
+ // call 0
+ // => pop %ebx
+ // This is used in i386 programs to get the PIC base address for finding global data
+ else if (call_next_insn_pattern_p ())
+ {
+ current_sp_bytes_offset_from_cfa += m_wordsize;
+ if (row->GetCFARegister() == m_lldb_sp_regnum)
+ {
+ row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row_updated = true;
+ }
+ }
if (row_updated)
{
@@ -884,12 +893,20 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
if (cfa_reg != m_lldb_sp_regnum || first_row->GetCFAOffset() != m_wordsize)
return false;
+ UnwindPlan::RowSP original_last_row = unwind_plan.GetRowForFunctionOffset (-1);
+
Target *target = m_exe_ctx.GetTargetPtr();
m_cur_insn = func.GetBaseAddress();
uint64_t offset = 0;
int row_id = 1;
bool unwind_plan_updated = false;
UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row));
+
+ // After a mid-function epilogue we will need to re-insert the original unwind rules
+ // so unwinds work for the remainder of the function. These aren't common with clang/gcc
+ // on x86 but it is possible.
+ bool reinstate_unwind_state = false;
+
while (func.ContainsFileAddress (m_cur_insn))
{
int insn_len;
@@ -912,6 +929,23 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
offset += insn_len;
m_cur_insn.SetOffset(m_cur_insn.GetOffset() + insn_len);
+ if (reinstate_unwind_state)
+ {
+ // that was the last instruction of this function
+ if (func.ContainsFileAddress (m_cur_insn) == false)
+ continue;
+
+ UnwindPlan::RowSP new_row(new UnwindPlan::Row());
+ *new_row = *original_last_row;
+ new_row->SetOffset (offset);
+ unwind_plan.AppendRow (new_row);
+ row.reset (new UnwindPlan::Row());
+ *row = *new_row;
+ reinstate_unwind_state = false;
+ unwind_plan_updated = true;
+ continue;
+ }
+
// If we already have one row for this instruction, we can continue.
while (row_id < unwind_plan.GetRowCount()
&& unwind_plan.GetRowAtIndex (row_id)->GetOffset() <= offset)
@@ -1016,6 +1050,11 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
unwind_plan_updated = true;
continue;
}
+ if (ret_pattern_p ())
+ {
+ reinstate_unwind_state = true;
+ continue;
+ }
}
else if (cfa_reg == m_lldb_fp_regnum)
{
@@ -1037,6 +1076,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
unwind_plan_updated = true;
+ reinstate_unwind_state = true;
continue;
}
}
@@ -1260,8 +1300,8 @@ UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& t
}
- // It looks like the prologue is described. Now check to see if the epilogue has the same
- // unwind state.
+ // It looks like the prologue is described.
+ // Is the epilogue described? If it is, no need to do any augmentation.
if (first_row != last_row && first_row->GetOffset() != last_row->GetOffset())
{