| //===-- ThreadPlanCallOnFunctionExit.cpp ------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "lldb/Target/ThreadPlanCallOnFunctionExit.h" |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| ThreadPlanCallOnFunctionExit::ThreadPlanCallOnFunctionExit( |
| Thread &thread, const Callback &callback) |
| : ThreadPlan(ThreadPlanKind::eKindGeneric, "CallOnFunctionExit", thread, |
| eVoteNoOpinion, eVoteNoOpinion // TODO check with Jim on these |
| ), |
| m_callback(callback) { |
| // We are not a user-generated plan. |
| SetIsMasterPlan(false); |
| } |
| |
| void ThreadPlanCallOnFunctionExit::DidPush() { |
| // We now want to queue the "step out" thread plan so it executes and |
| // completes. |
| |
| // Set stop vote to eVoteNo. |
| m_step_out_threadplan_sp = GetThread().QueueThreadPlanForStepOut( |
| false, // abort other plans |
| nullptr, // addr_context |
| true, // first instruction |
| true, // stop other threads |
| eVoteNo, // do not say "we're stopping" |
| eVoteNoOpinion, // don't care about |
| // run state broadcasting |
| 0, // frame_idx |
| eLazyBoolCalculate // avoid code w/o debinfo |
| ); |
| } |
| |
| // ------------------------------------------------------------------------- |
| // ThreadPlan API |
| // ------------------------------------------------------------------------- |
| |
| void ThreadPlanCallOnFunctionExit::GetDescription( |
| Stream *s, lldb::DescriptionLevel level) { |
| if (!s) |
| return; |
| s->Printf("Running until completion of current function, then making " |
| "callback."); |
| } |
| |
| bool ThreadPlanCallOnFunctionExit::ValidatePlan(Stream *error) { |
| // We'll say we're always good since I don't know what would make this |
| // invalid. |
| return true; |
| } |
| |
| bool ThreadPlanCallOnFunctionExit::ShouldStop(Event *event_ptr) { |
| // If this is where we find out that an internal stop came in, then: Check if |
| // the step-out plan completed. If it did, then we want to run the callback |
| // here (our reason for living...) |
| if (m_step_out_threadplan_sp && m_step_out_threadplan_sp->IsPlanComplete()) { |
| m_callback(); |
| |
| // We no longer need the pointer to the step-out thread plan. |
| m_step_out_threadplan_sp.reset(); |
| |
| // Indicate that this plan is done and can be discarded. |
| SetPlanComplete(); |
| |
| // We're done now, but we want to return false so that we don't cause the |
| // thread to really stop. |
| } |
| |
| return false; |
| } |
| |
| bool ThreadPlanCallOnFunctionExit::WillStop() { |
| // The code looks like the return value is ignored via ThreadList:: |
| // ShouldStop(). This is called when we really are going to stop. We don't |
| // care and don't need to do anything here. |
| return false; |
| } |
| |
| bool ThreadPlanCallOnFunctionExit::DoPlanExplainsStop(Event *event_ptr) { |
| // We don't ever explain a stop. The only stop that is relevant to us |
| // directly is the step_out plan we added to do the heavy lifting of getting |
| // us past the current method. |
| return false; |
| } |
| |
| lldb::StateType ThreadPlanCallOnFunctionExit::GetPlanRunState() { |
| // This value doesn't matter - we'll never be the top thread plan, so nobody |
| // will ask us this question. |
| return eStateRunning; |
| } |