[Lldb-commits] [lldb] r160337 - in /lldb/trunk: include/lldb/Symbol/UnwindPlan.h source/API/SBCommandInterpreter.cpp source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h source/Symbol/UnwindPlan.cpp

Jason Molenda jmolenda at apple.com
Mon Jul 16 18:57:24 PDT 2012


Author: jmolenda
Date: Mon Jul 16 20:57:24 2012
New Revision: 160337

URL: http://llvm.org/viewvc/llvm-project?rev=160337&view=rev
Log:
Change UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly so it records
the state of the unwind instructions once the prologue has finished.  If it hits an
early return epilogue in the middle of the function, re-instate the prologue after that
epilogue has completed so that we can still unwind for cases where the flow of control
goes past that early-return.  <rdar://problem/11775059>

Move the UnwindPlan operator== definition into the .cpp file, expand the definition a bit.

Add some casts to a SBCommandInterpreter::HandleCompletion() log statement so it builds without
warning on 64- and 32-bit systems.


Modified:
    lldb/trunk/include/lldb/Symbol/UnwindPlan.h
    lldb/trunk/source/API/SBCommandInterpreter.cpp
    lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
    lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
    lldb/trunk/source/Symbol/UnwindPlan.cpp

Modified: lldb/trunk/include/lldb/Symbol/UnwindPlan.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/UnwindPlan.h?rev=160337&r1=160336&r2=160337&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/UnwindPlan.h (original)
+++ lldb/trunk/include/lldb/Symbol/UnwindPlan.h Mon Jul 16 20:57:24 2012
@@ -250,6 +250,9 @@
         }
 
         bool
+        operator == (const Row &rhs) const;
+
+        bool
         GetRegisterInfo (uint32_t reg_num, RegisterLocation& register_location) const;
     
         void
@@ -337,34 +340,12 @@
         void
         Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, lldb::addr_t base_addr) const;
 
-        bool
-        operator == (const Row &rhs) const
-        {
-            if (m_offset == rhs.m_offset && 
-                m_cfa_reg_num != rhs.m_cfa_reg_num &&
-                m_cfa_offset != rhs.m_cfa_offset)
-                return m_register_locations == rhs.m_register_locations;
-            return false;
-        }
-
-        bool
-        operator != (const Row &rhs) const
-        {
-            if (m_offset != rhs.m_offset ||
-                m_cfa_reg_num != rhs.m_cfa_reg_num ||
-                m_cfa_offset != rhs.m_cfa_offset)
-                return true;
-            
-            return m_register_locations != rhs.m_register_locations;
-        }
-
     protected:
         typedef std::map<uint32_t, RegisterLocation> collection;
         lldb::addr_t m_offset;      // Offset into the function for this row
         uint32_t m_cfa_reg_num;     // The Call Frame Address register number
         int32_t  m_cfa_offset;      // The offset from the CFA for this row
         collection m_register_locations;
-
     }; // class Row
 
 public:

Modified: lldb/trunk/source/API/SBCommandInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBCommandInterpreter.cpp?rev=160337&r1=160336&r2=160337&view=diff
==============================================================================
--- lldb/trunk/source/API/SBCommandInterpreter.cpp (original)
+++ lldb/trunk/source/API/SBCommandInterpreter.cpp Mon Jul 16 20:57:24 2012
@@ -139,8 +139,8 @@
         return 0;
         
     if (log)
