xref: /src/contrib/llvm-project/lldb/source/Target/ThreadPlanPython.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1cfca06d7SDimitry Andric //===-- ThreadPlanPython.cpp ----------------------------------------------===//
2205afe67SEd Maste //
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
6205afe67SEd Maste //
7205afe67SEd Maste //===----------------------------------------------------------------------===//
8205afe67SEd Maste 
9205afe67SEd Maste #include "lldb/Target/ThreadPlan.h"
10205afe67SEd Maste 
11205afe67SEd Maste #include "lldb/Core/Debugger.h"
12205afe67SEd Maste #include "lldb/Interpreter/CommandInterpreter.h"
13ac9a064cSDimitry Andric #include "lldb/Interpreter/Interfaces/ScriptedThreadPlanInterface.h"
14205afe67SEd Maste #include "lldb/Interpreter/ScriptInterpreter.h"
1514f1b3e8SDimitry Andric #include "lldb/Target/Process.h"
16205afe67SEd Maste #include "lldb/Target/RegisterContext.h"
1714f1b3e8SDimitry Andric #include "lldb/Target/Target.h"
18205afe67SEd Maste #include "lldb/Target/Thread.h"
19205afe67SEd Maste #include "lldb/Target/ThreadPlan.h"
20205afe67SEd Maste #include "lldb/Target/ThreadPlanPython.h"
21145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
2274a628f7SDimitry Andric #include "lldb/Utility/Log.h"
2394994d37SDimitry Andric #include "lldb/Utility/State.h"
24205afe67SEd Maste 
25205afe67SEd Maste using namespace lldb;
26205afe67SEd Maste using namespace lldb_private;
27205afe67SEd Maste 
28205afe67SEd Maste // ThreadPlanPython
29205afe67SEd Maste 
ThreadPlanPython(Thread & thread,const char * class_name,const StructuredDataImpl & args_data)30ead24645SDimitry Andric ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name,
3177fc4c14SDimitry Andric                                    const StructuredDataImpl &args_data)
3214f1b3e8SDimitry Andric     : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread,
3314f1b3e8SDimitry Andric                  eVoteNoOpinion, eVoteNoOpinion),
34b60736ecSDimitry Andric       m_class_name(class_name), m_args_data(args_data), m_did_push(false),
35b60736ecSDimitry Andric       m_stop_others(false) {
36ac9a064cSDimitry Andric   ScriptInterpreter *interpreter = GetScriptInterpreter();
37ac9a064cSDimitry Andric   if (!interpreter) {
38ac9a064cSDimitry Andric     SetPlanComplete(false);
39ac9a064cSDimitry Andric     // FIXME: error handling
40ac9a064cSDimitry Andric     // error.SetErrorStringWithFormat(
41ac9a064cSDimitry Andric     //     "ThreadPlanPython::%s () - ERROR: %s", __FUNCTION__,
42ac9a064cSDimitry Andric     //     "Couldn't get script interpreter");
43ac9a064cSDimitry Andric     return;
44ac9a064cSDimitry Andric   }
45ac9a064cSDimitry Andric 
46ac9a064cSDimitry Andric   m_interface = interpreter->CreateScriptedThreadPlanInterface();
47ac9a064cSDimitry Andric   if (!m_interface) {
48ac9a064cSDimitry Andric     SetPlanComplete(false);
49ac9a064cSDimitry Andric     // FIXME: error handling
50ac9a064cSDimitry Andric     // error.SetErrorStringWithFormat(
51ac9a064cSDimitry Andric     //     "ThreadPlanPython::%s () - ERROR: %s", __FUNCTION__,
52ac9a064cSDimitry Andric     //     "Script interpreter couldn't create Scripted Thread Plan Interface");
53ac9a064cSDimitry Andric     return;
54ac9a064cSDimitry Andric   }
55ac9a064cSDimitry Andric 
56c0981da4SDimitry Andric   SetIsControllingPlan(true);
57205afe67SEd Maste   SetOkayToDiscard(true);
58205afe67SEd Maste   SetPrivate(false);
59205afe67SEd Maste }
60205afe67SEd Maste 
ValidatePlan(Stream * error)6114f1b3e8SDimitry Andric bool ThreadPlanPython::ValidatePlan(Stream *error) {
6294994d37SDimitry Andric   if (!m_did_push)
63205afe67SEd Maste     return true;
6494994d37SDimitry Andric 
6594994d37SDimitry Andric   if (!m_implementation_sp) {
6694994d37SDimitry Andric     if (error)
67ead24645SDimitry Andric       error->Printf("Error constructing Python ThreadPlan: %s",
68ead24645SDimitry Andric           m_error_str.empty() ? "<unknown error>"
69ead24645SDimitry Andric                                 : m_error_str.c_str());
70205afe67SEd Maste     return false;
71205afe67SEd Maste   }
72205afe67SEd Maste 
7394994d37SDimitry Andric   return true;
7494994d37SDimitry Andric }
7594994d37SDimitry Andric 
GetScriptInterpreter()76cfca06d7SDimitry Andric ScriptInterpreter *ThreadPlanPython::GetScriptInterpreter() {
77cfca06d7SDimitry Andric   return m_process.GetTarget().GetDebugger().GetScriptInterpreter();
78cfca06d7SDimitry Andric }
79cfca06d7SDimitry Andric 
DidPush()8014f1b3e8SDimitry Andric void ThreadPlanPython::DidPush() {
8114f1b3e8SDimitry Andric   // We set up the script side in DidPush, so that it can push other plans in
82f73363f1SDimitry Andric   // the constructor, and doesn't have to care about the details of DidPush.
8394994d37SDimitry Andric   m_did_push = true;
84ac9a064cSDimitry Andric   if (m_interface) {
85ac9a064cSDimitry Andric     auto obj_or_err = m_interface->CreatePluginObject(
86ac9a064cSDimitry Andric         m_class_name, this->shared_from_this(), m_args_data);
87ac9a064cSDimitry Andric     if (!obj_or_err) {
88ac9a064cSDimitry Andric       m_error_str = llvm::toString(obj_or_err.takeError());
89ac9a064cSDimitry Andric       SetPlanComplete(false);
90ac9a064cSDimitry Andric     } else
91ac9a064cSDimitry Andric       m_implementation_sp = *obj_or_err;
92205afe67SEd Maste   }
93205afe67SEd Maste }
94205afe67SEd Maste 
ShouldStop(Event * event_ptr)9514f1b3e8SDimitry Andric bool ThreadPlanPython::ShouldStop(Event *event_ptr) {
96145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Thread);
97ead24645SDimitry Andric   LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
9814f1b3e8SDimitry Andric             m_class_name.c_str());
99205afe67SEd Maste 
100205afe67SEd Maste   bool should_stop = true;
10114f1b3e8SDimitry Andric   if (m_implementation_sp) {
102ac9a064cSDimitry Andric     auto should_stop_or_err = m_interface->ShouldStop(event_ptr);
103ac9a064cSDimitry Andric     if (!should_stop_or_err) {
104ac9a064cSDimitry Andric       LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), should_stop_or_err.takeError(),
105ac9a064cSDimitry Andric                      "Can't call ScriptedThreadPlan::ShouldStop.");
106205afe67SEd Maste       SetPlanComplete(false);
107ac9a064cSDimitry Andric     } else
108ac9a064cSDimitry Andric       should_stop = *should_stop_or_err;
109205afe67SEd Maste   }
110205afe67SEd Maste   return should_stop;
111205afe67SEd Maste }
112205afe67SEd Maste 
IsPlanStale()11314f1b3e8SDimitry Andric bool ThreadPlanPython::IsPlanStale() {
114145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Thread);
115ead24645SDimitry Andric   LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
11614f1b3e8SDimitry Andric             m_class_name.c_str());
11714f1b3e8SDimitry Andric 
11814f1b3e8SDimitry Andric   bool is_stale = true;
11914f1b3e8SDimitry Andric   if (m_implementation_sp) {
120ac9a064cSDimitry Andric     auto is_stale_or_err = m_interface->IsStale();
121ac9a064cSDimitry Andric     if (!is_stale_or_err) {
122ac9a064cSDimitry Andric       LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), is_stale_or_err.takeError(),
123ac9a064cSDimitry Andric                      "Can't call ScriptedThreadPlan::IsStale.");
12414f1b3e8SDimitry Andric       SetPlanComplete(false);
125ac9a064cSDimitry Andric     } else
126ac9a064cSDimitry Andric       is_stale = *is_stale_or_err;
12714f1b3e8SDimitry Andric   }
12814f1b3e8SDimitry Andric   return is_stale;
12914f1b3e8SDimitry Andric }
13014f1b3e8SDimitry Andric 
DoPlanExplainsStop(Event * event_ptr)13114f1b3e8SDimitry Andric bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) {
132145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Thread);
133ead24645SDimitry Andric   LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
13414f1b3e8SDimitry Andric             m_class_name.c_str());
135205afe67SEd Maste 
136205afe67SEd Maste   bool explains_stop = true;
13714f1b3e8SDimitry Andric   if (m_implementation_sp) {
138ac9a064cSDimitry Andric     auto explains_stop_or_error = m_interface->ExplainsStop(event_ptr);
139ac9a064cSDimitry Andric     if (!explains_stop_or_error) {
140ac9a064cSDimitry Andric       LLDB_LOG_ERROR(GetLog(LLDBLog::Thread),
141ac9a064cSDimitry Andric                      explains_stop_or_error.takeError(),
142ac9a064cSDimitry Andric                      "Can't call ScriptedThreadPlan::ExplainsStop.");
143205afe67SEd Maste       SetPlanComplete(false);
144ac9a064cSDimitry Andric     } else
145ac9a064cSDimitry Andric       explains_stop = *explains_stop_or_error;
146205afe67SEd Maste   }
147205afe67SEd Maste   return explains_stop;
148205afe67SEd Maste }
149205afe67SEd Maste 
MischiefManaged()15014f1b3e8SDimitry Andric bool ThreadPlanPython::MischiefManaged() {
151145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Thread);
152ead24645SDimitry Andric   LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
15314f1b3e8SDimitry Andric             m_class_name.c_str());
154205afe67SEd Maste   bool mischief_managed = true;
15514f1b3e8SDimitry Andric   if (m_implementation_sp) {
15614f1b3e8SDimitry Andric     // I don't really need mischief_managed, since it's simpler to just call
15714f1b3e8SDimitry Andric     // SetPlanComplete in should_stop.
158205afe67SEd Maste     mischief_managed = IsPlanComplete();
1597fa27ce4SDimitry Andric     if (mischief_managed) {
1607fa27ce4SDimitry Andric       // We need to cache the stop reason here we'll need it in GetDescription.
1617fa27ce4SDimitry Andric       GetDescription(&m_stop_description, eDescriptionLevelBrief);
162205afe67SEd Maste       m_implementation_sp.reset();
163205afe67SEd Maste     }
1647fa27ce4SDimitry Andric   }
165205afe67SEd Maste   return mischief_managed;
166205afe67SEd Maste }
167205afe67SEd Maste 
GetPlanRunState()16814f1b3e8SDimitry Andric lldb::StateType ThreadPlanPython::GetPlanRunState() {
169145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Thread);
170ead24645SDimitry Andric   LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
171205afe67SEd Maste             m_class_name.c_str());
172205afe67SEd Maste   lldb::StateType run_state = eStateRunning;
173ac9a064cSDimitry Andric   if (m_implementation_sp)
174ac9a064cSDimitry Andric     run_state = m_interface->GetRunState();
175205afe67SEd Maste   return run_state;
176205afe67SEd Maste }
177205afe67SEd Maste 
GetDescription(Stream * s,lldb::DescriptionLevel level)17814f1b3e8SDimitry Andric void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) {
1797fa27ce4SDimitry Andric   Log *log = GetLog(LLDBLog::Thread);
1807fa27ce4SDimitry Andric   LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
1817fa27ce4SDimitry Andric             m_class_name.c_str());
1827fa27ce4SDimitry Andric   if (m_implementation_sp) {
1837fa27ce4SDimitry Andric     ScriptInterpreter *script_interp = GetScriptInterpreter();
1847fa27ce4SDimitry Andric     if (script_interp) {
185ac9a064cSDimitry Andric       lldb::StreamSP stream = std::make_shared<lldb_private::StreamString>();
186ac9a064cSDimitry Andric       llvm::Error err = m_interface->GetStopDescription(stream);
187ac9a064cSDimitry Andric       if (err) {
188ac9a064cSDimitry Andric         LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), std::move(err),
189ac9a064cSDimitry Andric                        "Can't call ScriptedThreadPlan::GetStopDescription.");
19014f1b3e8SDimitry Andric         s->Printf("Python thread plan implemented by class %s.",
19114f1b3e8SDimitry Andric             m_class_name.c_str());
192ac9a064cSDimitry Andric       } else
193ac9a064cSDimitry Andric         s->PutCString(
194ac9a064cSDimitry Andric             reinterpret_cast<StreamString *>(stream.get())->GetData());
195205afe67SEd Maste     }
1967fa27ce4SDimitry Andric     return;
1977fa27ce4SDimitry Andric   }
1987fa27ce4SDimitry Andric   // It's an error not to have a description, so if we get here, we should
1997fa27ce4SDimitry Andric   // add something.
2007fa27ce4SDimitry Andric   if (m_stop_description.Empty())
2017fa27ce4SDimitry Andric     s->Printf("Python thread plan implemented by class %s.",
2027fa27ce4SDimitry Andric               m_class_name.c_str());
2037fa27ce4SDimitry Andric   s->PutCString(m_stop_description.GetData());
2047fa27ce4SDimitry Andric }
205205afe67SEd Maste 
2067fa27ce4SDimitry Andric // The ones below are not currently exported to Python.
WillStop()20714f1b3e8SDimitry Andric bool ThreadPlanPython::WillStop() {
208145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Thread);
209ead24645SDimitry Andric   LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
21014f1b3e8SDimitry Andric             m_class_name.c_str());
211205afe67SEd Maste   return true;
212205afe67SEd Maste }
2137fa27ce4SDimitry Andric 
DoWillResume(lldb::StateType resume_state,bool current_plan)2147fa27ce4SDimitry Andric bool ThreadPlanPython::DoWillResume(lldb::StateType resume_state,
2157fa27ce4SDimitry Andric                                   bool current_plan) {
2167fa27ce4SDimitry Andric   m_stop_description.Clear();
2177fa27ce4SDimitry Andric   return true;
2187fa27ce4SDimitry Andric }
219