|  | //===-- ThreadPlanCallOnFunctionExit.cpp ----------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #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. | 
|  | Status status; | 
|  | 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 | 
|  | status,            // status | 
|  | 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; | 
|  | } |