xref: /llvm-project/lldb/source/Target/ScriptedThreadPlan.cpp (revision f2c5aa920054fa60372a161520e6ea8e8d23880d)
1039cfe81SMed Ismail Bennani //===-- ScriptedThreadPlan.cpp --------------------------------------------===//
2039cfe81SMed Ismail Bennani //
3039cfe81SMed Ismail Bennani // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4039cfe81SMed Ismail Bennani // See https://llvm.org/LICENSE.txt for license information.
5039cfe81SMed Ismail Bennani // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6039cfe81SMed Ismail Bennani //
7039cfe81SMed Ismail Bennani //===----------------------------------------------------------------------===//
8039cfe81SMed Ismail Bennani 
9039cfe81SMed Ismail Bennani #include "lldb/Target/ThreadPlan.h"
10039cfe81SMed Ismail Bennani 
11039cfe81SMed Ismail Bennani #include "lldb/Core/Debugger.h"
12039cfe81SMed Ismail Bennani #include "lldb/Interpreter/CommandInterpreter.h"
13039cfe81SMed Ismail Bennani #include "lldb/Interpreter/Interfaces/ScriptedThreadPlanInterface.h"
14039cfe81SMed Ismail Bennani #include "lldb/Interpreter/ScriptInterpreter.h"
15039cfe81SMed Ismail Bennani #include "lldb/Target/Process.h"
16039cfe81SMed Ismail Bennani #include "lldb/Target/RegisterContext.h"
17039cfe81SMed Ismail Bennani #include "lldb/Target/ScriptedThreadPlan.h"
18039cfe81SMed Ismail Bennani #include "lldb/Target/Target.h"
19039cfe81SMed Ismail Bennani #include "lldb/Target/Thread.h"
20039cfe81SMed Ismail Bennani #include "lldb/Target/ThreadPlan.h"
21039cfe81SMed Ismail Bennani #include "lldb/Utility/LLDBLog.h"
22039cfe81SMed Ismail Bennani #include "lldb/Utility/Log.h"
23039cfe81SMed Ismail Bennani #include "lldb/Utility/State.h"
24039cfe81SMed Ismail Bennani 
25039cfe81SMed Ismail Bennani using namespace lldb;
26039cfe81SMed Ismail Bennani using namespace lldb_private;
27039cfe81SMed Ismail Bennani 
28039cfe81SMed Ismail Bennani ScriptedThreadPlan::ScriptedThreadPlan(Thread &thread, const char *class_name,
29039cfe81SMed Ismail Bennani                                        const StructuredDataImpl &args_data)
30039cfe81SMed Ismail Bennani     : ThreadPlan(ThreadPlan::eKindPython, "Script based Thread Plan", thread,
31039cfe81SMed Ismail Bennani                  eVoteNoOpinion, eVoteNoOpinion),
32039cfe81SMed Ismail Bennani       m_class_name(class_name), m_args_data(args_data), m_did_push(false),
33039cfe81SMed Ismail Bennani       m_stop_others(false) {
34039cfe81SMed Ismail Bennani   ScriptInterpreter *interpreter = GetScriptInterpreter();
35039cfe81SMed Ismail Bennani   if (!interpreter) {
36039cfe81SMed Ismail Bennani     SetPlanComplete(false);
37039cfe81SMed Ismail Bennani     // FIXME: error handling
380642cd76SAdrian Prantl     // error = Status::FromErrorStringWithFormat(
39039cfe81SMed Ismail Bennani     //     "ScriptedThreadPlan::%s () - ERROR: %s", __FUNCTION__,
40039cfe81SMed Ismail Bennani     //     "Couldn't get script interpreter");
41039cfe81SMed Ismail Bennani     return;
42039cfe81SMed Ismail Bennani   }
43039cfe81SMed Ismail Bennani 
44039cfe81SMed Ismail Bennani   m_interface = interpreter->CreateScriptedThreadPlanInterface();
45039cfe81SMed Ismail Bennani   if (!m_interface) {
46039cfe81SMed Ismail Bennani     SetPlanComplete(false);
47039cfe81SMed Ismail Bennani     // FIXME: error handling
480642cd76SAdrian Prantl     // error = Status::FromErrorStringWithFormat(
49039cfe81SMed Ismail Bennani     //     "ScriptedThreadPlan::%s () - ERROR: %s", __FUNCTION__,
50039cfe81SMed Ismail Bennani     //     "Script interpreter couldn't create Scripted Thread Plan Interface");
51039cfe81SMed Ismail Bennani     return;
52039cfe81SMed Ismail Bennani   }
53039cfe81SMed Ismail Bennani 
54039cfe81SMed Ismail Bennani   SetIsControllingPlan(true);
55039cfe81SMed Ismail Bennani   SetOkayToDiscard(true);
56039cfe81SMed Ismail Bennani   SetPrivate(false);
57039cfe81SMed Ismail Bennani }
58039cfe81SMed Ismail Bennani 
59039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::ValidatePlan(Stream *error) {
60039cfe81SMed Ismail Bennani   if (!m_did_push)
61039cfe81SMed Ismail Bennani     return true;
62039cfe81SMed Ismail Bennani 
63039cfe81SMed Ismail Bennani   if (!m_implementation_sp) {
64039cfe81SMed Ismail Bennani     if (error)
65039cfe81SMed Ismail Bennani       error->Printf("Error constructing Python ThreadPlan: %s",
66039cfe81SMed Ismail Bennani                     m_error_str.empty() ? "<unknown error>"
67039cfe81SMed Ismail Bennani                                         : m_error_str.c_str());
68039cfe81SMed Ismail Bennani     return false;
69039cfe81SMed Ismail Bennani   }
70039cfe81SMed Ismail Bennani 
71039cfe81SMed Ismail Bennani   return true;
72039cfe81SMed Ismail Bennani }
73039cfe81SMed Ismail Bennani 
74039cfe81SMed Ismail Bennani ScriptInterpreter *ScriptedThreadPlan::GetScriptInterpreter() {
75039cfe81SMed Ismail Bennani   return m_process.GetTarget().GetDebugger().GetScriptInterpreter();
76039cfe81SMed Ismail Bennani }
77039cfe81SMed Ismail Bennani 
78039cfe81SMed Ismail Bennani void ScriptedThreadPlan::DidPush() {
79039cfe81SMed Ismail Bennani   // We set up the script side in DidPush, so that it can push other plans in
80039cfe81SMed Ismail Bennani   // the constructor, and doesn't have to care about the details of DidPush.
81039cfe81SMed Ismail Bennani   m_did_push = true;
82039cfe81SMed Ismail Bennani   if (m_interface) {
83039cfe81SMed Ismail Bennani     auto obj_or_err = m_interface->CreatePluginObject(
84039cfe81SMed Ismail Bennani         m_class_name, this->shared_from_this(), m_args_data);
85039cfe81SMed Ismail Bennani     if (!obj_or_err) {
86039cfe81SMed Ismail Bennani       m_error_str = llvm::toString(obj_or_err.takeError());
87039cfe81SMed Ismail Bennani       SetPlanComplete(false);
88039cfe81SMed Ismail Bennani     } else
89039cfe81SMed Ismail Bennani       m_implementation_sp = *obj_or_err;
90039cfe81SMed Ismail Bennani   }
91039cfe81SMed Ismail Bennani }
92039cfe81SMed Ismail Bennani 
93039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::ShouldStop(Event *event_ptr) {
94039cfe81SMed Ismail Bennani   Log *log = GetLog(LLDBLog::Thread);
95039cfe81SMed Ismail Bennani   LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
96039cfe81SMed Ismail Bennani             LLVM_PRETTY_FUNCTION, m_class_name.c_str());
97039cfe81SMed Ismail Bennani 
98039cfe81SMed Ismail Bennani   bool should_stop = true;
99039cfe81SMed Ismail Bennani   if (m_implementation_sp) {
100039cfe81SMed Ismail Bennani     auto should_stop_or_err = m_interface->ShouldStop(event_ptr);
101039cfe81SMed Ismail Bennani     if (!should_stop_or_err) {
102039cfe81SMed Ismail Bennani       LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), should_stop_or_err.takeError(),
103039cfe81SMed Ismail Bennani                      "Can't call ScriptedThreadPlan::ShouldStop.");
104039cfe81SMed Ismail Bennani       SetPlanComplete(false);
105039cfe81SMed Ismail Bennani     } else
106039cfe81SMed Ismail Bennani       should_stop = *should_stop_or_err;
107039cfe81SMed Ismail Bennani   }
108039cfe81SMed Ismail Bennani   return should_stop;
109039cfe81SMed Ismail Bennani }
110039cfe81SMed Ismail Bennani 
111039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::IsPlanStale() {
112039cfe81SMed Ismail Bennani   Log *log = GetLog(LLDBLog::Thread);
113039cfe81SMed Ismail Bennani   LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
114039cfe81SMed Ismail Bennani             LLVM_PRETTY_FUNCTION, m_class_name.c_str());
115039cfe81SMed Ismail Bennani 
116039cfe81SMed Ismail Bennani   bool is_stale = true;
117039cfe81SMed Ismail Bennani   if (m_implementation_sp) {
118039cfe81SMed Ismail Bennani     auto is_stale_or_err = m_interface->IsStale();
119039cfe81SMed Ismail Bennani     if (!is_stale_or_err) {
120039cfe81SMed Ismail Bennani       LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), is_stale_or_err.takeError(),
121039cfe81SMed Ismail Bennani                      "Can't call ScriptedThreadPlan::IsStale.");
122039cfe81SMed Ismail Bennani       SetPlanComplete(false);
123039cfe81SMed Ismail Bennani     } else
124039cfe81SMed Ismail Bennani       is_stale = *is_stale_or_err;
125039cfe81SMed Ismail Bennani   }
126039cfe81SMed Ismail Bennani   return is_stale;
127039cfe81SMed Ismail Bennani }
128039cfe81SMed Ismail Bennani 
129039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::DoPlanExplainsStop(Event *event_ptr) {
130039cfe81SMed Ismail Bennani   Log *log = GetLog(LLDBLog::Thread);
131039cfe81SMed Ismail Bennani   LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
132039cfe81SMed Ismail Bennani             LLVM_PRETTY_FUNCTION, m_class_name.c_str());
133039cfe81SMed Ismail Bennani 
134039cfe81SMed Ismail Bennani   bool explains_stop = true;
135039cfe81SMed Ismail Bennani   if (m_implementation_sp) {
136039cfe81SMed Ismail Bennani     auto explains_stop_or_error = m_interface->ExplainsStop(event_ptr);
137039cfe81SMed Ismail Bennani     if (!explains_stop_or_error) {
138039cfe81SMed Ismail Bennani       LLDB_LOG_ERROR(GetLog(LLDBLog::Thread),
139039cfe81SMed Ismail Bennani                      explains_stop_or_error.takeError(),
140039cfe81SMed Ismail Bennani                      "Can't call ScriptedThreadPlan::ExplainsStop.");
141039cfe81SMed Ismail Bennani       SetPlanComplete(false);
142039cfe81SMed Ismail Bennani     } else
143039cfe81SMed Ismail Bennani       explains_stop = *explains_stop_or_error;
144039cfe81SMed Ismail Bennani   }
145039cfe81SMed Ismail Bennani   return explains_stop;
146039cfe81SMed Ismail Bennani }
147039cfe81SMed Ismail Bennani 
148039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::MischiefManaged() {
149039cfe81SMed Ismail Bennani   Log *log = GetLog(LLDBLog::Thread);
150039cfe81SMed Ismail Bennani   LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
151039cfe81SMed Ismail Bennani             LLVM_PRETTY_FUNCTION, m_class_name.c_str());
152039cfe81SMed Ismail Bennani   bool mischief_managed = true;
153039cfe81SMed Ismail Bennani   if (m_implementation_sp) {
154039cfe81SMed Ismail Bennani     // I don't really need mischief_managed, since it's simpler to just call
155039cfe81SMed Ismail Bennani     // SetPlanComplete in should_stop.
156039cfe81SMed Ismail Bennani     mischief_managed = IsPlanComplete();
157039cfe81SMed Ismail Bennani     if (mischief_managed) {
158039cfe81SMed Ismail Bennani       // We need to cache the stop reason here we'll need it in GetDescription.
159039cfe81SMed Ismail Bennani       GetDescription(&m_stop_description, eDescriptionLevelBrief);
160039cfe81SMed Ismail Bennani       m_implementation_sp.reset();
161039cfe81SMed Ismail Bennani     }
162039cfe81SMed Ismail Bennani   }
163039cfe81SMed Ismail Bennani   return mischief_managed;
164039cfe81SMed Ismail Bennani }
165039cfe81SMed Ismail Bennani 
166039cfe81SMed Ismail Bennani lldb::StateType ScriptedThreadPlan::GetPlanRunState() {
167039cfe81SMed Ismail Bennani   Log *log = GetLog(LLDBLog::Thread);
168039cfe81SMed Ismail Bennani   LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
169039cfe81SMed Ismail Bennani             LLVM_PRETTY_FUNCTION, m_class_name.c_str());
170039cfe81SMed Ismail Bennani   lldb::StateType run_state = eStateRunning;
171039cfe81SMed Ismail Bennani   if (m_implementation_sp)
172039cfe81SMed Ismail Bennani     run_state = m_interface->GetRunState();
173039cfe81SMed Ismail Bennani   return run_state;
174039cfe81SMed Ismail Bennani }
175039cfe81SMed Ismail Bennani 
176039cfe81SMed Ismail Bennani void ScriptedThreadPlan::GetDescription(Stream *s,
177039cfe81SMed Ismail Bennani                                         lldb::DescriptionLevel level) {
178039cfe81SMed Ismail Bennani   Log *log = GetLog(LLDBLog::Thread);
179039cfe81SMed Ismail Bennani   LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
180039cfe81SMed Ismail Bennani             LLVM_PRETTY_FUNCTION, m_class_name.c_str());
181039cfe81SMed Ismail Bennani   if (m_implementation_sp) {
182039cfe81SMed Ismail Bennani     ScriptInterpreter *script_interp = GetScriptInterpreter();
183039cfe81SMed Ismail Bennani     if (script_interp) {
184039cfe81SMed Ismail Bennani       lldb::StreamSP stream = std::make_shared<lldb_private::StreamString>();
185039cfe81SMed Ismail Bennani       llvm::Error err = m_interface->GetStopDescription(stream);
186039cfe81SMed Ismail Bennani       if (err) {
187*f2c5aa92SJonas Devlieghere         LLDB_LOG_ERROR(
188*f2c5aa92SJonas Devlieghere             GetLog(LLDBLog::Thread), std::move(err),
189*f2c5aa92SJonas Devlieghere             "Can't call ScriptedThreadPlan::GetStopDescription: {0}");
190039cfe81SMed Ismail Bennani         s->Printf("Scripted thread plan implemented by class %s.",
191039cfe81SMed Ismail Bennani                   m_class_name.c_str());
192039cfe81SMed Ismail Bennani       } else
193039cfe81SMed Ismail Bennani         s->PutCString(
194039cfe81SMed Ismail Bennani             reinterpret_cast<StreamString *>(stream.get())->GetData());
195039cfe81SMed Ismail Bennani     }
196039cfe81SMed Ismail Bennani     return;
197039cfe81SMed Ismail Bennani   }
198039cfe81SMed Ismail Bennani   // It's an error not to have a description, so if we get here, we should
199039cfe81SMed Ismail Bennani   // add something.
200039cfe81SMed Ismail Bennani   if (m_stop_description.Empty())
201039cfe81SMed Ismail Bennani     s->Printf("Scripted thread plan implemented by class %s.",
202039cfe81SMed Ismail Bennani               m_class_name.c_str());
203039cfe81SMed Ismail Bennani   s->PutCString(m_stop_description.GetData());
204039cfe81SMed Ismail Bennani }
205039cfe81SMed Ismail Bennani 
206039cfe81SMed Ismail Bennani // The ones below are not currently exported to Python.
207039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::WillStop() {
208039cfe81SMed Ismail Bennani   Log *log = GetLog(LLDBLog::Thread);
209039cfe81SMed Ismail Bennani   LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
210039cfe81SMed Ismail Bennani             LLVM_PRETTY_FUNCTION, m_class_name.c_str());
211039cfe81SMed Ismail Bennani   return true;
212039cfe81SMed Ismail Bennani }
213039cfe81SMed Ismail Bennani 
214039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::DoWillResume(lldb::StateType resume_state,
215039cfe81SMed Ismail Bennani                                       bool current_plan) {
216039cfe81SMed Ismail Bennani   m_stop_description.Clear();
217039cfe81SMed Ismail Bennani   return true;
218039cfe81SMed Ismail Bennani }
219