-        log->Printf ("SBCommandInterpreter(%p)::HandleCompletion (current_line=\"%s\", cursor at: %ld, last char at: %ld, match_start_point: %d, max_return_elements: %d)",
-                     m_opaque_ptr, current_line, cursor - current_line, last_char - current_line, match_start_point, max_return_elements);
+        log->Printf ("SBCommandInterpreter(%p)::HandleCompletion (current_line=\"%s\", cursor at: %lld, last char at: %lld, match_start_point: %d, max_return_elements: %d)",
+                     m_opaque_ptr, current_line, (uint64_t) (cursor - current_line), (uint64_t) (last_char - current_line), match_start_point, max_return_elements);
                      
     if (m_opaque_ptr)
     {

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=160337&r1=160336&r2=160337&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp Mon Jul 16 20:57:24 2012
@@ -90,22 +90,38 @@
             const InstructionList &inst_list = disasm_sp->GetInstructionList ();
             const size_t num_instructions = inst_list.GetSize();
 
-            UnwindPlan::RowSP prologue_completed_row;
-
             if (num_instructions > 0)
             {
                 Instruction *inst = inst_list.GetInstructionAtIndex (0).get();
                 const addr_t base_addr = inst->GetAddress().GetFileAddress();
-                // Initialize the current row with the one row that was created
-                // from the CreateFunctionEntryUnwind call above...
+
+                // Make a copy of the current instruction Row and save it in m_curr_row
+                // so we can add updates as we process the instructions.  
                 UnwindPlan::RowSP last_row = unwind_plan.GetLastRow();
                 UnwindPlan::Row *newrow = new UnwindPlan::Row;
                 if (last_row.get())
                     *newrow = *last_row.get();
                 m_curr_row.reset(newrow);
 
+                // Once we've seen the initial prologue instructions complete, save a
+                // 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
+                UnwindPlan::RowSP prologue_completed_row;          // copy of prologue row of CFI
+
+                // cache the pc register number (in whatever register numbering this UnwindPlan uses) for
+                // quick reference during instruction parsing.
+                uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
+                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()];
+
+
                 for (size_t idx=0; idx<num_instructions; ++idx)
                 {
+                    m_curr_row_modified = false;
                     inst = inst_list.GetInstructionAtIndex (idx).get();
                     if (inst)
                     {
@@ -121,18 +137,70 @@
                                                             exe_ctx.GetTargetPtr());
 
                         m_inst_emulator_ap->EvaluateInstruction (eEmulateInstructionOptionIgnoreConditions);
-                        
-                        if (unwind_plan.GetLastRow() != m_curr_row)
+
+                        // Were there any changes to the CFI while evaluating this instruction?
+                        if (m_curr_row_modified)
                         {
-                            // Be sure to not edit the offset unless our row has changed
-                            // so that the "!=" call above doesn't trigger every time
+                            reinstate_prologue_next_instruction = false;
                             m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
                             // Append the new row
                             unwind_plan.AppendRow (m_curr_row);
 
+                            // Allocate a new Row for m_curr_row, copy the current state into it
                             UnwindPlan::Row *newrow = new UnwindPlan::Row;
                             *newrow = *m_curr_row.get();
                             m_curr_row.reset(newrow);
+
+                            instructions_since_last_prologue_insn = 0;
+
+                            // 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;
+                            if (prologue_complete
+                                && pc_reg_num != LLDB_INVALID_REGNUM 
+                                && m_curr_row->GetRegisterInfo (pc_reg_num, pc_regloc)
+                                && pc_regloc.IsSame())
+                            {
+                                if (log && log->GetVerbose())
+                                    log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- pc is <same>, restore prologue instructions.");
+                                reinstate_prologue_next_instruction = 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.
+                            // Reinstate the frame setup from the prologue.
+                            if (reinstate_prologue_next_instruction)
+                            {
+                                if (log && log->GetVerbose())
+                                    log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- Reinstating prologue instruction set");
+                                UnwindPlan::Row *newrow = new UnwindPlan::Row;
+                                *newrow = *prologue_completed_row.get();
+                                m_curr_row.reset(newrow);
+                                m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
+                                unwind_plan.AppendRow(m_curr_row);
+
+                                newrow = new UnwindPlan::Row;
+                                *newrow = *m_curr_row.get();
+                                m_curr_row.reset(newrow);
+
+                                reinstate_prologue_next_instruction = 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)
+                            {
+                                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.");
+                            }
                         }
                     }
                 }
@@ -373,6 +441,7 @@
                         m_pushed_regs[reg_num] = addr;
                         const int32_t offset = addr - m_initial_sp;
                         m_curr_row->SetRegisterLocationToAtCFAPlusOffset (reg_num, offset, cant_replace);
+                        m_curr_row_modified = true;
                         if (is_return_address_reg)
                         {
                             // This push was pushing the return address register,
@@ -382,7 +451,10 @@
                             {
                                 uint32_t pc_reg_num = pc_reg_info.kinds[unwind_reg_kind];
                                 if (pc_reg_num != LLDB_INVALID_REGNUM)
+                                {
                                     m_curr_row->SetRegisterLocationToAtCFAPlusOffset (pc_reg_num, offset, can_replace);
+                                    m_curr_row_modified = true;
+                                }
                             }
                         }
                     }
