1 //===-- ThreadPlanPython.cpp ------------------------------------*- C++ -*-===//
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/ThreadPlan.h"
10 
11 #include "lldb/Core/Debugger.h"
12 #include "lldb/Interpreter/CommandInterpreter.h"
13 #include "lldb/Interpreter/ScriptInterpreter.h"
14 #include "lldb/Target/Process.h"
15 #include "lldb/Target/RegisterContext.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Target/Thread.h"
18 #include "lldb/Target/ThreadPlan.h"
19 #include "lldb/Target/ThreadPlanPython.h"
20 #include "lldb/Utility/Log.h"
21 #include "lldb/Utility/State.h"
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 
26 //----------------------------------------------------------------------
27 // ThreadPlanPython
28 //----------------------------------------------------------------------
29 
30 ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name)
31     : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread,
32                  eVoteNoOpinion, eVoteNoOpinion),
33       m_class_name(class_name), m_did_push(false) {
34   SetIsMasterPlan(true);
35   SetOkayToDiscard(true);
36   SetPrivate(false);
37 }
38 
39 ThreadPlanPython::~ThreadPlanPython() {
40   // FIXME, do I need to decrement the ref count on this implementation object
41   // to make it go away?
42 }
43 
44 bool ThreadPlanPython::ValidatePlan(Stream *error) {
45   if (!m_did_push)
46     return true;
47 
48   if (!m_implementation_sp) {
49     if (error)
50       error->Printf("Python thread plan does not have an implementation");
51     return false;
52   }
53 
54   return true;
55 }
56 
57 void ThreadPlanPython::DidPush() {
58   // We set up the script side in DidPush, so that it can push other plans in
59   // the constructor, and doesn't have to care about the details of DidPush.
60   m_did_push = true;
61   if (!m_class_name.empty()) {
62     ScriptInterpreter *script_interp = m_thread.GetProcess()
63                                            ->GetTarget()
64                                            .GetDebugger()
65                                            .GetCommandInterpreter()
66                                            .GetScriptInterpreter();
67     if (script_interp) {
68       m_implementation_sp = script_interp->CreateScriptedThreadPlan(
69           m_class_name.c_str(), this->shared_from_this());
70     }
71   }
72 }
73 
74 bool ThreadPlanPython::ShouldStop(Event *event_ptr) {
75   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
76   if (log)
77     log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
78                 m_class_name.c_str());
79 
80   bool should_stop = true;
81   if (m_implementation_sp) {
82     ScriptInterpreter *script_interp = m_thread.GetProcess()
83                                            ->GetTarget()
84                                            .GetDebugger()
85                                            .GetCommandInterpreter()
86                                            .GetScriptInterpreter();
87     if (script_interp) {
88       bool script_error;
89       should_stop = script_interp->ScriptedThreadPlanShouldStop(
90           m_implementation_sp, event_ptr, script_error);
91       if (script_error)
92         SetPlanComplete(false);
93     }
94   }
95   return should_stop;
96 }
97 
98 bool ThreadPlanPython::IsPlanStale() {
99   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
100   if (log)
101     log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
102                 m_class_name.c_str());
103 
104   bool is_stale = true;
105   if (m_implementation_sp) {
106     ScriptInterpreter *script_interp = m_thread.GetProcess()
107                                            ->GetTarget()
108                                            .GetDebugger()
109                                            .GetCommandInterpreter()
110                                            .GetScriptInterpreter();
111     if (script_interp) {
112       bool script_error;
113       is_stale = script_interp->ScriptedThreadPlanIsStale(m_implementation_sp,
114                                                           script_error);
115       if (script_error)
116         SetPlanComplete(false);
117     }
118   }
119   return is_stale;
120 }
121 
122 bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) {
123   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
124   if (log)
125     log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
126                 m_class_name.c_str());
127 
128   bool explains_stop = true;
129   if (m_implementation_sp) {
130     ScriptInterpreter *script_interp = m_thread.GetProcess()
131                                            ->GetTarget()
132                                            .GetDebugger()
133                                            .GetCommandInterpreter()
134                                            .GetScriptInterpreter();
135     if (script_interp) {
136       bool script_error;
137       explains_stop = script_interp->ScriptedThreadPlanExplainsStop(
138           m_implementation_sp, event_ptr, script_error);
139       if (script_error)
140         SetPlanComplete(false);
141     }
142   }
143   return explains_stop;
144 }
145 
146 bool ThreadPlanPython::MischiefManaged() {
147   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
148   if (log)
149     log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
150                 m_class_name.c_str());
151   bool mischief_managed = true;
152   if (m_implementation_sp) {
153     // I don't really need mischief_managed, since it's simpler to just call
154     // SetPlanComplete in should_stop.
155     mischief_managed = IsPlanComplete();
156     if (mischief_managed)
157       m_implementation_sp.reset();
158   }
159   return mischief_managed;
160 }
161 
162 lldb::StateType ThreadPlanPython::GetPlanRunState() {
163   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
164   if (log)
165     log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
166                 m_class_name.c_str());
167   lldb::StateType run_state = eStateRunning;
168   if (m_implementation_sp) {
169     ScriptInterpreter *script_interp = m_thread.GetProcess()
170                                            ->GetTarget()
171                                            .GetDebugger()
172                                            .GetCommandInterpreter()
173                                            .GetScriptInterpreter();
174     if (script_interp) {
175       bool script_error;
176       run_state = script_interp->ScriptedThreadPlanGetRunState(
177           m_implementation_sp, script_error);
178     }
179   }
180   return run_state;
181 }
182 
183 // The ones below are not currently exported to Python.
184 
185 bool ThreadPlanPython::StopOthers() {
186   // For now Python plans run all threads, but we should add some controls for
187   // this.
188   return false;
189 }
190 
191 void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) {
192   s->Printf("Python thread plan implemented by class %s.",
193             m_class_name.c_str());
194 }
195 
196 bool ThreadPlanPython::WillStop() {
197   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
198   if (log)
199     log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
200                 m_class_name.c_str());
201   return true;
202 }
203