[Lldb-commits] [lldb] r216406 - On x86 & x86_64, try to use eh_frame for frame 0.

Todd Fiala todd.fiala at gmail.com
Mon Aug 25 13:29:10 PDT 2014


Author: tfiala
Date: Mon Aug 25 15:29:09 2014
New Revision: 216406

URL: http://llvm.org/viewvc/llvm-project?rev=216406&view=rev
Log:
On x86 & x86_64, try to use eh_frame for frame 0.

We decided to use assmbly profiler instead of eh_frame for frame 0 because for compiler generated code, eh_frame is usually synchronous(a.k.a. only valid at call site); and we have no way to tell if it's asynchronous or not.
But for x86 & x86_64 compiler generated code:
1. clang & GCC describes all prologue instructions in eh_frame;
2. mid-function stack pointer altering instructions can be easily detected.
So we can grab eh_frame, and use assembly profiler to augment it into asynchronous unwind table.
This change also benefits hand-written assembly; eh_frame for hand-written assembly is often asynchronous,so we have a much better chance to successfully unwind through them.

Change by Tong Shen.

Modified:
    lldb/trunk/include/lldb/Symbol/FuncUnwinders.h
    lldb/trunk/include/lldb/Symbol/UnwindPlan.h
    lldb/trunk/include/lldb/Target/UnwindAssembly.h
    lldb/trunk/source/Commands/CommandObjectTarget.cpp
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
    lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
    lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
    lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
    lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h
    lldb/trunk/source/Symbol/FuncUnwinders.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=216406&r1=216405&r2=216406&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/FuncUnwinders.h (original)
+++ lldb/trunk/include/lldb/Symbol/FuncUnwinders.h Mon Aug 25 15:29:09 2014
@@ -44,7 +44,7 @@ public:
     GetUnwindPlanAtCallSite (int current_offset);
 
     lldb::UnwindPlanSP
-    GetUnwindPlanAtNonCallSite (lldb_private::Thread& thread);
+    GetUnwindPlanAtNonCallSite (Target& target, lldb_private::Thread& thread, int current_offset);
 
     lldb::UnwindPlanSP
     GetUnwindPlanFastUnwind (lldb_private::Thread& Thread);

Modified: lldb/trunk/include/lldb/Symbol/UnwindPlan.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/UnwindPlan.h?rev=216406&r1=216405&r2=216406&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/UnwindPlan.h (original)
+++ lldb/trunk/include/lldb/Symbol/UnwindPlan.h Mon Aug 25 15:29:09 2014
@@ -365,6 +365,9 @@ public:
     void 
     AppendRow (const RowSP& row_sp);
 
+    void
+    InsertRow (const RowSP& row_sp);
+
     // Returns a pointer to the best row for the given offset into the function's instructions.
     // If offset is -1 it indicates that the function start is unknown - the final row in the UnwindPlan is returned.
     // In practice, the UnwindPlan for a function with no known start address will be the architectural default

Modified: lldb/trunk/include/lldb/Target/UnwindAssembly.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/UnwindAssembly.h?rev=216406&r1=216405&r2=216406&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/UnwindAssembly.h (original)
+++ lldb/trunk/include/lldb/Target/UnwindAssembly.h Mon Aug 25 15:29:09 2014
@@ -33,6 +33,11 @@ public:
                                           UnwindPlan& unwind_plan) = 0;
 
     virtual bool
+    AugmentUnwindPlanFromCallSite (AddressRange& func,
+                                   Thread& thread,
+                                   UnwindPlan& unwind_plan) = 0;
+
+    virtual bool
     GetFastUnwindPlan (AddressRange& func, 
                        Thread& thread, 
                        UnwindPlan &unwind_plan) = 0;

Modified: lldb/trunk/source/Commands/CommandObjectTarget.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectTarget.cpp?rev=216406&r1=216405&r2=216406&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectTarget.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectTarget.cpp Mon Aug 25 15:29:09 2014
@@ -3724,7 +3724,7 @@ protected:
                 result.GetOutputStream().Printf ("\n");
             }
 
-            UnwindPlanSP non_callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtNonCallSite(*thread.get());
+            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);

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp?rev=216406&r1=216405&r2=216406&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp Mon Aug 25 15:29:09 2014
@@ -794,7 +794,7 @@ RegisterContextLLDB::GetFullUnwindPlanFo
     // Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions
     if (behaves_like_zeroth_frame)
     {
-        unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
+        unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one);
         if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
         {
             if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo)
