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