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