@@ -822,7 +822,7 @@ RegisterContextLLDB::GetFullUnwindPlanFo
 
     // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've
     // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible.
-    unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
+    unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one);
     if (unwind_plan_sp && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo)
     {
         // We probably have an UnwindPlan created by inspecting assembly instructions, and we probably

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=216406&r1=216405&r2=216406&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp Mon Aug 25 15:29:09 2014
@@ -285,6 +285,14 @@ UnwindAssemblyInstEmulation::GetNonCallS
 }
 
 bool
+UnwindAssemblyInstEmulation::AugmentUnwindPlanFromCallSite (AddressRange& func,
+                                                            Thread& thread,
+                                                            UnwindPlan& unwind_plan)
+{
+    return false;
+}
+
+bool
 UnwindAssemblyInstEmulation::GetFastUnwindPlan (AddressRange& func, 
                                                 Thread& thread, 
                                                 UnwindPlan &unwind_plan)

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=216406&r1=216405&r2=216406&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h Mon Aug 25 15:29:09 2014
@@ -31,6 +31,11 @@ public:
                                           lldb_private::UnwindPlan& unwind_plan);
 
     virtual bool
+    AugmentUnwindPlanFromCallSite (lldb_private::AddressRange& func,
+                                   lldb_private::Thread& thread,
+                                   lldb_private::UnwindPlan& unwind_plan);
+
+    virtual bool
     GetFastUnwindPlan (lldb_private::AddressRange& func, 
                        lldb_private::Thread& thread, 
                        lldb_private::UnwindPlan &unwind_plan);

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=216406&r1=216405&r2=216406&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp Mon Aug 25 15:29:09 2014
@@ -123,6 +123,8 @@ public:
 
     bool get_non_call_site_unwind_plan (UnwindPlan &unwind_plan);
 
+    bool augment_unwind_plan_from_call_site (AddressRange& func, UnwindPlan &unwind_plan);
+
     bool get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan);
 
     bool find_first_non_prologue_insn (Address &address);
@@ -135,9 +137,14 @@ private:
     bool push_0_pattern_p ();
     bool mov_rsp_rbp_pattern_p ();
     bool sub_rsp_pattern_p (int& amount);
+    bool add_rsp_pattern_p (int& amount);
     bool push_reg_p (int& regno);
+    bool pop_reg_p (int& regno);
+    bool push_imm_pattern_p ();
     bool mov_reg_to_local_stack_frame_p (int& regno, int& fp_offset);
     bool ret_pattern_p ();
+    bool pop_rbp_pattern_p ();
+    bool call_next_insn_pattern_p();
     uint32_t extract_4 (uint8_t *b);
     bool machine_regno_to_lldb_regno (int machine_regno, uint32_t& lldb_regno);
     bool instruction_length (Address addr, int &length);
@@ -149,13 +156,13 @@ private:
     Address m_cur_insn;
     uint8_t m_cur_insn_bytes[kMaxInstructionByteSize];
 
-    int m_machine_ip_regnum;
-    int m_machine_sp_regnum;
-    int m_machine_fp_regnum;
-
-    int m_lldb_ip_regnum;
-    int m_lldb_sp_regnum;
-    int m_lldb_fp_regnum;
+    uint32_t m_machine_ip_regnum;
+    uint32_t m_machine_sp_regnum;
+    uint32_t m_machine_fp_regnum;
+
+    uint32_t m_lldb_ip_regnum;
+    uint32_t m_lldb_sp_regnum;
+    uint32_t m_lldb_fp_regnum;
 
     int m_wordsize;
     int m_cpu;
@@ -318,6 +325,15 @@ bool AssemblyParse_x86::push_0_pattern_p
     return false;
 }
 
+// pushq $0
+// pushl $0
+bool AssemblyParse_x86::push_imm_pattern_p () {
+    uint8_t *p = m_cur_insn_bytes;
+    if (*p == 0x68 || *p == 0x6a)
+        return true;
+    return false;
+}
+
 // 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 () {
@@ -346,13 +362,29 @@ bool AssemblyParse_x86::sub_rsp_pattern_
         amount = (int32_t) extract_4 (p + 2);
         return true;
     }
-    // Not handled:  [0x83 0xc4] for imm8 with neg values
-    // [0x81 0xc4] for imm32 with neg values
+    return false;
+}
+
+// addq $0x20, %rsp 
+bool AssemblyParse_x86::add_rsp_pattern_p (int& amount) {
+    uint8_t *p = m_cur_insn_bytes;
+    if (m_wordsize == 8 && *p == 0x48)
+      p++;
+    // 8-bit immediate operand
+    if (*p == 0x83 && *(p + 1) == 0xc4) {
+        amount = (int8_t) *(p + 2);
+        return true;
+    }
+    // 32-bit immediate operand
+    if (*p == 0x81 && *(p + 1) == 0xc4) {
+        amount = (int32_t) extract_4 (p + 2);
+        return true;
+    }
     return false;
 }
 
 // pushq %rbx
-// pushl $ebx
+// pushl %ebx
 bool AssemblyParse_x86::push_reg_p (int& regno) {
     uint8_t *p = m_cur_insn_bytes;
     int regno_prefix_bit = 0;
@@ -368,6 +400,37 @@ bool AssemblyParse_x86::push_reg_p (int&
     return false;
 }
 
+// popq %rbx
+// popl %ebx
+bool AssemblyParse_x86::pop_reg_p (int& regno) {
+    uint8_t *p = m_cur_insn_bytes;
+    int regno_prefix_bit = 0;
+    // If we have a rex prefix byte, check to see if a B bit is set
+    if (m_wordsize == 8 && *p == 0x41) {
+        regno_prefix_bit = 1 << 3;
+        p++;
+    }
+    if (*p >= 0x58 && *p <= 0x5f) {
+        regno = (*p - 0x58) | regno_prefix_bit;
+        return true;
+    }
+    return false;
+}
+
+// popq %rbp [0x5d]
+// popl %ebp [0x5d]
+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 () {
+    uint8_t *p = m_cur_insn_bytes;
+    return (*p == 0xe8) && (*(p+1) == 0x0) && (*(p+2) == 0x0)
+                        && (*(p+3) == 0x0) && (*(p+4) == 0x0);
+}
+
 // Look for an instruction sequence storing a nonvolatile register
 // on to the stack frame.
 
@@ -608,7 +671,7 @@ AssemblyParse_x86::get_non_call_site_unw
             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() == static_cast<uint32_t>(m_lldb_sp_regnum))
