[Lldb-commits] [lldb] r166081 - in /lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation: UnwindAssemblyInstEmulation.cpp UnwindAssemblyInstEmulation.h

Jason Molenda jmolenda at apple.com
Tue Oct 16 17:41:14 PDT 2012


Author: jmolenda
Date: Tue Oct 16 19:41:14 2012
New Revision: 166081

URL: http://llvm.org/viewvc/llvm-project?rev=166081&view=rev
Log:
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> 

Modified:
    lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
    lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h

Modified: lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp?rev=166081&r1=166080&r2=166081&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp Tue Oct 16 19:41:14 2012
@@ -109,7 +109,11 @@
                 // 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 @@
                 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 @@
                             // 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 @@
                                     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 @@
                                 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 @@
         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 @@
 //            }
             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()];

Modified: lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h?rev=166081&r1=166080&r2=166081&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h Tue Oct 16 19:41:14 2012
@@ -135,6 +135,7 @@
         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 @@
     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;





More information about the lldb-commits mailing list