1 | //===-- ThreadPlanCallOnFunctionExit.cpp ----------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "lldb/Target/ThreadPlanCallOnFunctionExit.h" |
10 | |
11 | using namespace lldb; |
12 | using namespace lldb_private; |
13 | |
14 | ThreadPlanCallOnFunctionExit::ThreadPlanCallOnFunctionExit( |
15 | Thread &thread, const Callback &callback) |
16 | : ThreadPlan(ThreadPlanKind::eKindGeneric, "CallOnFunctionExit" , thread, |
17 | eVoteNoOpinion, eVoteNoOpinion // TODO check with Jim on these |
18 | ), |
19 | m_callback(callback) { |
20 | // We are not a user-generated plan. |
21 | SetIsControllingPlan(false); |
22 | } |
23 | |
24 | void ThreadPlanCallOnFunctionExit::DidPush() { |
25 | // We now want to queue the "step out" thread plan so it executes and |
26 | // completes. |
27 | |
28 | // Set stop vote to eVoteNo. |
29 | Status status; |
30 | m_step_out_threadplan_sp = GetThread().QueueThreadPlanForStepOut( |
31 | abort_other_plans: false, // abort other plans |
32 | addr_context: nullptr, // addr_context |
33 | first_insn: true, // first instruction |
34 | stop_other_threads: true, // stop other threads |
35 | report_stop_vote: eVoteNo, // do not say "we're stopping" |
36 | report_run_vote: eVoteNoOpinion, // don't care about run state broadcasting |
37 | frame_idx: 0, // frame_idx |
38 | status, // status |
39 | step_out_avoids_code_without_debug_info: eLazyBoolCalculate // avoid code w/o debinfo |
40 | ); |
41 | } |
42 | |
43 | // ThreadPlan API |
44 | |
45 | void ThreadPlanCallOnFunctionExit::GetDescription( |
46 | Stream *s, lldb::DescriptionLevel level) { |
47 | if (!s) |
48 | return; |
49 | s->Printf(format: "Running until completion of current function, then making " |
50 | "callback." ); |
51 | } |
52 | |
53 | bool ThreadPlanCallOnFunctionExit::ValidatePlan(Stream *error) { |
54 | // We'll say we're always good since I don't know what would make this |
55 | // invalid. |
56 | return true; |
57 | } |
58 | |
59 | bool ThreadPlanCallOnFunctionExit::ShouldStop(Event *event_ptr) { |
60 | // If this is where we find out that an internal stop came in, then: Check if |
61 | // the step-out plan completed. If it did, then we want to run the callback |
62 | // here (our reason for living...) |
63 | if (m_step_out_threadplan_sp && m_step_out_threadplan_sp->IsPlanComplete()) { |
64 | m_callback(); |
65 | |
66 | // We no longer need the pointer to the step-out thread plan. |
67 | m_step_out_threadplan_sp.reset(); |
68 | |
69 | // Indicate that this plan is done and can be discarded. |
70 | SetPlanComplete(); |
71 | |
72 | // We're done now, but we want to return false so that we don't cause the |
73 | // thread to really stop. |
74 | } |
75 | |
76 | return false; |
77 | } |
78 | |
79 | bool ThreadPlanCallOnFunctionExit::WillStop() { |
80 | // The code looks like the return value is ignored via ThreadList:: |
81 | // ShouldStop(). This is called when we really are going to stop. We don't |
82 | // care and don't need to do anything here. |
83 | return false; |
84 | } |
85 | |
86 | bool ThreadPlanCallOnFunctionExit::DoPlanExplainsStop(Event *event_ptr) { |
87 | // We don't ever explain a stop. The only stop that is relevant to us |
88 | // directly is the step_out plan we added to do the heavy lifting of getting |
89 | // us past the current method. |
90 | return false; |
91 | } |
92 | |
93 | lldb::StateType ThreadPlanCallOnFunctionExit::GetPlanRunState() { |
94 | // This value doesn't matter - we'll never be the top thread plan, so nobody |
95 | // will ask us this question. |
96 | return eStateRunning; |
97 | } |
98 | |