diff options
author | Jason Molenda <jmolenda@apple.com> | 2012-10-17 00:41:14 +0000 |
---|---|---|
committer | Jason Molenda <jmolenda@apple.com> | 2012-10-17 00:41:14 +0000 |
commit | 5c1ac4ea7266fb136f0381e9d4ce47c1e93e6ae7 (patch) | |
tree | 9fe607a3e60b8709fce892ee1fdcd451362832d3 | |
parent | 9272407c3977fe51a03fa546eda251da696874f5 (diff) | |
download | bcm5719-llvm-5c1ac4ea7266fb136f0381e9d4ce47c1e93e6ae7.tar.gz bcm5719-llvm-5c1ac4ea7266fb136f0381e9d4ce47c1e93e6ae7.zip |
Add code to UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly
to handle an addition class of early-return instructions we find in arm code:
tail-call optimziation returns where we restore the register state from the
function entry and jump directly (not branch & link) to another function --
when that other function returns, it will return to our caller.
Previously this mid-function epilogue sequence was not being correctly detected.
We would not re-instate the prologue setup instructions for the rest of the function
so unwinds would break from that point until the end of the function.
<rdar://problem/12502597>
llvm-svn: 166081
-rw-r--r-- | lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp | 51 | ||||
-rw-r--r-- | lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h | 2 |
2 files changed, 51 insertions, 2 deletions
diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp index 7cadcd1a6b4..ea0aec6164e 100644 --- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -109,7 +109,11 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& // use later. int instructions_since_last_prologue_insn = 0; // # of insns since last CFI was update bool prologue_complete = false; // true if we have finished prologue setup + bool reinstate_prologue_next_instruction = false; // Next iteration, re-install the prologue row of CFI + + bool last_instruction_restored_return_addr_reg = false; // re-install the prologue row of CFI if the next instruction is a branch immediate + UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI // cache the pc register number (in whatever register numbering this UnwindPlan uses) for @@ -118,7 +122,17 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& RegisterInfo pc_reg_info; if (m_inst_emulator_ap->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info)) pc_reg_num = pc_reg_info.kinds[unwind_plan.GetRegisterKind()]; + else + pc_reg_num = LLDB_INVALID_REGNUM; + // cache the return address register number (in whatever register numbering this UnwindPlan uses) for + // quick reference during instruction parsing. + uint32_t ra_reg_num = LLDB_INVALID_REGNUM; + RegisterInfo ra_reg_info; + if (m_inst_emulator_ap->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, ra_reg_info)) + ra_reg_num = ra_reg_info.kinds[unwind_plan.GetRegisterKind()]; + else + ra_reg_num = LLDB_INVALID_REGNUM; for (size_t idx=0; idx<num_instructions; ++idx) { @@ -159,6 +173,7 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& // If there are any instructions past this, there must have been flow control over this // epilogue so we'll reinstate the original prologue setup instructions. UnwindPlan::Row::RegisterLocation pc_regloc; + UnwindPlan::Row::RegisterLocation ra_regloc; if (prologue_complete && pc_reg_num != LLDB_INVALID_REGNUM && m_curr_row->GetRegisterInfo (pc_reg_num, pc_regloc) @@ -168,13 +183,25 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- pc is <same>, restore prologue instructions."); reinstate_prologue_next_instruction = true; } + else if (prologue_complete + && ra_reg_num != LLDB_INVALID_REGNUM + && m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc) + && ra_regloc.IsSame()) + { + if (log && log->GetVerbose()) + log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- lr is <same>, restore prologue instruction if the next instruction is a branch immediate."); + last_instruction_restored_return_addr_reg = true; + } } else { // If the previous instruction was a return-to-caller (epilogue), and we're still executing // instructions in this function, there must be a code path that jumps over that epilogue. + // Also detect the case where we epilogue & branch imm to another function (tail-call opt) + // instead of a normal pop lr-into-pc exit. // Reinstate the frame setup from the prologue. - if (reinstate_prologue_next_instruction) + if (reinstate_prologue_next_instruction + || (m_curr_insn_is_branch_immediate && last_instruction_restored_return_addr_reg)) { if (log && log->GetVerbose()) log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- Reinstating prologue instruction set"); @@ -189,8 +216,20 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& m_curr_row.reset(newrow); reinstate_prologue_next_instruction = false; + last_instruction_restored_return_addr_reg = false; + m_curr_insn_is_branch_immediate = false; } + // clear both of these if either one wasn't set + if (last_instruction_restored_return_addr_reg) + { + last_instruction_restored_return_addr_reg = false; + } + if (m_curr_insn_is_branch_immediate) + { + m_curr_insn_is_branch_immediate = false; + } + // If we haven't seen any prologue instructions for a while (4 instructions in a row), // the function prologue has probably completed. Save a copy of that Row. if (prologue_complete == false && instructions_since_last_prologue_insn++ > 3) @@ -544,7 +583,6 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction, case EmulateInstruction::eContextAdjustPC: case EmulateInstruction::eContextRegisterStore: case EmulateInstruction::eContextRegisterLoad: - case EmulateInstruction::eContextRelativeBranchImmediate: case EmulateInstruction::eContextAbsoluteBranchRegister: case EmulateInstruction::eContextSupervisorCall: case EmulateInstruction::eContextTableBranchReadMemory: @@ -568,6 +606,15 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction, // } break; + case EmulateInstruction::eContextRelativeBranchImmediate: + { + + { + m_curr_insn_is_branch_immediate = true; + } + } + break; + case EmulateInstruction::eContextPopRegisterOffStack: { const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h index 374bd17f2d5..57a85726400 100644 --- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h +++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h @@ -135,6 +135,7 @@ private: m_unwind_plan_ptr (NULL), m_curr_row (), m_curr_row_modified (false), + m_curr_insn_is_branch_immediate (false), m_cfa_reg_info (), m_fp_is_cfa (false), m_register_values (), @@ -164,6 +165,7 @@ private: lldb_private::UnwindPlan* m_unwind_plan_ptr; lldb_private::UnwindPlan::RowSP m_curr_row; bool m_curr_row_modified; + bool m_curr_insn_is_branch_immediate; typedef std::map<uint64_t, uint64_t> PushedRegisterToAddrMap; uint64_t m_initial_sp; lldb_private::RegisterInfo m_cfa_reg_info; |