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