[Lldb-commits] [lldb] r225770 - Change the x86 assembly instruction unwind parser to

Jason Molenda jmolenda at apple.com
Mon Jan 12 22:04:05 PST 2015


Author: jmolenda
Date: Tue Jan 13 00:04:04 2015
New Revision: 225770

URL: http://llvm.org/viewvc/llvm-project?rev=225770&view=rev
Log:
Change the x86 assembly instruction unwind parser to
step through the complete function looking for any epilogue
instructions.  If we find an epilogue sequence, re-instate
the correct unwind instructions if there is more code past
that epilogue -- this will correctly handle an x86 function
with multiple epilogues in it.

NB there is still a bug with the "eh_frame augmented" 
UnwindPlans and mid-function epilogues.  Looking at that next.

<rdar://problem/18863406> 

Modified:
    lldb/trunk/include/lldb/Symbol/FuncUnwinders.h
    lldb/trunk/include/lldb/Symbol/UnwindPlan.h
    lldb/trunk/source/Commands/CommandObjectTarget.cpp
    lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
    lldb/trunk/source/Symbol/UnwindPlan.cpp

Modified: lldb/trunk/include/lldb/Symbol/FuncUnwinders.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/FuncUnwinders.h?rev=225770&r1=225769&r2=225770&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/FuncUnwinders.h (original)
+++ lldb/trunk/include/lldb/Symbol/FuncUnwinders.h Tue Jan 13 00:04:04 2015
@@ -84,10 +84,11 @@ public:
     Address
     GetPersonalityRoutinePtrAddress (Target &target);
 
-private:
 
-    lldb::UnwindAssemblySP
-    GetUnwindAssemblyProfiler ();
+
+    // The following methods to retrieve specific unwind plans should rarely be used.
+    // Instead, clients should ask for the *behavior* they are looking for, using one
+    // of the above UnwindPlan retrieval methods.
 
     lldb::UnwindPlanSP
     GetAssemblyUnwindPlan (Target &target, Thread &thread, int current_offset);
@@ -102,13 +103,15 @@ private:
     GetCompactUnwindUnwindPlan (Target &target, int current_offset);
 
     lldb::UnwindPlanSP
-    GetFastUnwindPlan (Target &target, int current_offset);
+    GetArchDefaultUnwindPlan (Thread &thread);
 
     lldb::UnwindPlanSP
-    GetArchDefaultUnwindPlan (Target &target, int current_offset);
+    GetArchDefaultAtFuncEntryUnwindPlan (Thread &thread);
 
-    lldb::UnwindPlanSP
-    GetArchDefaultAtFuncEntryUnwindPlan (Target &target, int current_offset);
+private:
+
+    lldb::UnwindAssemblySP
+    GetUnwindAssemblyProfiler ();
 
     UnwindTable& m_unwind_table;
     AddressRange m_range;

Modified: lldb/trunk/include/lldb/Symbol/UnwindPlan.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/UnwindPlan.h?rev=225770&r1=225769&r2=225770&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/UnwindPlan.h (original)
+++ lldb/trunk/include/lldb/Symbol/UnwindPlan.h Tue Jan 13 00:04:04 2015
@@ -257,7 +257,10 @@ public:
     
         void
         SetRegisterInfo (uint32_t reg_num, const RegisterLocation register_location);