@@ -489,6 +561,7 @@
 //                    m_curr_row.SetRegisterLocationToUndefined (reg_num, 
 //                                                               can_replace_only_if_unspecified, 
 //                                                               can_replace_only_if_unspecified);
+//                    m_curr_row_modified = true;
 //                }
 //            }
             break;
@@ -499,6 +572,7 @@
                 if (reg_num != LLDB_INVALID_REGNUM)
                 {
                     m_curr_row->SetRegisterLocationToSame (reg_num, must_replace);
+                    m_curr_row_modified = true;
                 }
             }
             break;
@@ -512,6 +586,7 @@
                 assert (cfa_reg_num != LLDB_INVALID_REGNUM);
                 m_curr_row->SetCFARegister(cfa_reg_num);
                 m_curr_row->SetCFAOffset(m_initial_sp - reg_value.GetAsUInt64());
+                m_curr_row_modified = true;
             }
             break;
 
@@ -521,6 +596,7 @@
             if (!m_fp_is_cfa)
             {
                 m_curr_row->SetCFAOffset (m_initial_sp - reg_value.GetAsUInt64());
+                m_curr_row_modified = 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=160337&r1=160336&r2=160337&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h Mon Jul 16 20:57:24 2012
@@ -134,6 +134,7 @@
         m_thread_ptr (NULL),
         m_unwind_plan_ptr (NULL),
         m_curr_row (),
+        m_curr_row_modified (false),
         m_cfa_reg_info (),
         m_fp_is_cfa (false),
         m_register_values (),
@@ -162,6 +163,7 @@
     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;
     typedef std::map<uint64_t, uint64_t> PushedRegisterToAddrMap;
     uint64_t m_initial_sp;
     lldb_private::RegisterInfo m_cfa_reg_info;

Modified: lldb/trunk/source/Symbol/UnwindPlan.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/UnwindPlan.cpp?rev=160337&r1=160336&r2=160337&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/UnwindPlan.cpp (original)
+++ lldb/trunk/source/Symbol/UnwindPlan.cpp Mon Jul 16 20:57:24 2012
@@ -295,6 +295,23 @@
     m_cfa_reg_num = reg_num;
 }
 
+bool
+UnwindPlan::Row::operator == (const UnwindPlan::Row& rhs) const
+{
+    if (m_offset != rhs.m_offset || m_cfa_reg_num != rhs.m_cfa_reg_num || m_cfa_offset != rhs.m_cfa_offset)
+        return false;
+    if (m_register_locations.size() != rhs.m_register_locations.size())
+        return false;
+    for (collection::const_iterator idx = m_register_locations.begin(); idx != m_register_locations.end(); ++idx)
+    {
+        collection::const_iterator lhs_pos = m_register_locations.find(idx->first);
+        collection::const_iterator rhs_pos = rhs.m_register_locations.find(idx->first);
+        if (lhs_pos->second != rhs_pos->second)
+            return false;
+    }
+    return true;
+}
+
 void
 UnwindPlan::AppendRow (UnwindPlan::RowSP row)
 {





More information about the lldb-commits mailing list