forked from OSchip/llvm-project
Added support for stepping out of a frame. If you have 10 stack frames, and you
select frame #3, you can then do a step out and be able to go directly to the frame above frame #3! Added StepOverUntil and StepOutOfFrame to the SBThread API to allow more powerful stepping. llvm-svn: 123970
This commit is contained in:
parent
47ff14b091
commit
481cef25dc
|
@ -72,17 +72,18 @@ public:
|
|||
GetDescription (lldb::SBStream &description) const;
|
||||
|
||||
protected:
|
||||
|
||||
#ifndef SWIG
|
||||
friend class SBArguments;
|
||||
friend class SBDebugger;
|
||||
friend class SBCommunication;
|
||||
friend class SBHostOS;
|
||||
friend class SBInputReader;
|
||||
friend class SBProcess;
|
||||
friend class SBThread;
|
||||
friend class SBTarget;
|
||||
friend class SBValue;
|
||||
|
||||
#ifndef SWIG
|
||||
|
||||
lldb_private::Error *
|
||||
get();
|
||||
|
||||
|
|
|
@ -146,6 +146,9 @@ private:
|
|||
lldb_private::StackFrame *
|
||||
get() const;
|
||||
|
||||
const lldb::StackFrameSP &
|
||||
get_sp() const;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -84,9 +84,17 @@ public:
|
|||
void
|
||||
StepOut ();
|
||||
|
||||
void
|
||||
StepOutOfFrame (lldb::SBFrame &frame);
|
||||
|
||||
void
|
||||
StepInstruction(bool step_over);
|
||||
|
||||
SBError
|
||||
StepOverUntil (lldb::SBFrame &frame,
|
||||
lldb::SBFileSpec &file_spec,
|
||||
uint32_t line);
|
||||
|
||||
void
|
||||
RunToAddress (lldb::addr_t addr);
|
||||
|
||||
|
|
|
@ -481,8 +481,9 @@ public:
|
|||
SymbolContext *addr_context,
|
||||
bool first_insn,
|
||||
bool stop_other_threads,
|
||||
lldb::Vote stop_vote = lldb::eVoteYes,
|
||||
lldb::Vote run_vote = lldb::eVoteNoOpinion);
|
||||
lldb::Vote stop_vote, // = lldb::eVoteYes,
|
||||
lldb::Vote run_vote, // = lldb::eVoteNoOpinion);
|
||||
uint32_t frame_idx);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Gets the plan used to step through the code that steps from a function
|
||||
|
@ -529,7 +530,8 @@ public:
|
|||
QueueThreadPlanForStepUntil (bool abort_other_plans,
|
||||
lldb::addr_t *address_list,
|
||||
size_t num_addresses,
|
||||
bool stop_others);
|
||||
bool stop_others,
|
||||
uint32_t frame_idx);
|
||||
|
||||
virtual ThreadPlan *
|
||||
QueueThreadPlanForCallFunction (bool abort_other_plans,
|
||||
|
|
|
@ -40,13 +40,14 @@ public:
|
|||
bool first_insn,
|
||||
bool stop_others,
|
||||
lldb::Vote stop_vote,
|
||||
lldb::Vote run_vote);
|
||||
lldb::Vote run_vote,
|
||||
uint32_t frame_idx);
|
||||
protected:
|
||||
|
||||
private:
|
||||
SymbolContext *m_step_from_context;
|
||||
lldb::addr_t m_step_from_insn;
|
||||
uint64_t m_stack_depth;
|
||||
uint32_t m_stack_depth;
|
||||
lldb::break_id_t m_return_bp_id;
|
||||
lldb::addr_t m_return_addr;
|
||||
bool m_first_insn;
|
||||
|
@ -58,7 +59,8 @@ private:
|
|||
bool first_insn,
|
||||
bool stop_others,
|
||||
lldb::Vote stop_vote,
|
||||
lldb::Vote run_vote);
|
||||
lldb::Vote run_vote,
|
||||
uint32_t frame_idx);
|
||||
|
||||
// Need an appropriate marker for the current stack so we can tell step out
|
||||
// from step in.
|
||||
|
|
|
@ -45,7 +45,8 @@ protected:
|
|||
ThreadPlanStepUntil (Thread &thread,
|
||||
lldb::addr_t *address_list,
|
||||
size_t num_addresses,
|
||||
bool stop_others);
|
||||
bool stop_others,
|
||||
uint32_t frame_idx = 0);
|
||||
void AnalyzeStop(void);
|
||||
|
||||
private:
|
||||
|
@ -69,7 +70,8 @@ private:
|
|||
Thread::QueueThreadPlanForStepUntil (bool abort_other_plans,
|
||||
lldb::addr_t *address_list,
|
||||
size_t num_addresses,
|
||||
bool stop_others);
|
||||
bool stop_others,
|
||||
uint32_t frame_idx);
|
||||
|
||||
// Need an appropriate marker for the current stack so we can tell step out
|
||||
// from step in.
|
||||
|
|
|
@ -511,6 +511,11 @@ SBFrame::get() const
|
|||
return m_opaque_sp.get();
|
||||
}
|
||||
|
||||
const lldb::StackFrameSP &
|
||||
SBFrame::get_sp() const
|
||||
{
|
||||
return m_opaque_sp;
|
||||
}
|
||||
|
||||
SBThread
|
||||
SBFrame::GetThread () const
|
||||
|
|
|
@ -492,7 +492,52 @@ SBThread::StepOut ()
|
|||
bool abort_other_plans = true;
|
||||
bool stop_other_threads = true;
|
||||
|
||||
m_opaque_sp->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, stop_other_threads, eVoteYes, eVoteNoOpinion);
|
||||
m_opaque_sp->QueueThreadPlanForStepOut (abort_other_plans,
|
||||
NULL,
|
||||
false,
|
||||
stop_other_threads,
|
||||
eVoteYes,
|
||||
eVoteNoOpinion,
|
||||
0);
|
||||
|
||||
Process &process = m_opaque_sp->GetProcess();
|
||||
process.GetThreadList().SetSelectedThreadByID (m_opaque_sp->GetID());
|
||||
Error error (process.Resume());
|
||||
if (error.Success())
|
||||
{
|
||||
// If we are doing synchronous mode, then wait for the
|
||||
// process to stop yet again!
|
||||
if (process.GetTarget().GetDebugger().GetAsyncExecution () == false)
|
||||
process.WaitForProcessToStop (NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SBThread::StepOutOfFrame (lldb::SBFrame &sb_frame)
|
||||
{
|
||||
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
|
||||
if (log)
|
||||
{
|
||||
SBStream frame_desc_strm;
|
||||
sb_frame.GetDescription (frame_desc_strm);
|
||||
log->Printf ("SBThread(%p)::StepOutOfFrame (frame = SBFrame(%p): %s)", m_opaque_sp.get(), sb_frame.get(), frame_desc_strm.GetData());
|
||||
}
|
||||
|
||||
if (m_opaque_sp)
|
||||
{
|
||||
Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
|
||||
bool abort_other_plans = true;
|
||||
bool stop_other_threads = true;
|
||||
|
||||
m_opaque_sp->QueueThreadPlanForStepOut (abort_other_plans,
|
||||
NULL,
|
||||
false,
|
||||
stop_other_threads,
|
||||
eVoteYes,
|
||||
eVoteNoOpinion,
|
||||
sb_frame->GetFrameIndex());
|
||||
|
||||
Process &process = m_opaque_sp->GetProcess();
|
||||
process.GetThreadList().SetSelectedThreadByID (m_opaque_sp->GetID());
|
||||
|
@ -559,9 +604,141 @@ SBThread::RunToAddress (lldb::addr_t addr)
|
|||
process.WaitForProcessToStop (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SBError
|
||||
SBThread::StepOverUntil (lldb::SBFrame &sb_frame,
|
||||
lldb::SBFileSpec &sb_file_spec,
|
||||
uint32_t line)
|
||||
{
|
||||
SBError sb_error;
|
||||
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (log)
|
||||
{
|
||||
SBStream frame_desc_strm;
|
||||
sb_frame.GetDescription (frame_desc_strm);
|
||||
sb_file_spec->GetPath (path, sizeof(path));
|
||||
log->Printf ("SBThread(%p)::StepOverUntil (frame = SBFrame(%p): %s, file+line = %s:%u)",
|
||||
m_opaque_sp.get(),
|
||||
sb_frame.get(),
|
||||
frame_desc_strm.GetData(),
|
||||
path, line);
|
||||
}
|
||||
|
||||
if (m_opaque_sp)
|
||||
{
|
||||
Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
|
||||
|
||||
if (line == 0)
|
||||
{
|
||||
sb_error.SetErrorString("invalid line argument");
|
||||
return sb_error;
|
||||
}
|
||||
|
||||
StackFrameSP frame_sp;
|
||||
if (sb_frame.IsValid())
|
||||
frame_sp = sb_frame.get_sp();
|
||||
else
|
||||
{
|
||||
frame_sp = m_opaque_sp->GetSelectedFrame ();
|
||||
if (!frame_sp)
|
||||
frame_sp = m_opaque_sp->GetStackFrameAtIndex (0);
|
||||
}
|
||||
|
||||
SymbolContext frame_sc;
|
||||
if (!frame_sp)
|
||||
{
|
||||
sb_error.SetErrorString("no valid frames in thread to step");
|
||||
return sb_error;
|
||||
}
|
||||
|
||||
// If we have a frame, get its line
|
||||
frame_sc = frame_sp->GetSymbolContext (eSymbolContextCompUnit |
|
||||
eSymbolContextFunction |
|
||||
eSymbolContextLineEntry |
|
||||
eSymbolContextSymbol );
|
||||
|
||||
if (frame_sc.comp_unit == NULL)
|
||||
{
|
||||
sb_error.SetErrorStringWithFormat("frame %u doesn't have debug information", frame_sp->GetFrameIndex());
|
||||
return sb_error;
|
||||
}
|
||||
|
||||
FileSpec step_file_spec;
|
||||
if (sb_file_spec.IsValid())
|
||||
{
|
||||
// The file spec passed in was valid, so use it
|
||||
step_file_spec = sb_file_spec.ref();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (frame_sc.line_entry.IsValid())
|
||||
step_file_spec = frame_sc.line_entry.file;
|
||||
else
|
||||
{
|
||||
sb_error.SetErrorString("invalid file argument or no file for frame");
|
||||
return sb_error;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<addr_t> step_over_until_addrs;
|
||||
const bool abort_other_plans = true;
|
||||
const bool stop_other_threads = true;
|
||||
const bool check_inlines = true;
|
||||
const bool exact = false;
|
||||
|
||||
SymbolContextList sc_list;
|
||||
const uint32_t num_matches = frame_sc.comp_unit->ResolveSymbolContext (step_file_spec, line, check_inlines, exact, eSymbolContextLineEntry, sc_list);
|
||||
if (num_matches > 0)
|
||||
{
|
||||
SymbolContext sc;
|
||||
for (uint32_t i=0; i<num_matches; ++i)
|
||||
{
|
||||
if (sc_list.GetContextAtIndex(i, sc))
|
||||
{
|
||||
addr_t step_addr = sc.line_entry.range.GetBaseAddress().GetLoadAddress(&m_opaque_sp->GetProcess().GetTarget());
|
||||
if (step_addr != LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
step_over_until_addrs.push_back(step_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (step_over_until_addrs.empty())
|
||||
{
|
||||
step_file_spec.GetPath (path, sizeof(path));
|
||||
sb_error.SetErrorStringWithFormat("No line entries for %s:u", path, line);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_opaque_sp->QueueThreadPlanForStepUntil (abort_other_plans,
|
||||
&step_over_until_addrs[0],
|
||||
step_over_until_addrs.size(),
|
||||
stop_other_threads,
|
||||
frame_sp->GetFrameIndex());
|
||||
|
||||
m_opaque_sp->GetProcess().GetThreadList().SetSelectedThreadByID (m_opaque_sp->GetID());
|
||||
sb_error.ref() = m_opaque_sp->GetProcess().Resume();
|
||||
if (sb_error->Success())
|
||||
{
|
||||
// If we are doing synchronous mode, then wait for the
|
||||
// process to stop yet again!
|
||||
if (m_opaque_sp->GetProcess().GetTarget().GetDebugger().GetAsyncExecution () == false)
|
||||
m_opaque_sp->GetProcess().WaitForProcessToStop (NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_error.SetErrorString("this SBThread object is invalid");
|
||||
}
|
||||
return sb_error;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SBThread::Suspend()
|
||||
{
|
||||
|
@ -606,10 +783,10 @@ SBThread::GetProcess ()
|
|||
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
if (log)
|
||||
{
|
||||
SBStream sstr;
|
||||
process.GetDescription (sstr);
|
||||
SBStream frame_desc_strm;
|
||||
process.GetDescription (frame_desc_strm);
|
||||
log->Printf ("SBThread(%p)::GetProcess () => SBProcess(%p): %s", m_opaque_sp.get(),
|
||||
process.get(), sstr.GetData());
|
||||
process.get(), frame_desc_strm.GetData());
|
||||
}
|
||||
|
||||
return process;
|
||||
|
@ -647,10 +824,10 @@ SBThread::GetFrameAtIndex (uint32_t idx)
|
|||
|
||||
if (log)
|
||||
{
|
||||
SBStream sstr;
|
||||
sb_frame.GetDescription (sstr);
|
||||
SBStream frame_desc_strm;
|
||||
sb_frame.GetDescription (frame_desc_strm);
|
||||
log->Printf ("SBThread(%p)::GetFrameAtIndex (idx=%d) => SBFrame(%p): %s",
|
||||
m_opaque_sp.get(), idx, sb_frame.get(), sstr.GetData());
|
||||
m_opaque_sp.get(), idx, sb_frame.get(), frame_desc_strm.GetData());
|
||||
}
|
||||
|
||||
return sb_frame;
|
||||
|
@ -670,10 +847,10 @@ SBThread::GetSelectedFrame ()
|
|||
|
||||
if (log)
|
||||
{
|
||||
SBStream sstr;
|
||||
sb_frame.GetDescription (sstr);
|
||||
SBStream frame_desc_strm;
|
||||
sb_frame.GetDescription (frame_desc_strm);
|
||||
log->Printf ("SBThread(%p)::GetSelectedFrame () => SBFrame(%p): %s",
|
||||
m_opaque_sp.get(), sb_frame.get(), sstr.GetData());
|
||||
m_opaque_sp.get(), sb_frame.get(), frame_desc_strm.GetData());
|
||||
}
|
||||
|
||||
return sb_frame;
|
||||
|
@ -698,10 +875,10 @@ SBThread::SetSelectedFrame (uint32_t idx)
|
|||
|
||||
if (log)
|
||||
{
|
||||
SBStream sstr;
|
||||
sb_frame.GetDescription (sstr);
|
||||
SBStream frame_desc_strm;
|
||||
sb_frame.GetDescription (frame_desc_strm);
|
||||
log->Printf ("SBThread(%p)::SetSelectedFrame (idx=%u) => SBFrame(%p): %s",
|
||||
m_opaque_sp.get(), idx, sb_frame.get(), sstr.GetData());
|
||||
m_opaque_sp.get(), idx, sb_frame.get(), frame_desc_strm.GetData());
|
||||
}
|
||||
return sb_frame;
|
||||
}
|
||||
|
|
|
@ -729,7 +729,13 @@ public:
|
|||
{
|
||||
ThreadPlan *new_plan;
|
||||
|
||||
new_plan = thread->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, bool_stop_other_threads, eVoteYes, eVoteNoOpinion);
|
||||
new_plan = thread->QueueThreadPlanForStepOut (abort_other_plans,
|
||||
NULL,
|
||||
false,
|
||||
bool_stop_other_threads,
|
||||
eVoteYes,
|
||||
eVoteNoOpinion,
|
||||
thread->GetSelectedFrameIndex());
|
||||
// FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over.
|
||||
// Maybe there should be a parameter to control this.
|
||||
new_plan->SetOkayToDiscard(false);
|
||||
|
@ -1208,7 +1214,7 @@ public:
|
|||
index_ptr++;
|
||||
}
|
||||
|
||||
new_plan = thread->QueueThreadPlanForStepUntil (abort_other_plans, &address_list.front(), address_list.size(), m_options.m_stop_others);
|
||||
new_plan = thread->QueueThreadPlanForStepUntil (abort_other_plans, &address_list.front(), address_list.size(), m_options.m_stop_others, thread->GetSelectedFrameIndex ());
|
||||
new_plan->SetOkayToDiscard(false);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -129,7 +129,13 @@ AppleThreadPlanStepThroughObjCTrampoline::ShouldStop (Event *event_ptr)
|
|||
log->Printf ("Implementation lookup returned msgForward function: 0x%llx, stopping.", target_addr);
|
||||
|
||||
SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext(eSymbolContextEverything);
|
||||
m_run_to_sp.reset(new ThreadPlanStepOut(m_thread, &sc, true, m_stop_others, eVoteNoOpinion, eVoteNoOpinion));
|
||||
m_run_to_sp.reset(new ThreadPlanStepOut (m_thread,
|
||||
&sc,
|
||||
true,
|
||||
m_stop_others,
|
||||
eVoteNoOpinion,
|
||||
eVoteNoOpinion,
|
||||
0));
|
||||
m_thread.QueueThreadPlan(m_run_to_sp, false);
|
||||
m_run_to_sp->SetPrivate(true);
|
||||
return false;
|
||||
|
|
|
@ -661,7 +661,12 @@ Thread::QueueFundamentalPlan (bool abort_other_plans)
|
|||
}
|
||||
|
||||
ThreadPlan *
|
||||
Thread::QueueThreadPlanForStepSingleInstruction (bool step_over, bool abort_other_plans, bool stop_other_threads)
|
||||
Thread::QueueThreadPlanForStepSingleInstruction
|
||||
(
|
||||
bool step_over,
|
||||
bool abort_other_plans,
|
||||
bool stop_other_threads
|
||||
)
|
||||
{
|
||||
ThreadPlanSP thread_plan_sp (new ThreadPlanStepInstruction (*this, step_over, stop_other_threads, eVoteNoOpinion, eVoteNoOpinion));
|
||||
QueueThreadPlan (thread_plan_sp, abort_other_plans);
|
||||
|
@ -706,10 +711,24 @@ Thread::QueueThreadPlanForStepOverBreakpointPlan (bool abort_other_plans)
|
|||
}
|
||||
|
||||
ThreadPlan *
|
||||
Thread::QueueThreadPlanForStepOut (bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
|
||||
bool stop_other_threads, Vote stop_vote, Vote run_vote)
|
||||
Thread::QueueThreadPlanForStepOut
|
||||
(
|
||||
bool abort_other_plans,
|
||||
SymbolContext *addr_context,
|
||||
bool first_insn,
|
||||
bool stop_other_threads,
|
||||
Vote stop_vote,
|
||||
Vote run_vote,
|
||||
uint32_t frame_idx
|
||||
)
|
||||
{
|
||||
ThreadPlanSP thread_plan_sp (new ThreadPlanStepOut (*this, addr_context, first_insn, stop_other_threads, stop_vote, run_vote));
|
||||
ThreadPlanSP thread_plan_sp (new ThreadPlanStepOut (*this,
|
||||
addr_context,
|
||||
first_insn,
|
||||
stop_other_threads,
|
||||
stop_vote,
|
||||
run_vote,
|
||||
frame_idx));
|
||||
QueueThreadPlan (thread_plan_sp, abort_other_plans);
|
||||
return thread_plan_sp.get();
|
||||
}
|
||||
|
@ -763,9 +782,10 @@ ThreadPlan *
|
|||
Thread::QueueThreadPlanForStepUntil (bool abort_other_plans,
|
||||
lldb::addr_t *address_list,
|
||||
size_t num_addresses,
|
||||
bool stop_other_threads)
|
||||
bool stop_other_threads,
|
||||
uint32_t frame_idx)
|
||||
{
|
||||
ThreadPlanSP thread_plan_sp (new ThreadPlanStepUntil (*this, address_list, num_addresses, stop_other_threads));
|
||||
ThreadPlanSP thread_plan_sp (new ThreadPlanStepUntil (*this, address_list, num_addresses, stop_other_threads, frame_idx));
|
||||
QueueThreadPlan (thread_plan_sp, abort_other_plans);
|
||||
return thread_plan_sp.get();
|
||||
|
||||
|
|
|
@ -270,9 +270,13 @@ ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan,
|
|||
if (should_step_out)
|
||||
{
|
||||
// FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
|
||||
return current_plan->GetThread().QueueThreadPlanForStepOut (false, NULL, true,
|
||||
return current_plan->GetThread().QueueThreadPlanForStepOut (false,
|
||||
NULL,
|
||||
true,
|
||||
current_plan->StopOthers(),
|
||||
eVoteNo, eVoteNoOpinion);
|
||||
eVoteNo,
|
||||
eVoteNoOpinion,
|
||||
0); // Frame index
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -129,7 +129,7 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
|
|||
s.Address (return_addr, m_thread.GetProcess().GetAddressByteSize());
|
||||
log->Printf("%s.", s.GetData());
|
||||
}
|
||||
m_thread.QueueThreadPlanForStepOut(false, NULL, true, m_stop_other_threads, eVoteNo, eVoteNoOpinion);
|
||||
m_thread.QueueThreadPlanForStepOut(false, NULL, true, m_stop_other_threads, eVoteNo, eVoteNoOpinion, 0);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -35,7 +35,8 @@ ThreadPlanStepOut::ThreadPlanStepOut
|
|||
bool first_insn,
|
||||
bool stop_others,
|
||||
Vote stop_vote,
|
||||
Vote run_vote
|
||||
Vote run_vote,
|
||||
uint32_t frame_idx
|
||||
) :
|
||||
ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote),
|
||||
m_step_from_context (context),
|
||||
|
@ -50,24 +51,20 @@ ThreadPlanStepOut::ThreadPlanStepOut
|
|||
// Find the return address and set a breakpoint there:
|
||||
// FIXME - can we do this more securely if we know first_insn?
|
||||
|
||||
StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
|
||||
if (return_frame)
|
||||
StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
|
||||
if (return_frame_sp)
|
||||
{
|
||||
// TODO: check for inlined frames and do the right thing...
|
||||
m_return_addr = return_frame->GetRegisterContext()->GetPC();
|
||||
m_return_addr = return_frame_sp->GetRegisterContext()->GetPC();
|
||||
Breakpoint *return_bp = m_thread.GetProcess().GetTarget().CreateBreakpoint (m_return_addr, true).get();
|
||||
if (return_bp != NULL)
|
||||
{
|
||||
return_bp->SetThreadID(m_thread.GetID());
|
||||
m_return_bp_id = return_bp->GetID();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_return_bp_id = LLDB_INVALID_BREAK_ID;
|
||||
}
|
||||
}
|
||||
|
||||
m_stack_depth = m_thread.GetStackFrameCount();
|
||||
m_stack_depth = m_thread.GetStackFrameCount() - frame_idx;
|
||||
}
|
||||
|
||||
ThreadPlanStepOut::~ThreadPlanStepOut ()
|
||||
|
@ -116,6 +113,10 @@ ThreadPlanStepOut::PlanExplainsStop ()
|
|||
BreakpointSiteSP site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (stop_info_sp->GetValue()));
|
||||
if (site_sp && site_sp->IsBreakpointAtThisSite (m_return_bp_id))
|
||||
{
|
||||
const uint32_t num_frames = m_thread.GetStackFrameCount();
|
||||
if (m_stack_depth > num_frames);
|
||||
SetPlanComplete();
|
||||
|
||||
// If there was only one owner, then we're done. But if we also hit some
|
||||
// user breakpoint on our way out, we should mark ourselves as done, but
|
||||
// also not claim to explain the stop, since it is more important to report
|
||||
|
@ -124,7 +125,6 @@ ThreadPlanStepOut::PlanExplainsStop ()
|
|||
if (site_sp->GetNumberOfOwners() == 1)
|
||||
return true;
|
||||
|
||||
SetPlanComplete();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -143,9 +143,7 @@ ThreadPlanStepOut::PlanExplainsStop ()
|
|||
bool
|
||||
ThreadPlanStepOut::ShouldStop (Event *event_ptr)
|
||||
{
|
||||
if (IsPlanComplete()
|
||||
|| m_thread.GetRegisterContext()->GetPC() == m_return_addr
|
||||
|| m_stack_depth > m_thread.GetStackFrameCount())
|
||||
if (IsPlanComplete() || m_stack_depth > m_thread.GetStackFrameCount())
|
||||
{
|
||||
SetPlanComplete();
|
||||
return true;
|
||||
|
|
|
@ -104,7 +104,13 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
|
|||
}
|
||||
else if (FrameIsYounger())
|
||||
{
|
||||
new_plan = m_thread.QueueThreadPlanForStepOut (false, NULL, true, stop_others, lldb::eVoteNo, lldb::eVoteNoOpinion);
|
||||
new_plan = m_thread.QueueThreadPlanForStepOut (false,
|
||||
NULL,
|
||||
true,
|
||||
stop_others,
|
||||
lldb::eVoteNo,
|
||||
lldb::eVoteNoOpinion,
|
||||
0);
|
||||
}
|
||||
else if (!InSymbol())
|
||||
{
|
||||
|
|
|
@ -37,7 +37,8 @@ ThreadPlanStepUntil::ThreadPlanStepUntil
|
|||
Thread &thread,
|
||||
lldb::addr_t *address_list,
|
||||
size_t num_addresses,
|
||||
bool stop_others
|
||||
bool stop_others,
|
||||
uint32_t frame_idx
|
||||
) :
|
||||
ThreadPlan (ThreadPlan::eKindStepUntil, "Step until", thread, eVoteNoOpinion, eVoteNoOpinion),
|
||||
m_stack_depth (0),
|
||||
|
@ -56,27 +57,29 @@ ThreadPlanStepUntil::ThreadPlanStepUntil
|
|||
// Stash away our "until" addresses:
|
||||
Target &target = m_thread.GetProcess().GetTarget();
|
||||
|
||||
m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
|
||||
StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (frame_idx));
|
||||
if (frame_sp)
|
||||
{
|
||||
m_step_from_insn = frame_sp->GetStackID().GetPC();
|
||||
lldb::user_id_t thread_id = m_thread.GetID();
|
||||
|
||||
// Find the return address and set a breakpoint there:
|
||||
// FIXME - can we do this more securely if we know first_insn?
|
||||
|
||||
StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
|
||||
StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
|
||||
if (return_frame_sp)
|
||||
{
|
||||
// TODO: add inline functionality
|
||||
m_return_addr = return_frame->GetRegisterContext()->GetPC();
|
||||
m_return_addr = return_frame_sp->GetStackID().GetPC();
|
||||
Breakpoint *return_bp = target.CreateBreakpoint (m_return_addr, true).get();
|
||||
if (return_bp != NULL)
|
||||
{
|
||||
return_bp->SetThreadID(thread_id);
|
||||
m_return_bp_id = return_bp->GetID();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_return_bp_id = LLDB_INVALID_BREAK_ID;
|
||||
}
|
||||
|
||||
m_stack_depth = m_thread.GetStackFrameCount();
|
||||
m_stack_depth = m_thread.GetStackFrameCount() - frame_idx;
|
||||
|
||||
// Now set breakpoints on all our return addresses:
|
||||
for (int i = 0; i < num_addresses; i++)
|
||||
|
@ -92,6 +95,7 @@ ThreadPlanStepUntil::ThreadPlanStepUntil
|
|||
m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThreadPlanStepUntil::~ThreadPlanStepUntil ()
|
||||
|
|
Loading…
Reference in New Issue