+            if (row->GetCFARegister() == m_lldb_sp_regnum)
             {
                 need_to_push_row = true;
                 row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
@@ -659,7 +722,7 @@ AssemblyParse_x86::get_non_call_site_unw
         if (sub_rsp_pattern_p (stack_offset))
         {
             current_sp_bytes_offset_from_cfa += stack_offset;
-            if (row->GetCFARegister() == static_cast<uint32_t>(m_lldb_sp_regnum))
+            if (row->GetCFARegister() == m_lldb_sp_regnum)
             {
                 row->SetOffset (current_func_text_offset + insn_len);
                 row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
@@ -787,6 +850,183 @@ loopnext:
     return true;
 }
 
+bool
+AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, UnwindPlan &unwind_plan)
+{
+    // Is func address valid?
+    Address addr_start = func.GetBaseAddress();
+    if (!addr_start.IsValid())
+        return false;
+
+    // Is original unwind_plan valid?
+    // unwind_plan should have at least one row which is ABI-default (CFA register is sp),
+    // and another row in mid-function.
+    if (unwind_plan.GetRowCount() < 2)
+        return false;
+    UnwindPlan::RowSP first_row = unwind_plan.GetRowAtIndex (0);
+    if (first_row->GetOffset() != 0)
+        return false;
+    uint32_t cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext()
+                       ->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(),
+                                                              first_row->GetCFARegister());
+    if (cfa_reg != m_lldb_sp_regnum || first_row->GetCFAOffset() != m_wordsize)
+        return false;
+
+    Target *target = m_exe_ctx.GetTargetPtr();
+    m_cur_insn = func.GetBaseAddress();
+    uint64_t offset = 0;
+    int row_id = 1;
+    UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row));
+    while (func.ContainsFileAddress (m_cur_insn))
+    {
+        int insn_len;
+        if (!instruction_length (m_cur_insn, insn_len)
+            || insn_len == 0 || insn_len > kMaxInstructionByteSize)
+        {
+            // An unrecognized/junk instruction.
+            break;
+        }
+        const bool prefer_file_cache = true;
+        Error error;
+        if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
+                                insn_len, error) == static_cast<size_t>(-1))
+        {
+           // Error reading the instruction out of the file, stop scanning.
+           break;
+        }
+
+        // Advance offsets.
+        offset += insn_len;
+        m_cur_insn.SetOffset(m_cur_insn.GetOffset() + insn_len);
+
+        // If we already have one row for this instruction, we can continue.
+        while (row_id < unwind_plan.GetRowCount()
+               && unwind_plan.GetRowAtIndex (row_id)->GetOffset() <= offset)
+            row_id++;
+        UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex (row_id - 1);
+        if (original_row->GetOffset() == offset)
+        {
+            *row = *original_row;
+            continue;
+        }
+
+        if (row_id == 0) {
+            // If we are here, compiler didn't generate CFI for prologue.
+            // This won't happen to GCC or clang.
+            // In this case, bail out directly.
+            return false;
+        }
+
+        // Inspect the instruction to check if we need a new row for it.
+        cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext()
+                  ->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(),
+                                                         row->GetCFARegister());
+        if (cfa_reg == m_lldb_sp_regnum)
+        {
+            // CFA register is sp.
+
+            // call next instruction
+            //     call 0
+            //  => pop  %ebx
+            if (call_next_insn_pattern_p ())
+            {
+                row->SetOffset (offset);
+                row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
+
+                UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+                unwind_plan.InsertRow (new_row);
+                continue;
+            }
+
+            // push/pop register
+            int regno;
+            if (push_reg_p (regno)) {
+                row->SetOffset (offset);
+                row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
+
+                UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+                unwind_plan.InsertRow (new_row);
+                continue;
+            }
+            if (pop_reg_p (regno)) {
+                // Technically, this might be a nonvolatile register recover in epilogue.
+                // We should reset RegisterInfo for the register.
+                // But in practice, previous rule for the register is still valid...
+                // So we ignore this case.
+
+                row->SetOffset (offset);
+                row->SetCFAOffset (-m_wordsize + row->GetCFAOffset());
+
+                UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+                unwind_plan.InsertRow (new_row);
+                continue;
+            }
+
+            // push imm
+            if (push_imm_pattern_p ()) {
+                row->SetOffset (offset);
+                row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
+                UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+                unwind_plan.InsertRow (new_row);
+                continue;
+            }
+
+            // add/sub %rsp/%esp
+            int amount;
+            if (add_rsp_pattern_p (amount)) {
+                row->SetOffset (offset);
+                row->SetCFAOffset (-amount + row->GetCFAOffset());
+
+                UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+                unwind_plan.InsertRow (new_row);
+                continue;
+            }
+            if (sub_rsp_pattern_p (amount)) {
+                row->SetOffset (offset);
+                row->SetCFAOffset (amount + row->GetCFAOffset());
+
+                UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+                unwind_plan.InsertRow (new_row);
+                continue;
+            }
+        }
+        else if (cfa_reg == m_lldb_fp_regnum)
+        {
+            // CFA register is fp.
+
+            // The only case we care about is epilogue:
+            //     [0x5d] pop %rbp/%ebp
+            //  => [0xc3] ret
+            if (pop_rbp_pattern_p ())
+            {
+                if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
+                                        1, error) != static_cast<size_t>(-1)
+                    && ret_pattern_p ())
+                {
+                    row->SetOffset (offset);
+                    row->SetCFARegister (first_row->GetCFARegister());
+                    row->SetCFAOffset (m_wordsize);
+
+                    UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+                    unwind_plan.InsertRow (new_row);
+                    continue;
+                }
+            }
+        }
+        else
+        {
+            // CFA register is not sp or fp.
+
+            // This must be hand-written assembly.
+            // Just trust eh_frame and assume we have finished.
+            break;
+        }
+    }
+
+    unwind_plan.SetPlanValidAddressRange (func);
+    return true;
+}
+
 /* The "fast unwind plan" is valid for functions that follow the usual convention of 
    using the frame pointer register (ebp, rbp), i.e. the function prologue looks like
      push   %rbp      [0x55]
@@ -946,6 +1186,14 @@ UnwindAssembly_x86::GetNonCallSiteUnwind
 }
 
 bool
+UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& thread, UnwindPlan& unwind_plan)
+{
+    ExecutionContext exe_ctx (thread.shared_from_this());
+    AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
+    return asm_parse.augment_unwind_plan_from_call_site (func, unwind_plan);
+}
+
+bool
 UnwindAssembly_x86::GetFastUnwindPlan (AddressRange& func, Thread& thread, UnwindPlan &unwind_plan)
 {
     ExecutionContext exe_ctx (thread.shared_from_this());

Modified: lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h?rev=216406&r1=216405&r2=216406&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h Mon Aug 25 15:29:09 2014
@@ -27,6 +27,11 @@ public:
                                           lldb_private::UnwindPlan& unwind_plan);
 
     virtual bool
+    AugmentUnwindPlanFromCallSite (lldb_private::AddressRange& func,
+                                   lldb_private::Thread& thread,
+                                   lldb_private::UnwindPlan& unwind_plan);
+
+    virtual bool
     GetFastUnwindPlan (lldb_private::AddressRange& func, 
                        lldb_private::Thread& thread, 
                        lldb_private::UnwindPlan &unwind_plan);

Modified: lldb/trunk/source/Symbol/FuncUnwinders.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/FuncUnwinders.cpp?rev=216406&r1=216405&r2=216406&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/FuncUnwinders.cpp (original)
+++ lldb/trunk/source/Symbol/FuncUnwinders.cpp Mon Aug 25 15:29:09 2014
@@ -32,7 +32,7 @@ FuncUnwinders::FuncUnwinders
 ) : 
     m_unwind_table(unwind_table), 
     m_range(range), 
-    m_mutex (Mutex::eMutexTypeNormal),
+    m_mutex (Mutex::eMutexTypeRecursive),
     m_unwind_plan_call_site_sp (), 
     m_unwind_plan_non_call_site_sp (), 
     m_unwind_plan_fast_sp (), 
@@ -94,7 +94,7 @@ FuncUnwinders::GetUnwindPlanAtCallSite (
 }
 
 UnwindPlanSP
-FuncUnwinders::GetUnwindPlanAtNonCallSite (Thread& thread)
+FuncUnwinders::GetUnwindPlanAtNonCallSite (Target& target, Thread& thread, int current_offset)
 {
     // Lock the mutex to ensure we can always give out the most appropriate
     // information. We want to make sure if someone requests an unwind
@@ -114,6 +114,17 @@ FuncUnwinders::GetUnwindPlanAtNonCallSit
         UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
         if (assembly_profiler_sp)
         {
+            if (target.GetArchitecture().GetCore() == ArchSpec::eCore_x86_32_i386
+                || target.GetArchitecture().GetCore() == ArchSpec::eCore_x86_64_x86_64)
+            {
+                // For 0th frame on i386 & x86_64, we fetch eh_frame and try using assembly profiler
+                // to augment it into asynchronous unwind table.
+                GetUnwindPlanAtCallSite(current_offset);
+                if (m_unwind_plan_call_site_sp
+                    && assembly_profiler_sp->AugmentUnwindPlanFromCallSite(m_range, thread, *m_unwind_plan_call_site_sp))
+                    return m_unwind_plan_call_site_sp;
+            }
+
             m_unwind_plan_non_call_site_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
             if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *m_unwind_plan_non_call_site_sp))
                 m_unwind_plan_non_call_site_sp.reset();

Modified: lldb/trunk/source/Symbol/UnwindPlan.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/UnwindPlan.cpp?rev=216406&r1=216405&r2=216406&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/UnwindPlan.cpp (original)
+++ lldb/trunk/source/Symbol/UnwindPlan.cpp Mon Aug 25 15:29:09 2014
@@ -313,6 +313,19 @@ UnwindPlan::AppendRow (const UnwindPlan:
         m_row_list.back() = row_sp;
 }
 
+void
+UnwindPlan::InsertRow (const UnwindPlan::RowSP &row_sp)
+{
+    collection::iterator it = m_row_list.begin();
+    while (it != m_row_list.end()) {
+        RowSP row = *it;
+        if (row->GetOffset() > row_sp->GetOffset())
+            break;
+        it++;
+    }
+    m_row_list.insert(it, row_sp);
+}
+
 UnwindPlan::RowSP
 UnwindPlan::GetRowForFunctionOffset (int offset) const
 {





More information about the lldb-commits mailing list