1cfca06d7SDimitry Andric //===-- ThreadPlanCallOnFunctionExit.cpp ----------------------------------===//
214f1b3e8SDimitry Andric //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
614f1b3e8SDimitry Andric //
714f1b3e8SDimitry Andric //===----------------------------------------------------------------------===//
814f1b3e8SDimitry Andric
914f1b3e8SDimitry Andric #include "lldb/Target/ThreadPlanCallOnFunctionExit.h"
1014f1b3e8SDimitry Andric
1114f1b3e8SDimitry Andric using namespace lldb;
1214f1b3e8SDimitry Andric using namespace lldb_private;
1314f1b3e8SDimitry Andric
ThreadPlanCallOnFunctionExit(Thread & thread,const Callback & callback)1414f1b3e8SDimitry Andric ThreadPlanCallOnFunctionExit::ThreadPlanCallOnFunctionExit(
1514f1b3e8SDimitry Andric Thread &thread, const Callback &callback)
1614f1b3e8SDimitry Andric : ThreadPlan(ThreadPlanKind::eKindGeneric, "CallOnFunctionExit", thread,
1714f1b3e8SDimitry Andric eVoteNoOpinion, eVoteNoOpinion // TODO check with Jim on these
1814f1b3e8SDimitry Andric ),
1914f1b3e8SDimitry Andric m_callback(callback) {
2014f1b3e8SDimitry Andric // We are not a user-generated plan.
21c0981da4SDimitry Andric SetIsControllingPlan(false);
2214f1b3e8SDimitry Andric }
2314f1b3e8SDimitry Andric
DidPush()2414f1b3e8SDimitry Andric void ThreadPlanCallOnFunctionExit::DidPush() {
25f73363f1SDimitry Andric // We now want to queue the "step out" thread plan so it executes and
26f73363f1SDimitry Andric // completes.
2714f1b3e8SDimitry Andric
2814f1b3e8SDimitry Andric // Set stop vote to eVoteNo.
2994994d37SDimitry Andric Status status;
3014f1b3e8SDimitry Andric m_step_out_threadplan_sp = GetThread().QueueThreadPlanForStepOut(
3114f1b3e8SDimitry Andric false, // abort other plans
3214f1b3e8SDimitry Andric nullptr, // addr_context
3314f1b3e8SDimitry Andric true, // first instruction
3414f1b3e8SDimitry Andric true, // stop other threads
3514f1b3e8SDimitry Andric eVoteNo, // do not say "we're stopping"
3694994d37SDimitry Andric eVoteNoOpinion, // don't care about run state broadcasting
3714f1b3e8SDimitry Andric 0, // frame_idx
3894994d37SDimitry Andric status, // status
3914f1b3e8SDimitry Andric eLazyBoolCalculate // avoid code w/o debinfo
4014f1b3e8SDimitry Andric );
4114f1b3e8SDimitry Andric }
4214f1b3e8SDimitry Andric
4314f1b3e8SDimitry Andric // ThreadPlan API
4414f1b3e8SDimitry Andric
GetDescription(Stream * s,lldb::DescriptionLevel level)4514f1b3e8SDimitry Andric void ThreadPlanCallOnFunctionExit::GetDescription(
4614f1b3e8SDimitry Andric Stream *s, lldb::DescriptionLevel level) {
4714f1b3e8SDimitry Andric if (!s)
4814f1b3e8SDimitry Andric return;
4914f1b3e8SDimitry Andric s->Printf("Running until completion of current function, then making "
5014f1b3e8SDimitry Andric "callback.");
5114f1b3e8SDimitry Andric }
5214f1b3e8SDimitry Andric
ValidatePlan(Stream * error)5314f1b3e8SDimitry Andric bool ThreadPlanCallOnFunctionExit::ValidatePlan(Stream *error) {
5414f1b3e8SDimitry Andric // We'll say we're always good since I don't know what would make this
5514f1b3e8SDimitry Andric // invalid.
5614f1b3e8SDimitry Andric return true;
5714f1b3e8SDimitry Andric }
5814f1b3e8SDimitry Andric
ShouldStop(Event * event_ptr)5914f1b3e8SDimitry Andric bool ThreadPlanCallOnFunctionExit::ShouldStop(Event *event_ptr) {
60f73363f1SDimitry Andric // If this is where we find out that an internal stop came in, then: Check if
61f73363f1SDimitry Andric // the step-out plan completed. If it did, then we want to run the callback
62f73363f1SDimitry Andric // here (our reason for living...)
6314f1b3e8SDimitry Andric if (m_step_out_threadplan_sp && m_step_out_threadplan_sp->IsPlanComplete()) {
6414f1b3e8SDimitry Andric m_callback();
6514f1b3e8SDimitry Andric
6614f1b3e8SDimitry Andric // We no longer need the pointer to the step-out thread plan.
6714f1b3e8SDimitry Andric m_step_out_threadplan_sp.reset();
6814f1b3e8SDimitry Andric
6914f1b3e8SDimitry Andric // Indicate that this plan is done and can be discarded.
7014f1b3e8SDimitry Andric SetPlanComplete();
7114f1b3e8SDimitry Andric
72f73363f1SDimitry Andric // We're done now, but we want to return false so that we don't cause the
73f73363f1SDimitry Andric // thread to really stop.
7414f1b3e8SDimitry Andric }
7514f1b3e8SDimitry Andric
7614f1b3e8SDimitry Andric return false;
7714f1b3e8SDimitry Andric }
7814f1b3e8SDimitry Andric
WillStop()7914f1b3e8SDimitry Andric bool ThreadPlanCallOnFunctionExit::WillStop() {
8014f1b3e8SDimitry Andric // The code looks like the return value is ignored via ThreadList::
81f73363f1SDimitry Andric // ShouldStop(). This is called when we really are going to stop. We don't
82f73363f1SDimitry Andric // care and don't need to do anything here.
8314f1b3e8SDimitry Andric return false;
8414f1b3e8SDimitry Andric }
8514f1b3e8SDimitry Andric
DoPlanExplainsStop(Event * event_ptr)8614f1b3e8SDimitry Andric bool ThreadPlanCallOnFunctionExit::DoPlanExplainsStop(Event *event_ptr) {
87f73363f1SDimitry Andric // We don't ever explain a stop. The only stop that is relevant to us
88f73363f1SDimitry Andric // directly is the step_out plan we added to do the heavy lifting of getting
89f73363f1SDimitry Andric // us past the current method.
9014f1b3e8SDimitry Andric return false;
9114f1b3e8SDimitry Andric }
9214f1b3e8SDimitry Andric
GetPlanRunState()9314f1b3e8SDimitry Andric lldb::StateType ThreadPlanCallOnFunctionExit::GetPlanRunState() {
94f73363f1SDimitry Andric // This value doesn't matter - we'll never be the top thread plan, so nobody
95f73363f1SDimitry Andric // will ask us this question.
9614f1b3e8SDimitry Andric return eStateRunning;
9714f1b3e8SDimitry Andric }
98