-    
+
+        void
+        RemoveRegisterInfo (uint32_t reg_num);
+
         lldb::addr_t
         GetOffset() const
         {

Modified: lldb/trunk/source/Commands/CommandObjectTarget.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectTarget.cpp?rev=225770&r1=225769&r2=225770&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectTarget.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectTarget.cpp Tue Jan 13 00:04:04 2015
@@ -3744,45 +3744,85 @@ protected:
             if (func_unwinders_sp.get() == NULL)
                 continue;
 
-            Address first_non_prologue_insn (func_unwinders_sp->GetFirstNonPrologueInsn(*target));
-            if (first_non_prologue_insn.IsValid())
-            {
-                result.GetOutputStream().Printf("First non-prologue instruction is at address 0x%" PRIx64 " or offset %" PRId64 " into the function.\n", first_non_prologue_insn.GetLoadAddress(target), first_non_prologue_insn.GetLoadAddress(target) - start_addr);
-                result.GetOutputStream().Printf ("\n");
-            }
+            result.GetOutputStream().Printf("UNWIND PLANS for %s`%s (start addr 0x%" PRIx64 ")\n\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
 
             UnwindPlanSP non_callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtNonCallSite(*target, *thread.get(), -1);
             if (non_callsite_unwind_plan.get())
             {
-                result.GetOutputStream().Printf("Asynchronous (not restricted to call-sites) UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
-                non_callsite_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
-                result.GetOutputStream().Printf ("\n");
+                result.GetOutputStream().Printf("Asynchronous (not restricted to call-sites) UnwindPlan is '%s'\n", non_callsite_unwind_plan->GetSourceName().AsCString());
             }
-
             UnwindPlanSP callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(*target, -1);
             if (callsite_unwind_plan.get())
             {
-                result.GetOutputStream().Printf("Synchronous (restricted to call-sites) UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
-                callsite_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
-                result.GetOutputStream().Printf ("\n");
+                result.GetOutputStream().Printf("Synchronous (restricted to call-sites) UnwindPlan is '%s'\n", callsite_unwind_plan->GetSourceName().AsCString());
             }
+            UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*thread.get());
+            if (fast_unwind_plan.get())
+            {
+                result.GetOutputStream().Printf("Fast UnwindPlan is '%s'\n", fast_unwind_plan->GetSourceName().AsCString());
+            }
+
+            result.GetOutputStream().Printf("\n");
 
-            UnwindPlanSP arch_default_unwind_plan = func_unwinders_sp->GetUnwindPlanArchitectureDefault(*thread.get());
-            if (arch_default_unwind_plan.get())
+            UnwindPlanSP assembly_sp = func_unwinders_sp->GetAssemblyUnwindPlan(*target, *thread.get(), 0);
+            if (assembly_sp)
             {
-                result.GetOutputStream().Printf("Architecture default UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
-                arch_default_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
-                result.GetOutputStream().Printf ("\n");
+                result.GetOutputStream().Printf("Assembly language inspection UnwindPlan:\n");
+                assembly_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+                result.GetOutputStream().Printf("\n");
             }
+            
 
-            UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*thread.get());
-            if (fast_unwind_plan.get())
+            UnwindPlanSP ehframe_sp = func_unwinders_sp->GetEHFrameUnwindPlan(*target, 0);
+            if (ehframe_sp)
             {
-                result.GetOutputStream().Printf("Fast UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
+                result.GetOutputStream().Printf("eh_frame UnwindPlan:\n");
+                ehframe_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+                result.GetOutputStream().Printf("\n");
+            }
+
+            UnwindPlanSP ehframe_augmented_sp = func_unwinders_sp->GetEHFrameAugmentedUnwindPlan(*target, *thread.get(), 0);
+            if (ehframe_augmented_sp)
+            {
+                result.GetOutputStream().Printf("eh_frame augmented UnwindPlan:\n");
+                ehframe_augmented_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+                result.GetOutputStream().Printf("\n");
+            }
+
+            UnwindPlanSP compact_unwind_sp = func_unwinders_sp->GetCompactUnwindUnwindPlan(*target, 0);
+            if (compact_unwind_sp)
+            {
+                result.GetOutputStream().Printf("Compact unwind UnwindPlan:\n");
+                compact_unwind_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+                result.GetOutputStream().Printf("\n");
+            }
+
+            if (fast_unwind_plan)
+            {
+                result.GetOutputStream().Printf("Fast UnwindPlan:\n");
                 fast_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
-                result.GetOutputStream().Printf ("\n");
+                result.GetOutputStream().Printf("\n");
             }
 
+            ABISP abi_sp = process->GetABI();
+            if (abi_sp)
+            {
+                UnwindPlan arch_default(lldb::eRegisterKindGeneric);
+                if (abi_sp->CreateDefaultUnwindPlan (arch_default))
+                {
+                    result.GetOutputStream().Printf("Arch default UnwindPlan:\n");
+                    arch_default.Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+                    result.GetOutputStream().Printf("\n");
+                }
+
+                UnwindPlan arch_entry(lldb::eRegisterKindGeneric);
+                if (abi_sp->CreateFunctionEntryUnwindPlan (arch_entry))
+                {
+                    result.GetOutputStream().Printf("Arch default at entry point UnwindPlan:\n");
+                    arch_entry.Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+                    result.GetOutputStream().Printf("\n");
+                }
+            }
 
             result.GetOutputStream().Printf ("\n");
         }

Modified: lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp?rev=225770&r1=225769&r2=225770&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp Tue Jan 13 00:04:04 2015
@@ -319,7 +319,8 @@ AssemblyParse_x86::nonvolatile_reg_p (in
 #define REX_W_DSTREG(opcode) ((opcode) & 0x1)
 
 // pushq %rbp [0x55]
-bool AssemblyParse_x86::push_rbp_pattern_p ()
+bool 
+AssemblyParse_x86::push_rbp_pattern_p ()
 {
     uint8_t *p = m_cur_insn_bytes;
     if (*p == 0x55)
@@ -328,7 +329,8 @@ bool AssemblyParse_x86::push_rbp_pattern
 }
 
 // pushq $0 ; the first instruction in start() [0x6a 0x00]
-bool AssemblyParse_x86::push_0_pattern_p ()
+bool 
+AssemblyParse_x86::push_0_pattern_p ()
 {
     uint8_t *p = m_cur_insn_bytes;
     if (*p == 0x6a && *(p + 1) == 0x0)
@@ -338,7 +340,8 @@ bool AssemblyParse_x86::push_0_pattern_p
 
 // pushq $0
 // pushl $0
-bool AssemblyParse_x86::push_imm_pattern_p ()
+bool 
+AssemblyParse_x86::push_imm_pattern_p ()
 {
     uint8_t *p = m_cur_insn_bytes;
     if (*p == 0x68 || *p == 0x6a)
@@ -348,7 +351,8 @@ bool AssemblyParse_x86::push_imm_pattern
 
 // movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5]
 // movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5]
-bool AssemblyParse_x86::mov_rsp_rbp_pattern_p ()
+bool 
+AssemblyParse_x86::mov_rsp_rbp_pattern_p ()
 {
     uint8_t *p = m_cur_insn_bytes;
     if (m_wordsize == 8 && *p == 0x48)
@@ -361,7 +365,8 @@ bool AssemblyParse_x86::mov_rsp_rbp_patt
 }
 
 // subq $0x20, %rsp
-bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount)
+bool 
+AssemblyParse_x86::sub_rsp_pattern_p (int& amount)
 {
     uint8_t *p = m_cur_insn_bytes;
     if (m_wordsize == 8 && *p == 0x48)
@@ -382,7 +387,8 @@ bool AssemblyParse_x86::sub_rsp_pattern_
 }
 
 // addq $0x20, %rsp
-bool AssemblyParse_x86::add_rsp_pattern_p (int& amount)
+bool 
+AssemblyParse_x86::add_rsp_pattern_p (int& amount)
 {
     uint8_t *p = m_cur_insn_bytes;
     if (m_wordsize == 8 && *p == 0x48)
@@ -404,7 +410,8 @@ bool AssemblyParse_x86::add_rsp_pattern_
 
 // pushq %rbx
 // pushl %ebx
-bool AssemblyParse_x86::push_reg_p (int& regno)
+bool 
+AssemblyParse_x86::push_reg_p (int& regno)
 {
     uint8_t *p = m_cur_insn_bytes;
     int regno_prefix_bit = 0;
@@ -424,7 +431,8 @@ bool AssemblyParse_x86::push_reg_p (int&
 
 // popq %rbx
 // popl %ebx
-bool AssemblyParse_x86::pop_reg_p (int& regno)
+bool 
+AssemblyParse_x86::pop_reg_p (int& regno)
 {
     uint8_t *p = m_cur_insn_bytes;
     int regno_prefix_bit = 0;
@@ -444,14 +452,16 @@ bool AssemblyParse_x86::pop_reg_p (int&
 
 // popq %rbp [0x5d]
 // popl %ebp [0x5d]
-bool AssemblyParse_x86::pop_rbp_pattern_p ()
+bool 
+AssemblyParse_x86::pop_rbp_pattern_p ()
 {
     uint8_t *p = m_cur_insn_bytes;
     return (*p == 0x5d);
 }
 
 // call $0 [0xe8 0x0 0x0 0x0 0x0]
-bool AssemblyParse_x86::call_next_insn_pattern_p ()
+bool 
+AssemblyParse_x86::call_next_insn_pattern_p ()
 {
     uint8_t *p = m_cur_insn_bytes;
     return (*p == 0xe8) && (*(p+1) == 0x0) && (*(p+2) == 0x0)
@@ -469,7 +479,8 @@ bool AssemblyParse_x86::call_next_insn_p
 // the actual location.  The positive value returned for the offset
 // is a convention used elsewhere for CFA offsets et al.
 
-bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset)
+bool 
+AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset)
 {
     uint8_t *p = m_cur_insn_bytes;
     int src_reg_prefix_bit = 0;
@@ -603,7 +614,6 @@ bool
 AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
 {
     UnwindPlan::RowSP row(new UnwindPlan::Row);
-    int non_prologue_insn_count = 0;
     m_cur_insn = m_func_bounds.GetBaseAddress ();
     int current_func_text_offset = 0;
     int current_sp_bytes_offset_from_cfa = 0;
@@ -647,18 +657,29 @@ AssemblyParse_x86::get_non_call_site_unw
 
     const bool prefer_file_cache = true;
 
+    // Once the prologue has completed we'll save a copy of the unwind instructions
+    // If there is an epilogue in the middle of the function, after that epilogue we'll reinstate
+    // the unwind setup -- we assume that some code path jumps over the mid-function epilogue
+
+    bool in_epilogue = false;                          // we're in the middle of an epilogue sequence
+    UnwindPlan::RowSP prologue_completed_row;          // copy of prologue row of CFI
+    int prologue_completed_sp_bytes_offset_from_cfa;   // The sp value before the epilogue started executed
+
     Target *target = m_exe_ctx.GetTargetPtr();
-    while (m_func_bounds.ContainsFileAddress (m_cur_insn) && non_prologue_insn_count < 10)
+    while (m_func_bounds.ContainsFileAddress (m_cur_insn))
     {
         int stack_offset, insn_len;
         int machine_regno;          // register numbers masked directly out of instructions
         uint32_t lldb_regno;        // register numbers in lldb's eRegisterKindLLDB numbering scheme
 
+        bool row_updated = false;
+
         if (!instruction_length (m_cur_insn, insn_len) || insn_len == 0 || insn_len > kMaxInstructionByteSize)
         {
             // An unrecognized/junk instruction
             break;
         }
+
         if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
                                 insn_len, error) == static_cast<size_t>(-1))
         {
@@ -668,232 +689,170 @@ AssemblyParse_x86::get_non_call_site_unw
 
         if (push_rbp_pattern_p ())
         {
-            row->SetOffset (current_func_text_offset + insn_len);
             current_sp_bytes_offset_from_cfa += m_wordsize;
             row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
             UnwindPlan::Row::RegisterLocation regloc;
             regloc.SetAtCFAPlusOffset (-row->GetCFAOffset());
             row->SetRegisterInfo (m_lldb_fp_regnum, regloc);
-            unwind_plan.AppendRow (row);
-            // Allocate a new Row, populate it with the existing Row contents.
-            newrow = new UnwindPlan::Row;
-            *newrow = *row.get();
-            row.reset(newrow);
-            goto loopnext;
+            saved_registers[m_machine_fp_regnum] = true;
+            row_updated = true;
         }
 
-        if (mov_rsp_rbp_pattern_p ())
+        else if (mov_rsp_rbp_pattern_p ())
         {
-            row->SetOffset (current_func_text_offset + insn_len);
             row->SetCFARegister (m_lldb_fp_regnum);
-            unwind_plan.AppendRow (row);
-            // Allocate a new Row, populate it with the existing Row contents.
-            newrow = new UnwindPlan::Row;
-            *newrow = *row.get();
-            row.reset(newrow);
-            goto loopnext;
+            row_updated = true;
         }
 
         // This is the start() function (or a pthread equivalent), it starts with a pushl $0x0 which puts the
         // saved pc value of 0 on the stack.  In this case we want to pretend we didn't see a stack movement at all --
         // normally the saved pc value is already on the stack by the time the function starts executing.
-        if (push_0_pattern_p ())
+        else if (push_0_pattern_p ())
         {
-            goto loopnext;
         }
 
-        if (push_reg_p (machine_regno))
+        else if (push_reg_p (machine_regno))
         {
             current_sp_bytes_offset_from_cfa += m_wordsize;
-            bool need_to_push_row = false;
             // the PUSH instruction has moved the stack pointer - if the CFA is set in terms of the stack pointer,
             // we need to add a new row of instructions.
             if (row->GetCFARegister() == m_lldb_sp_regnum)
             {
-                need_to_push_row = true;
                 row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+                row_updated = true;
             }
             // record where non-volatile (callee-saved, spilled) registers are saved on the stack
             if (nonvolatile_reg_p (machine_regno) 
                 && machine_regno_to_lldb_regno (machine_regno, lldb_regno)
                 && saved_registers[machine_regno] == false)
             {
-                need_to_push_row = true;
                 UnwindPlan::Row::RegisterLocation regloc;
                 regloc.SetAtCFAPlusOffset (-current_sp_bytes_offset_from_cfa);
                 row->SetRegisterInfo (lldb_regno, regloc);
                 saved_registers[machine_regno] = true;
+                row_updated = true;
             }
-            if (need_to_push_row)
-            {
-                row->SetOffset (current_func_text_offset + insn_len);
-                unwind_plan.AppendRow (row);
-                // Allocate a new Row, populate it with the existing Row contents.
-                newrow = new UnwindPlan::Row;
-                *newrow = *row.get();
-                row.reset(newrow);
-            }
-            goto loopnext;
         }
 
-        if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset) && nonvolatile_reg_p (machine_regno))
+        else if (pop_reg_p (machine_regno))
         {
-            if (machine_regno_to_lldb_regno (machine_regno, lldb_regno) && saved_registers[machine_regno] == false)
-            {
-                saved_registers[machine_regno] = true;
+            current_sp_bytes_offset_from_cfa -= m_wordsize;
 
-                row->SetOffset (current_func_text_offset + insn_len);
-                UnwindPlan::Row::RegisterLocation regloc;
+            if (nonvolatile_reg_p (machine_regno) 
+                && machine_regno_to_lldb_regno (machine_regno, lldb_regno)
+                && saved_registers[machine_regno] == true)
+            {
+                saved_registers[machine_regno] = false;
+                row->RemoveRegisterInfo (lldb_regno);
 
-                // stack_offset for 'movq %r15, -80(%rbp)' will be 80.
-                // In the Row, we want to express this as the offset from the CFA.  If the frame base
-                // is rbp (like the above instruction), the CFA offset for rbp is probably 16.  So we
-                // want to say that the value is stored at the CFA address - 96.
-                regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAOffset()));
+                if (machine_regno == m_machine_fp_regnum)
+                {
+                    row->SetCFARegister (m_lldb_sp_regnum);
+                }
 
-                row->SetRegisterInfo (lldb_regno, regloc);
-                unwind_plan.AppendRow (row);
-                // Allocate a new Row, populate it with the existing Row contents.
-                newrow = new UnwindPlan::Row;
-                *newrow = *row.get();
-                row.reset(newrow);
-                goto loopnext;
+                in_epilogue = true;
+                row_updated = true;
             }
-        }
 
-        if (sub_rsp_pattern_p (stack_offset))
-        {
-            current_sp_bytes_offset_from_cfa += stack_offset;
+            // the POP instruction has moved the stack pointer - if the CFA is set in terms of the stack pointer,
+            // we need to add a new row of instructions.
             if (row->GetCFARegister() == m_lldb_sp_regnum)
             {
-                row->SetOffset (current_func_text_offset + insn_len);
                 row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
-                unwind_plan.AppendRow (row);
-                // Allocate a new Row, populate it with the existing Row contents.
-                newrow = new UnwindPlan::Row;
-                *newrow = *row.get();
-                row.reset(newrow);
+                row_updated = true;
             }
-            goto loopnext;
         }
 
-        if (ret_pattern_p ())
+        else if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset) 
+                 && nonvolatile_reg_p (machine_regno)
+                 && machine_regno_to_lldb_regno (machine_regno, lldb_regno) 
+                 && saved_registers[machine_regno] == false)
         {
-            // we know where the end of the function is; set the limit on the PlanValidAddressRange
-            // in case our initial "high pc" value was overly large
-            // int original_size = m_func_bounds.GetByteSize();
-            // int calculated_size = m_cur_insn.GetOffset() - m_func_bounds.GetBaseAddress().GetOffset() + insn_len + 1;
-            // m_func_bounds.SetByteSize (calculated_size);
-            // unwind_plan.SetPlanValidAddressRange (m_func_bounds);
-            break;
-        }
-
-        // 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.
-
-        non_prologue_insn_count++;
-loopnext:
-        m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
-        current_func_text_offset += insn_len;
-    }
+            saved_registers[machine_regno] = true;
 
-    // Now look at the byte at the end of the AddressRange for a limited attempt at describing the
-    // epilogue.  We're looking for the sequence
+            UnwindPlan::Row::RegisterLocation regloc;
 
-    //  [ 0x5d ] mov %rbp, %rsp  (aka pop %rbp)
-    //  [ 0xc3 ] ret
+            // stack_offset for 'movq %r15, -80(%rbp)' will be 80.
+            // In the Row, we want to express this as the offset from the CFA.  If the frame base
+            // is rbp (like the above instruction), the CFA offset for rbp is probably 16.  So we
+            // want to say that the value is stored at the CFA address - 96.
+            regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAOffset()));
 
-    // or
+            row->SetRegisterInfo (lldb_regno, regloc);
 
-    //  [ 0x5d ] mov %rbp, %rsp  (aka pop %rbp)
-    //  [ 0xe9 xx xx xx xx ] jmp objc_retainAutoreleaseReturnValue  (this is sometimes the final insn in the function)
+            row_updated = true;
+        }
 
-    // or
+        else if (sub_rsp_pattern_p (stack_offset))
+        {
+            current_sp_bytes_offset_from_cfa += stack_offset;
+            if (row->GetCFARegister() == m_lldb_sp_regnum)
+            {
+                row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+                row_updated = true;
+            }
+        }
 
-    //  [ 0x5d ] mov %rbp, %rsp  (aka pop %rbp)
-    //  [ 0xc3 ] ret
-    //  [ 0xe8 xx xx xx xx ] call __stack_chk_fail  (this is sometimes the final insn in the function)
+        else if (add_rsp_pattern_p (stack_offset))
+        {
+            current_sp_bytes_offset_from_cfa -= stack_offset;
+            if (row->GetCFARegister() == m_lldb_sp_regnum)
+            {
+                row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+                row_updated = true;
+            }
+            in_epilogue = true;
+        }
 
-    // or
+        else if (ret_pattern_p () && prologue_completed_row.get())
+        {
+            // Reinstate the saved prologue setup for any instructions
+            // that come after the ret instruction
 
-    //  [ 0x5d ] mov %rbp, %rsp  (aka pop %rbp)
-    //  [ 0xc3 ] ret
-    //  [ 0x0f 0x1f 0x44 xx xx ] nopl (%rax,%rax)   (aka nop)
+            UnwindPlan::Row *newrow = new UnwindPlan::Row;
+            *newrow = *prologue_completed_row.get();
+            row.reset (newrow);
+            current_sp_bytes_offset_from_cfa = prologue_completed_sp_bytes_offset_from_cfa;
 
-    // We want to add a Row describing how to unwind when we're stopped on the 'ret' instruction where the
-    // CFA is no longer defined in terms of rbp, but is now defined in terms of rsp like on function entry.
-    // (or the 'jmp' instruction in the second case)
+            in_epilogue = true;
+            row_updated = true;
+        }
 
-    uint64_t ret_insn_offset = LLDB_INVALID_ADDRESS;
-    Address end_of_fun(m_func_bounds.GetBaseAddress());
-    end_of_fun.SetOffset (end_of_fun.GetOffset() + m_func_bounds.GetByteSize());
+        // 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.
 
-    if (m_func_bounds.GetByteSize() > 7)
-    {
-        uint8_t bytebuf[7];
-        Address last_seven_bytes(end_of_fun);
-        last_seven_bytes.SetOffset (last_seven_bytes.GetOffset() - 7);
-        if (target->ReadMemory (last_seven_bytes, prefer_file_cache, bytebuf, 7,
-                                error) != static_cast<size_t>(-1))
+        if (row_updated)
         {
-            if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3)  // mov & ret
-            {
-                ret_insn_offset = m_func_bounds.GetByteSize() - 1;
-            }
-            else if (bytebuf[1] == 0x5d && bytebuf[2] == 0xe9)  // mov & jmp
-            {
-                // When the pc is sitting on the 'jmp' instruction, we have the same
-                // unwind state as if it was sitting on a 'ret' instruction.
-                ret_insn_offset = m_func_bounds.GetByteSize() - 5;
-            }
-            else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3 && bytebuf[2] == 0xe8) // mov & ret & call
+            if (current_func_text_offset + insn_len < m_func_bounds.GetByteSize())
             {
-                ret_insn_offset = m_func_bounds.GetByteSize() - 6;
-            }
-            else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3
-                     && bytebuf[2] == 0x0f && bytebuf[3] == 0x1f && bytebuf[4] == 0x44) // mov & ret & nop
-            {
-                ret_insn_offset = m_func_bounds.GetByteSize() - 6;
+                row->SetOffset (current_func_text_offset + insn_len);
+                unwind_plan.AppendRow (row);
+                // Allocate a new Row, populate it with the existing Row contents.
+                newrow = new UnwindPlan::Row;
+                *newrow = *row.get();
+                row.reset(newrow);
             }
         }
