1696bd635SAlexander Shaposhnikov //===-- ThreadPlanPython.cpp ------------------------------------*- C++ -*-===//
22bdbfd50SJim Ingham //
32bdbfd50SJim Ingham //                     The LLVM Compiler Infrastructure
42bdbfd50SJim Ingham //
52bdbfd50SJim Ingham // This file is distributed under the University of Illinois Open Source
62bdbfd50SJim Ingham // License. See LICENSE.TXT for details.
72bdbfd50SJim Ingham //
82bdbfd50SJim Ingham //===----------------------------------------------------------------------===//
92bdbfd50SJim Ingham 
102bdbfd50SJim Ingham #include "lldb/Target/ThreadPlan.h"
112bdbfd50SJim Ingham 
122bdbfd50SJim Ingham #include "lldb/Core/Debugger.h"
132bdbfd50SJim Ingham #include "lldb/Interpreter/CommandInterpreter.h"
142bdbfd50SJim Ingham #include "lldb/Interpreter/ScriptInterpreter.h"
15b9c1b51eSKate Stone #include "lldb/Target/Process.h"
162bdbfd50SJim Ingham #include "lldb/Target/RegisterContext.h"
17b9c1b51eSKate Stone #include "lldb/Target/Target.h"
182bdbfd50SJim Ingham #include "lldb/Target/Thread.h"
192bdbfd50SJim Ingham #include "lldb/Target/ThreadPlan.h"
202bdbfd50SJim Ingham #include "lldb/Target/ThreadPlanPython.h"
216f9e6901SZachary Turner #include "lldb/Utility/Log.h"
22d821c997SPavel Labath #include "lldb/Utility/State.h"
232bdbfd50SJim Ingham 
242bdbfd50SJim Ingham using namespace lldb;
252bdbfd50SJim Ingham using namespace lldb_private;
262bdbfd50SJim Ingham 
272bdbfd50SJim Ingham //----------------------------------------------------------------------
282bdbfd50SJim Ingham // ThreadPlanPython
292bdbfd50SJim Ingham //----------------------------------------------------------------------
302bdbfd50SJim Ingham 
31b9c1b51eSKate Stone ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name)
32b9c1b51eSKate Stone     : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread,
33b9c1b51eSKate Stone                  eVoteNoOpinion, eVoteNoOpinion),
34*e103ae92SJonas Devlieghere       m_class_name(class_name), m_did_push(false) {
352bdbfd50SJim Ingham   SetIsMasterPlan(true);
362bdbfd50SJim Ingham   SetOkayToDiscard(true);
372bdbfd50SJim Ingham   SetPrivate(false);
382bdbfd50SJim Ingham }
392bdbfd50SJim Ingham 
40b9c1b51eSKate Stone ThreadPlanPython::~ThreadPlanPython() {
41b9c1b51eSKate Stone   // FIXME, do I need to decrement the ref count on this implementation object
42b9c1b51eSKate Stone   // to make it go away?
432bdbfd50SJim Ingham }
442bdbfd50SJim Ingham 
45b9c1b51eSKate Stone bool ThreadPlanPython::ValidatePlan(Stream *error) {
46*e103ae92SJonas Devlieghere   if (!m_did_push)
472bdbfd50SJim Ingham     return true;
48*e103ae92SJonas Devlieghere 
49*e103ae92SJonas Devlieghere   if (!m_implementation_sp) {
50*e103ae92SJonas Devlieghere     if (error)
51*e103ae92SJonas Devlieghere       error->Printf("Python thread plan does not have an implementation");
522bdbfd50SJim Ingham     return false;
532bdbfd50SJim Ingham   }
542bdbfd50SJim Ingham 
55*e103ae92SJonas Devlieghere   return true;
56*e103ae92SJonas Devlieghere }
57*e103ae92SJonas Devlieghere 
58b9c1b51eSKate Stone void ThreadPlanPython::DidPush() {
59b9c1b51eSKate Stone   // We set up the script side in DidPush, so that it can push other plans in
6005097246SAdrian Prantl   // the constructor, and doesn't have to care about the details of DidPush.
61*e103ae92SJonas Devlieghere   m_did_push = true;
62b9c1b51eSKate Stone   if (!m_class_name.empty()) {
63b9c1b51eSKate Stone     ScriptInterpreter *script_interp = m_thread.GetProcess()
64b9c1b51eSKate Stone                                            ->GetTarget()
65b9c1b51eSKate Stone                                            .GetDebugger()
66b9c1b51eSKate Stone                                            .GetCommandInterpreter()
67b9c1b51eSKate Stone                                            .GetScriptInterpreter();
68b9c1b51eSKate Stone     if (script_interp) {
69b9c1b51eSKate Stone       m_implementation_sp = script_interp->CreateScriptedThreadPlan(
70b9c1b51eSKate Stone           m_class_name.c_str(), this->shared_from_this());
712bdbfd50SJim Ingham     }
722bdbfd50SJim Ingham   }
732bdbfd50SJim Ingham }
742bdbfd50SJim Ingham 
75b9c1b51eSKate Stone bool ThreadPlanPython::ShouldStop(Event *event_ptr) {
762bdbfd50SJim Ingham   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
772bdbfd50SJim Ingham   if (log)
78b9c1b51eSKate Stone     log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
79b9c1b51eSKate Stone                 m_class_name.c_str());
802bdbfd50SJim Ingham 
812bdbfd50SJim Ingham   bool should_stop = true;
82b9c1b51eSKate Stone   if (m_implementation_sp) {
83b9c1b51eSKate Stone     ScriptInterpreter *script_interp = m_thread.GetProcess()
84b9c1b51eSKate Stone                                            ->GetTarget()
85b9c1b51eSKate Stone                                            .GetDebugger()
86b9c1b51eSKate Stone                                            .GetCommandInterpreter()
87b9c1b51eSKate Stone                                            .GetScriptInterpreter();
88b9c1b51eSKate Stone     if (script_interp) {
892bdbfd50SJim Ingham       bool script_error;
90b9c1b51eSKate Stone       should_stop = script_interp->ScriptedThreadPlanShouldStop(
91b9c1b51eSKate Stone           m_implementation_sp, event_ptr, script_error);
922bdbfd50SJim Ingham       if (script_error)
932bdbfd50SJim Ingham         SetPlanComplete(false);
942bdbfd50SJim Ingham     }
952bdbfd50SJim Ingham   }
962bdbfd50SJim Ingham   return should_stop;
972bdbfd50SJim Ingham }
982bdbfd50SJim Ingham 
99b9c1b51eSKate Stone bool ThreadPlanPython::IsPlanStale() {
100c915a7d2SJim Ingham   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
101c915a7d2SJim Ingham   if (log)
102b9c1b51eSKate Stone     log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
103b9c1b51eSKate Stone                 m_class_name.c_str());
104c915a7d2SJim Ingham 
105c915a7d2SJim Ingham   bool is_stale = true;
106b9c1b51eSKate Stone   if (m_implementation_sp) {
107b9c1b51eSKate Stone     ScriptInterpreter *script_interp = m_thread.GetProcess()
108b9c1b51eSKate Stone                                            ->GetTarget()
109b9c1b51eSKate Stone                                            .GetDebugger()
110b9c1b51eSKate Stone                                            .GetCommandInterpreter()
111b9c1b51eSKate Stone                                            .GetScriptInterpreter();
112b9c1b51eSKate Stone     if (script_interp) {
113c915a7d2SJim Ingham       bool script_error;
114b9c1b51eSKate Stone       is_stale = script_interp->ScriptedThreadPlanIsStale(m_implementation_sp,
115b9c1b51eSKate Stone                                                           script_error);
116c915a7d2SJim Ingham       if (script_error)
117c915a7d2SJim Ingham         SetPlanComplete(false);
118c915a7d2SJim Ingham     }
119c915a7d2SJim Ingham   }
120c915a7d2SJim Ingham   return is_stale;
121c915a7d2SJim Ingham }
122c915a7d2SJim Ingham 
123b9c1b51eSKate Stone bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) {
1242bdbfd50SJim Ingham   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
1252bdbfd50SJim Ingham   if (log)
126b9c1b51eSKate Stone     log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
127b9c1b51eSKate Stone                 m_class_name.c_str());
1282bdbfd50SJim Ingham 
1292bdbfd50SJim Ingham   bool explains_stop = true;
130b9c1b51eSKate Stone   if (m_implementation_sp) {
131b9c1b51eSKate Stone     ScriptInterpreter *script_interp = m_thread.GetProcess()
132b9c1b51eSKate Stone                                            ->GetTarget()
133b9c1b51eSKate Stone                                            .GetDebugger()
134b9c1b51eSKate Stone                                            .GetCommandInterpreter()
135b9c1b51eSKate Stone                                            .GetScriptInterpreter();
136b9c1b51eSKate Stone     if (script_interp) {
1372bdbfd50SJim Ingham       bool script_error;
138b9c1b51eSKate Stone       explains_stop = script_interp->ScriptedThreadPlanExplainsStop(
139b9c1b51eSKate Stone           m_implementation_sp, event_ptr, script_error);
1402bdbfd50SJim Ingham       if (script_error)
1412bdbfd50SJim Ingham         SetPlanComplete(false);
1422bdbfd50SJim Ingham     }
1432bdbfd50SJim Ingham   }
1442bdbfd50SJim Ingham   return explains_stop;
1452bdbfd50SJim Ingham }
1462bdbfd50SJim Ingham 
147b9c1b51eSKate Stone bool ThreadPlanPython::MischiefManaged() {
1482bdbfd50SJim Ingham   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
1492bdbfd50SJim Ingham   if (log)
150b9c1b51eSKate Stone     log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
151b9c1b51eSKate Stone                 m_class_name.c_str());
1522bdbfd50SJim Ingham   bool mischief_managed = true;
153b9c1b51eSKate Stone   if (m_implementation_sp) {
154b9c1b51eSKate Stone     // I don't really need mischief_managed, since it's simpler to just call
155b9c1b51eSKate Stone     // SetPlanComplete in should_stop.
1562bdbfd50SJim Ingham     mischief_managed = IsPlanComplete();
1572bdbfd50SJim Ingham     if (mischief_managed)
1582bdbfd50SJim Ingham       m_implementation_sp.reset();
1592bdbfd50SJim Ingham   }
1602bdbfd50SJim Ingham   return mischief_managed;
1612bdbfd50SJim Ingham }
1622bdbfd50SJim Ingham 
163b9c1b51eSKate Stone lldb::StateType ThreadPlanPython::GetPlanRunState() {
1642bdbfd50SJim Ingham   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
1652bdbfd50SJim Ingham   if (log)
166b9c1b51eSKate Stone     log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
1672bdbfd50SJim Ingham                 m_class_name.c_str());
1682bdbfd50SJim Ingham   lldb::StateType run_state = eStateRunning;
169b9c1b51eSKate Stone   if (m_implementation_sp) {
170b9c1b51eSKate Stone     ScriptInterpreter *script_interp = m_thread.GetProcess()
171b9c1b51eSKate Stone                                            ->GetTarget()
172b9c1b51eSKate Stone                                            .GetDebugger()
173b9c1b51eSKate Stone                                            .GetCommandInterpreter()
174b9c1b51eSKate Stone                                            .GetScriptInterpreter();
175b9c1b51eSKate Stone     if (script_interp) {
1762bdbfd50SJim Ingham       bool script_error;
177b9c1b51eSKate Stone       run_state = script_interp->ScriptedThreadPlanGetRunState(
178b9c1b51eSKate Stone           m_implementation_sp, script_error);
1792bdbfd50SJim Ingham     }
1802bdbfd50SJim Ingham   }
1812bdbfd50SJim Ingham   return run_state;
1822bdbfd50SJim Ingham }
1832bdbfd50SJim Ingham 
1842bdbfd50SJim Ingham // The ones below are not currently exported to Python.
1852bdbfd50SJim Ingham 
186b9c1b51eSKate Stone bool ThreadPlanPython::StopOthers() {
187b9c1b51eSKate Stone   // For now Python plans run all threads, but we should add some controls for
188b9c1b51eSKate Stone   // this.
1892bdbfd50SJim Ingham   return false;
1902bdbfd50SJim Ingham }
1912bdbfd50SJim Ingham 
192b9c1b51eSKate Stone void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) {
193b9c1b51eSKate Stone   s->Printf("Python thread plan implemented by class %s.",
194b9c1b51eSKate Stone             m_class_name.c_str());
1952bdbfd50SJim Ingham }
1962bdbfd50SJim Ingham 
197b9c1b51eSKate Stone bool ThreadPlanPython::WillStop() {
1982bdbfd50SJim Ingham   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
1992bdbfd50SJim Ingham   if (log)
200b9c1b51eSKate Stone     log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
201b9c1b51eSKate Stone                 m_class_name.c_str());
2022bdbfd50SJim Ingham   return true;
2032bdbfd50SJim Ingham }
204