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 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 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 76 ScriptInterpreter *ThreadPlanPython::GetScriptInterpreter() { 77 return m_process.GetTarget().GetDebugger().GetScriptInterpreter(); 78 } 79 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 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 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 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 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 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 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. 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 214 bool ThreadPlanPython::DoWillResume(lldb::StateType resume_state, 215 bool current_plan) { 216 m_stop_description.Clear(); 217 return true; 218 } 219