1 //===-- ThreadPlanPython.cpp ----------------------------------------------===//
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/Interfaces/ScriptedThreadPlanInterface.h"
14 #include "lldb/Interpreter/ScriptInterpreter.h"
15 #include "lldb/Target/Process.h"
16 #include "lldb/Target/RegisterContext.h"
17 #include "lldb/Target/Target.h"
18 #include "lldb/Target/Thread.h"
19 #include "lldb/Target/ThreadPlan.h"
20 #include "lldb/Target/ThreadPlanPython.h"
21 #include "lldb/Utility/LLDBLog.h"
22 #include "lldb/Utility/Log.h"
23 #include "lldb/Utility/State.h"
24
25 using namespace lldb;
26 using namespace lldb_private;
27
28 // ThreadPlanPython
29
ThreadPlanPython(Thread & thread,const char * class_name,const StructuredDataImpl & args_data)30 ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name,
31 const StructuredDataImpl &args_data)
32 : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread,
33 eVoteNoOpinion, eVoteNoOpinion),
34 m_class_name(class_name), m_args_data(args_data), m_did_push(false),
35 m_stop_others(false) {
36 ScriptInterpreter *interpreter = GetScriptInterpreter();
37 if (!interpreter) {
38 SetPlanComplete(false);
39 // FIXME: error handling
40 // error.SetErrorStringWithFormat(
41 // "ThreadPlanPython::%s () - ERROR: %s", __FUNCTION__,
42 // "Couldn't get script interpreter");
43 return;
44 }
45
46 m_interface = interpreter->CreateScriptedThreadPlanInterface();
47 if (!m_interface) {
48 SetPlanComplete(false);
49 // FIXME: error handling
50 // error.SetErrorStringWithFormat(
51 // "ThreadPlanPython::%s () - ERROR: %s", __FUNCTION__,
52 // "Script interpreter couldn't create Scripted Thread Plan Interface");
53 return;
54 }
55
56 SetIsControllingPlan(true);
57 SetOkayToDiscard(true);
58 SetPrivate(false);
59 }
60
ValidatePlan(Stream * error)61 bool ThreadPlanPython::ValidatePlan(Stream *error) {
62 if (!m_did_push)
63 return true;
64
65 if (!m_implementation_sp) {
66 if (error)
67 error->Printf("Error constructing Python ThreadPlan: %s",
68 m_error_str.empty() ? "<unknown error>"
69 : m_error_str.c_str());
70 return false;
71 }
72
73 return true;
74 }
75
GetScriptInterpreter()76 ScriptInterpreter *ThreadPlanPython::GetScriptInterpreter() {
77 return m_process.GetTarget().GetDebugger().GetScriptInterpreter();
78 }
79
DidPush()80 void ThreadPlanPython::DidPush() {
81 // We set up the script side in DidPush, so that it can push other plans in
82 // the constructor, and doesn't have to care about the details of DidPush.
83 m_did_push = true;
84 if (m_interface) {
85 auto obj_or_err = m_interface->CreatePluginObject(
86 m_class_name, this->shared_from_this(), m_args_data);
87 if (!obj_or_err) {
88 m_error_str = llvm::toString(obj_or_err.takeError());
89 SetPlanComplete(false);
90 } else
91 m_implementation_sp = *obj_or_err;
92 }
93 }
94
ShouldStop(Event * event_ptr)95 bool ThreadPlanPython::ShouldStop(Event *event_ptr) {
96 Log *log = GetLog(LLDBLog::Thread);
97 LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
98 m_class_name.c_str());
99
100 bool should_stop = true;
101 if (m_implementation_sp) {
102 auto should_stop_or_err = m_interface->ShouldStop(event_ptr);
103 if (!should_stop_or_err) {
104 LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), should_stop_or_err.takeError(),
105 "Can't call ScriptedThreadPlan::ShouldStop.");
106 SetPlanComplete(false);
107 } else
108 should_stop = *should_stop_or_err;
109 }
110 return should_stop;
111 }
112
IsPlanStale()113 bool ThreadPlanPython::IsPlanStale() {
114 Log *log = GetLog(LLDBLog::Thread);
115 LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
116 m_class_name.c_str());
117
118 bool is_stale = true;
119 if (m_implementation_sp) {
120 auto is_stale_or_err = m_interface->IsStale();
121 if (!is_stale_or_err) {
122 LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), is_stale_or_err.takeError(),
123 "Can't call ScriptedThreadPlan::IsStale.");
124 SetPlanComplete(false);
125 } else
126 is_stale = *is_stale_or_err;
127 }
128 return is_stale;
129 }
130
DoPlanExplainsStop(Event * event_ptr)131 bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) {
132 Log *log = GetLog(LLDBLog::Thread);
133 LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
134 m_class_name.c_str());
135
136 bool explains_stop = true;
137 if (m_implementation_sp) {
138 auto explains_stop_or_error = m_interface->ExplainsStop(event_ptr);
139 if (!explains_stop_or_error) {
140 LLDB_LOG_ERROR(GetLog(LLDBLog::Thread),
141 explains_stop_or_error.takeError(),
142 "Can't call ScriptedThreadPlan::ExplainsStop.");
143 SetPlanComplete(false);
144 } else
145 explains_stop = *explains_stop_or_error;
146 }
147 return explains_stop;
148 }
149
MischiefManaged()150 bool ThreadPlanPython::MischiefManaged() {
151 Log *log = GetLog(LLDBLog::Thread);
152 LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
153 m_class_name.c_str());
154 bool mischief_managed = true;
155 if (m_implementation_sp) {
156 // I don't really need mischief_managed, since it's simpler to just call
157 // SetPlanComplete in should_stop.
158 mischief_managed = IsPlanComplete();
159 if (mischief_managed) {
160 // We need to cache the stop reason here we'll need it in GetDescription.
161 GetDescription(&m_stop_description, eDescriptionLevelBrief);
162 m_implementation_sp.reset();
163 }
164 }
165 return mischief_managed;
166 }
167
GetPlanRunState()168 lldb::StateType ThreadPlanPython::GetPlanRunState() {
169 Log *log = GetLog(LLDBLog::Thread);
170 LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
171 m_class_name.c_str());
172 lldb::StateType run_state = eStateRunning;
173 if (m_implementation_sp)
174 run_state = m_interface->GetRunState();
175 return run_state;
176 }
177
GetDescription(Stream * s,lldb::DescriptionLevel level)178 void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) {
179 Log *log = GetLog(LLDBLog::Thread);
180 LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
181 m_class_name.c_str());
182 if (m_implementation_sp) {
183 ScriptInterpreter *script_interp = GetScriptInterpreter();
184 if (script_interp) {
185 lldb::StreamSP stream = std::make_shared<lldb_private::StreamString>();
186 llvm::Error err = m_interface->GetStopDescription(stream);
187 if (err) {
188 LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), std::move(err),
189 "Can't call ScriptedThreadPlan::GetStopDescription.");
190 s->Printf("Python thread plan implemented by class %s.",
191 m_class_name.c_str());
192 } else
193 s->PutCString(
194 reinterpret_cast<StreamString *>(stream.get())->GetData());
195 }
196 return;
197 }
198 // It's an error not to have a description, so if we get here, we should
199 // add something.
200 if (m_stop_description.Empty())
201 s->Printf("Python thread plan implemented by class %s.",
202 m_class_name.c_str());
203 s->PutCString(m_stop_description.GetData());
204 }
205
206 // The ones below are not currently exported to Python.
WillStop()207 bool ThreadPlanPython::WillStop() {
208 Log *log = GetLog(LLDBLog::Thread);
209 LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
210 m_class_name.c_str());
211 return true;
212 }
213
DoWillResume(lldb::StateType resume_state,bool current_plan)214 bool ThreadPlanPython::DoWillResume(lldb::StateType resume_state,
215 bool current_plan) {
216 m_stop_description.Clear();
217 return true;
218 }
219