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