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

Jason Molenda jmolenda at apple.com
Mon Oct 22 20:08:32 PDT 2012


Author: jmolenda
Date: Mon Oct 22 22:08:31 2012
New Revision: 166465

URL: http://llvm.org/viewvc/llvm-project?rev=166465&view=rev
Log:
Change how the UnwindAssemblyInstEmulation class tracks the setup of
the function's prologue instructions so we can re-instate that prologue
if we hit an early return mid-function.  Add some additional heuristics
to differentiate between prologue and epilogue instruction sequences.

This fixes the specific problem of correctly unwinding through a function
which has an epilogue one instruction after the last prologue setup
instruction has completed.
<rdar://problem/12091139> 

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=166465&r1=166464&r2=166465&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp Mon Oct 22 22:08:31 2012
@@ -108,12 +108,13 @@
                 // copy of the CFI at that point into prologue_completed_row for possible
                 // 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
 
+                bool return_address_register_has_been_saved = false; // if we've seen the ra register get saved yet
+
                 UnwindPlan::RowSP prologue_completed_row;          // copy of prologue row of CFI
 
                 // cache the pc register number (in whatever register numbering this UnwindPlan uses) for
@@ -137,6 +138,7 @@
                 for (size_t idx=0; idx<num_instructions; ++idx)
                 {
                     m_curr_row_modified = false;
+                    m_curr_insn_restored_a_register = false;
                     inst = inst_list.GetInstructionAtIndex (idx).get();
                     if (inst)
                     {
@@ -166,15 +168,33 @@
                             *newrow = *m_curr_row.get();
                             m_curr_row.reset(newrow);
 
-                            instructions_since_last_prologue_insn = 0;
+                            // If m_curr_insn_restored_a_register == true, we're looking at an epilogue instruction.
+                            // Set instructions_since_last_prologue_insn to a very high number so we don't append 
+                            // any of these epilogue instructions to our prologue_complete row.
+                            if (m_curr_insn_restored_a_register == false && instructions_since_last_prologue_insn < 8)
+                              instructions_since_last_prologue_insn = 0;
+                            else
+                              instructions_since_last_prologue_insn = 99;
+
+                            UnwindPlan::Row::RegisterLocation pc_regloc;
+                            UnwindPlan::Row::RegisterLocation ra_regloc;
+
+                            // While parsing the instructions of this function, if we've ever
+                            // seen the return address register (aka lr on arm) in a non-IsSame() state,
+                            // it has been saved on the stack.  If it's evern back to IsSame(), we've
+                            // executed an epilogue.
+                            if (ra_reg_num != LLDB_INVALID_REGNUM
+                                && m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
+                                && !ra_regloc.IsSame())
+                            {
+                                return_address_register_has_been_saved = true;
+                            }
 
                             // If the caller's pc is "same", we've just executed an epilogue and we return to the caller
                             // after this instruction completes executing.
                             // 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
+                            if (prologue_completed_row.get()
                                 && pc_reg_num != LLDB_INVALID_REGNUM 
                                 && m_curr_row->GetRegisterInfo (pc_reg_num, pc_regloc)
                                 && pc_regloc.IsSame())
@@ -183,7 +203,8 @@
                                     log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- pc is <same>, restore prologue instructions.");
                                 reinstate_prologue_next_instruction = true;
                             }
-                            else if (prologue_complete
+                            else if (prologue_completed_row.get()
+                                     && return_address_register_has_been_saved
                                      && ra_reg_num != LLDB_INVALID_REGNUM
                                      && m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
                                      && ra_regloc.IsSame())
@@ -230,16 +251,15 @@
                                 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)
+                            // Stop updating the prologue instructions if we've seen 8 non-prologue instructions
+                            // in a row.
+                            if (instructions_since_last_prologue_insn++ < 8)
                             {
-                                prologue_complete = true;
                                 UnwindPlan::Row *newrow = new UnwindPlan::Row;
                                 *newrow = *m_curr_row.get();
                                 prologue_completed_row.reset(newrow);
                                 if (log && log->GetVerbose())
-                                    log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- prologue has been set up, saving a copy.");
+                                    log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- saving a copy of the current row as the prologue row.");
                             }
                         }
                     }
@@ -622,6 +642,7 @@
                 {
                     m_curr_row->SetRegisterLocationToSame (reg_num, must_replace);
                     m_curr_row_modified = true;
+                    m_curr_insn_restored_a_register = true;
                 }
             }
             break;

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=166465&r1=166464&r2=166465&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h Mon Oct 22 22:08:31 2012
@@ -134,12 +134,13 @@
         m_thread_ptr (NULL),
         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 (),
-        m_pushed_regs()
+        m_pushed_regs(),
+        m_curr_row_modified (false),
+        m_curr_insn_is_branch_immediate (false),
+        m_curr_insn_restored_a_register (false)
     {
         if (m_inst_emulator_ap.get())
         {
@@ -164,8 +165,6 @@
     lldb_private::Thread* m_thread_ptr;
     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;
@@ -173,6 +172,17 @@
     typedef std::map<uint64_t, lldb_private::RegisterValue> RegisterValueMap;
     RegisterValueMap m_register_values;
     PushedRegisterToAddrMap m_pushed_regs;
+
+    // While processing the instruction stream, we need to communicate some state change
+    // information up to the higher level loop that makes decisions about how to push
+    // the unwind instructions for the UnwindPlan we're constructing.
+    
+    // The instruction we're processing updated the UnwindPlan::Row contents
+    bool m_curr_row_modified;
+    // The instruction we're examining is a branch immediate instruction
+    bool m_curr_insn_is_branch_immediate;
+    // The instruction we're processing restored a caller's reg value (e.g. in an epilogue)
+    bool m_curr_insn_restored_a_register;
 };
 
 #endif // liblldb_UnwindAssemblyInstEmulation_h_





More information about the lldb-commits mailing list