summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Fiala <todd.fiala@gmail.com>2014-08-25 20:29:09 +0000
committerTodd Fiala <todd.fiala@gmail.com>2014-08-25 20:29:09 +0000
commitcb6562cef3d840f7435ca29e0dc2c94e32af9a44 (patch)
tree3610d8118445fd8a5a407376aa42868b1dc57a49
parent360adc2488c89d67b28553fcffd33861f11487fc (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@216406 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/lldb/Symbol/FuncUnwinders.h2
-rw-r--r--include/lldb/Symbol/UnwindPlan.h3
-rw-r--r--include/lldb/Target/UnwindAssembly.h5
-rw-r--r--source/Commands/CommandObjectTarget.cpp2
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.cpp4
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp8
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h5
-rw-r--r--source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp270
-rw-r--r--source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h5
-rw-r--r--source/Symbol/FuncUnwinders.cpp15
-rw-r--r--source/Symbol/UnwindPlan.cpp13
11 files changed, 315 insertions, 17 deletions
diff --git a/include/lldb/Symbol/FuncUnwinders.h b/include/lldb/Symbol/FuncUnwinders.h
index b664bb736..0cf584239 100644
--- a/include/lldb/Symbol/FuncUnwinders.h
+++ b/include/lldb/Symbol/FuncUnwinders.h
@@ -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);
diff --git a/include/lldb/Symbol/UnwindPlan.h b/include/lldb/Symbol/UnwindPlan.h
index 6fc5ce042..e1b146fe2 100644
--- a/include/lldb/Symbol/UnwindPlan.h
+++ b/include/lldb/Symbol/UnwindPlan.h
@@ -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
diff --git a/include/lldb/Target/UnwindAssembly.h b/include/lldb/Target/UnwindAssembly.h
index 254382ac0..963949cf0 100644
--- a/include/lldb/Target/UnwindAssembly.h
+++ b/include/lldb/Target/UnwindAssembly.h
@@ -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;
diff --git a/source/Commands/CommandObjectTarget.cpp b/source/Commands/CommandObjectTarget.cpp
index c5e8826cc..24a6b9dca 100644
--- a/source/Commands/CommandObjectTarget.cpp
+++ b/source/Commands/CommandObjectTarget.cpp
@@ -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);
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
index cfbe133f1..b58e6bb60 100644
--- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -794,7 +794,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
// 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::GetFullUnwindPlanForFrame ()
// 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
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
index 42453ce72..b8d56d390 100644
--- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
+++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -285,6 +285,14 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
}
bool
+UnwindAssemblyInstEmulation::AugmentUnwindPlanFromCallSite (AddressRange& func,
+ Thread& thread,
+ UnwindPlan& unwind_plan)
+{
+ return false;
+}
+
+bool
UnwindAssemblyInstEmulation::GetFastUnwindPlan (AddressRange& func,
Thread& thread,
UnwindPlan &unwind_plan)
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
index 6a02f0a55..758c3ce2e 100644
--- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
+++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
@@ -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);
diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
index 6df4bade5..d1836bf62 100644
--- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
+++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
@@ -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;
+ uint32_t m_machine_ip_regnum;
+ uint32_t m_machine_sp_regnum;
+ uint32_t m_machine_fp_regnum;
- int m_lldb_ip_regnum;
- int m_lldb_sp_regnum;
- int m_lldb_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_p (int& amount) {
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& regno) {
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_unwind_plan (UnwindPlan &unwind_plan)
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_unwind_plan (UnwindPlan &unwind_plan)
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::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& func, Th
}
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());
diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h
index eebaa7b6c..8a4fe7c09 100644
--- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h
+++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h
@@ -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);
diff --git a/source/Symbol/FuncUnwinders.cpp b/source/Symbol/FuncUnwinders.cpp
index 4ed04a00a..d6f89bc29 100644
--- a/source/Symbol/FuncUnwinders.cpp
+++ b/source/Symbol/FuncUnwinders.cpp
@@ -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 (int current_offset)
}
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::GetUnwindPlanAtNonCallSite (Thread& thread)
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();
diff --git a/source/Symbol/UnwindPlan.cpp b/source/Symbol/UnwindPlan.cpp
index f1cb1a994..ff0468e31 100644
--- a/source/Symbol/UnwindPlan.cpp
+++ b/source/Symbol/UnwindPlan.cpp
@@ -313,6 +313,19 @@ UnwindPlan::AppendRow (const UnwindPlan::RowSP &row_sp)
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
{