xref: /freebsd/contrib/llvm-project/lldb/source/Target/ThreadPlanPython.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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