-    }
-    else if (m_func_bounds.GetByteSize() > 2)
-    {
-        uint8_t bytebuf[2];
-        Address last_two_bytes(end_of_fun);
-        last_two_bytes.SetOffset (last_two_bytes.GetOffset() - 2);
-        if (target->ReadMemory (last_two_bytes, prefer_file_cache, bytebuf, 2,
-                                error) != static_cast<size_t>(-1))
+
+        if (in_epilogue == false && row_updated)
         {
-            if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov & ret
-            {
-                ret_insn_offset = m_func_bounds.GetByteSize() - 1;
-            }
+            // If we're not in an epilogue sequence, save the updated Row
+            UnwindPlan::Row *newrow = new UnwindPlan::Row;
+            *newrow = *row.get();
+            prologue_completed_row.reset (newrow);
         }
-    }
 
-    if (ret_insn_offset != LLDB_INVALID_ADDRESS)
-    {
-        // Create a fresh, empty Row and RegisterLocation - don't mention any other registers
-        UnwindPlan::RowSP epi_row(new UnwindPlan::Row);
-        UnwindPlan::Row::RegisterLocation epi_regloc;
-
-        // When the ret instruction is about to be executed, here's our state
-        epi_row->SetOffset (ret_insn_offset);
-        epi_row->SetCFARegister (m_lldb_sp_regnum);
-        epi_row->SetCFAOffset (m_wordsize);
-
-        // caller's stack pointer value before the call insn is the CFA address
-        epi_regloc.SetIsCFAPlusOffset (0);
-        epi_row->SetRegisterInfo (m_lldb_sp_regnum, epi_regloc);
-
-        // saved instruction pointer can be found at CFA - wordsize
-        epi_regloc.SetAtCFAPlusOffset (-m_wordsize);
-        epi_row->SetRegisterInfo (m_lldb_ip_regnum, epi_regloc);
+        // We may change the sp value without adding a new Row necessarily -- keep
+        // track of it either way.
+        if (in_epilogue == false)
+        {
+            prologue_completed_sp_bytes_offset_from_cfa = current_sp_bytes_offset_from_cfa;
+        }
 
-        unwind_plan.AppendRow (epi_row);
+        m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
+        current_func_text_offset += insn_len;
     }
 
     unwind_plan.SetSourceName ("assembly insn profiling");

Modified: lldb/trunk/source/Symbol/UnwindPlan.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/UnwindPlan.cpp?rev=225770&r1=225769&r2=225770&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/UnwindPlan.cpp (original)
+++ lldb/trunk/source/Symbol/UnwindPlan.cpp Tue Jan 13 00:04:04 2015
@@ -168,7 +168,7 @@ UnwindPlan::Row::Dump (Stream& s, const
     if (base_addr != LLDB_INVALID_ADDRESS)
         s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
     else
-        s.Printf ("0x%8.8" PRIx64 ": CFA=", GetOffset());
+        s.Printf ("%4" PRId64 ": CFA=", GetOffset());
             
     if (reg_info)
         s.Printf ("%s", reg_info->name);
@@ -211,6 +211,16 @@ UnwindPlan::Row::GetRegisterInfo (uint32
 }
 
 void
+UnwindPlan::Row::RemoveRegisterInfo (uint32_t reg_num)
+{
+    collection::const_iterator pos = m_register_locations.find(reg_num);
+    if (pos != m_register_locations.end())
+    {
+        m_register_locations.erase(pos);
+    }
+}
+
+void
 UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
 {
     m_register_locations[reg_num] = register_location;





More information about the lldb-commits mailing list