forked from OSchip/llvm-project
Have the FuncUnwinder object request & provide an architecture-defined
UnwindPlan for unwinding from the first instruction of an otherwise unknown function call (GetUnwindPlanArchitectureDefaultAtFunctionEntry()). Update RegisterContextLLDB::GetFullUnwindPlanForFrame() to detect the case of a frame 0 at address 0x0 which indicates that we jumped through a NULL function pointer. Use the ABI's FunctionEntryUnwindPlan to find the caller frame. These changes make it so lldb can identify the calling frame correctly in code like int main () { void (*f)(void) = 0; f(); } llvm-svn: 139760
This commit is contained in:
parent
e1dadb831a
commit
995cd3a514
|
@ -55,6 +55,9 @@ public:
|
|||
lldb::UnwindPlanSP
|
||||
GetUnwindPlanArchitectureDefault (lldb_private::Thread& thread);
|
||||
|
||||
lldb::UnwindPlanSP
|
||||
GetUnwindPlanArchitectureDefaultAtFunctionEntry (lldb_private::Thread& thread);
|
||||
|
||||
Address&
|
||||
GetFirstNonPrologueInsn (Target& target);
|
||||
|
||||
|
@ -78,11 +81,14 @@ private:
|
|||
lldb::UnwindPlanSP m_unwind_plan_non_call_site_sp;
|
||||
lldb::UnwindPlanSP m_unwind_plan_fast_sp;
|
||||
lldb::UnwindPlanSP m_unwind_plan_arch_default_sp;
|
||||
lldb::UnwindPlanSP m_unwind_plan_arch_default_at_func_entry_sp;
|
||||
|
||||
bool m_tried_unwind_at_call_site:1,
|
||||
m_tried_unwind_at_non_call_site:1,
|
||||
m_tried_unwind_fast:1,
|
||||
m_tried_unwind_arch_default:1;
|
||||
m_tried_unwind_arch_default:1,
|
||||
m_tried_unwind_arch_default_at_func_entry:1;
|
||||
|
||||
|
||||
Address m_first_non_prologue_insn;
|
||||
|
||||
|
|
|
@ -538,7 +538,7 @@ ABIMacOSX_arm::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
|
|||
|
||||
// All other registers are the same.
|
||||
|
||||
unwind_plan.SetSourceName (pluginName);
|
||||
unwind_plan.SetSourceName ("arm at-func-entry default");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -803,7 +803,7 @@ ABIMacOSX_i386::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
|
|||
row.SetCFAOffset (4);
|
||||
row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
|
||||
unwind_plan.AppendRow (row);
|
||||
unwind_plan.SetSourceName (pluginName);
|
||||
unwind_plan.SetSourceName ("i386 at-func-entry default");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -661,7 +661,7 @@ ABISysV_x86_64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
|
|||
row.SetCFAOffset (8);
|
||||
row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -8, false);
|
||||
unwind_plan.AppendRow (row);
|
||||
unwind_plan.SetSourceName (pluginName);
|
||||
unwind_plan.SetSourceName ("x86_64 at-func-entry default");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -552,7 +552,19 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
|
|||
m_all_registers_available = true;
|
||||
}
|
||||
|
||||
// No Module for the current pc, try using the architecture default unwind.
|
||||
// If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer) so the pc is 0x0
|
||||
// in the zeroth frame, we need to use the "unwind at first instruction" arch default UnwindPlan
|
||||
if (behaves_like_zeroth_frame
|
||||
&& m_current_pc.IsValid()
|
||||
&& m_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()) == 0)
|
||||
{
|
||||
unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
|
||||
abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
|
||||
m_frame_type = eNormalFrame;
|
||||
return unwind_plan_sp;
|
||||
}
|
||||
|
||||
// No Module fm_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()or the current pc, try using the architecture default unwind.
|
||||
if (!m_current_pc.IsValid() || m_current_pc.GetModule() == NULL || m_current_pc.GetModule()->GetObjectFile() == NULL)
|
||||
{
|
||||
m_frame_type = eNormalFrame;
|
||||
|
|
|
@ -42,6 +42,7 @@ FuncUnwinders::FuncUnwinders
|
|||
m_tried_unwind_at_non_call_site (false),
|
||||
m_tried_unwind_fast (false),
|
||||
m_tried_unwind_arch_default (false),
|
||||
m_tried_unwind_arch_default_at_func_entry (false),
|
||||
m_first_non_prologue_insn()
|
||||
{
|
||||
}
|
||||
|
@ -181,6 +182,43 @@ FuncUnwinders::GetUnwindPlanArchitectureDefault (Thread& thread)
|
|||
return m_unwind_plan_arch_default_sp;
|
||||
}
|
||||
|
||||
UnwindPlanSP
|
||||
FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry (Thread& thread)
|
||||
{
|
||||
// Lock the mutex to ensure we can always give out the most appropriate
|
||||
// information. We want to make sure if someone requests an unwind
|
||||
// plan, that they get one and don't run into a race condition where one
|
||||
// thread has started to create the unwind plan and has put it into
|
||||
// the auto_ptr member variable, and have another thread enter this function
|
||||
// and return the partially filled pointer contained in the auto_ptr.
|
||||
// We also want to make sure that we lock out other unwind plans from
|
||||
// being accessed until this one is done creating itself in case someone
|
||||
// had some code like:
|
||||
// UnwindPlan *best_unwind_plan = ...GetUnwindPlanAtCallSite (...)
|
||||
// if (best_unwind_plan == NULL)
|
||||
// best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
|
||||
Mutex::Locker locker (m_mutex);
|
||||
if (m_tried_unwind_arch_default_at_func_entry == false && m_unwind_plan_arch_default_at_func_entry_sp.get() == NULL)
|
||||
{
|
||||
m_tried_unwind_arch_default_at_func_entry = true;
|
||||
Address current_pc;
|
||||
Target *target = thread.CalculateTarget();
|
||||
if (target)
|
||||
{
|
||||
ABI *abi = thread.GetProcess().GetABI().get();
|
||||
if (abi)
|
||||
{
|
||||
m_unwind_plan_arch_default_at_func_entry_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
|
||||
if (m_unwind_plan_arch_default_at_func_entry_sp)
|
||||
abi->CreateFunctionEntryUnwindPlan(*m_unwind_plan_arch_default_at_func_entry_sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_unwind_plan_arch_default_sp;
|
||||
}
|
||||
|
||||
|
||||
Address&
|
||||
FuncUnwinders::GetFirstNonPrologueInsn (Target& target)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue