1 //===-- ScriptedThread.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 "ScriptedThread.h" 10 11 #include "Plugins/Process/Utility/RegisterContextThreadMemory.h" 12 #include "lldb/Target/OperatingSystem.h" 13 #include "lldb/Target/Process.h" 14 #include "lldb/Target/RegisterContext.h" 15 #include "lldb/Target/StopInfo.h" 16 #include "lldb/Target/Unwind.h" 17 #include "lldb/Utility/DataBufferHeap.h" 18 #include "lldb/Utility/LLDBLog.h" 19 #include <memory> 20 21 using namespace lldb; 22 using namespace lldb_private; 23 24 void ScriptedThread::CheckInterpreterAndScriptObject() const { 25 lldbassert(m_script_object_sp && "Invalid Script Object."); 26 lldbassert(GetInterface() && "Invalid Scripted Thread Interface."); 27 } 28 29 llvm::Expected<std::shared_ptr<ScriptedThread>> 30 ScriptedThread::Create(ScriptedProcess &process, 31 StructuredData::Generic *script_object) { 32 if (!process.IsValid()) 33 return llvm::createStringError(llvm::inconvertibleErrorCode(), 34 "Invalid scripted process."); 35 36 process.CheckInterpreterAndScriptObject(); 37 38 auto scripted_thread_interface = 39 process.GetInterface().CreateScriptedThreadInterface(); 40 if (!scripted_thread_interface) 41 return llvm::createStringError( 42 llvm::inconvertibleErrorCode(), 43 "Failed to create scripted thread interface."); 44 45 llvm::StringRef thread_class_name; 46 if (!script_object) { 47 llvm::Optional<std::string> class_name = 48 process.GetInterface().GetScriptedThreadPluginName(); 49 if (!class_name || class_name->empty()) 50 return llvm::createStringError( 51 llvm::inconvertibleErrorCode(), 52 "Failed to get scripted thread class name."); 53 thread_class_name = *class_name; 54 } 55 56 ExecutionContext exe_ctx(process); 57 StructuredData::GenericSP owned_script_object_sp = 58 scripted_thread_interface->CreatePluginObject( 59 thread_class_name, exe_ctx, 60 process.m_scripted_process_info.GetArgsSP(), script_object); 61 62 if (!owned_script_object_sp) 63 return llvm::createStringError(llvm::inconvertibleErrorCode(), 64 "Failed to create script object."); 65 if (!owned_script_object_sp->IsValid()) 66 return llvm::createStringError(llvm::inconvertibleErrorCode(), 67 "Created script object is invalid."); 68 69 lldb::tid_t tid = scripted_thread_interface->GetThreadID(); 70 71 return std::make_shared<ScriptedThread>(process, scripted_thread_interface, 72 tid, owned_script_object_sp); 73 } 74 75 ScriptedThread::ScriptedThread(ScriptedProcess &process, 76 ScriptedThreadInterfaceSP interface_sp, 77 lldb::tid_t tid, 78 StructuredData::GenericSP script_object_sp) 79 : Thread(process, tid), m_scripted_process(process), 80 m_scripted_thread_interface_sp(interface_sp), 81 m_script_object_sp(script_object_sp) {} 82 83 ScriptedThread::~ScriptedThread() { DestroyThread(); } 84 85 const char *ScriptedThread::GetName() { 86 CheckInterpreterAndScriptObject(); 87 llvm::Optional<std::string> thread_name = GetInterface()->GetName(); 88 if (!thread_name) 89 return nullptr; 90 return ConstString(thread_name->c_str()).AsCString(); 91 } 92 93 const char *ScriptedThread::GetQueueName() { 94 CheckInterpreterAndScriptObject(); 95 llvm::Optional<std::string> queue_name = GetInterface()->GetQueue(); 96 if (!queue_name) 97 return nullptr; 98 return ConstString(queue_name->c_str()).AsCString(); 99 } 100 101 void ScriptedThread::WillResume(StateType resume_state) {} 102 103 void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); } 104 105 RegisterContextSP ScriptedThread::GetRegisterContext() { 106 if (!m_reg_context_sp) 107 m_reg_context_sp = CreateRegisterContextForFrame(nullptr); 108 return m_reg_context_sp; 109 } 110 111 RegisterContextSP 112 ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) { 113 const uint32_t concrete_frame_idx = 114 frame ? frame->GetConcreteFrameIndex() : 0; 115 116 if (concrete_frame_idx) 117 return GetUnwinder().CreateRegisterContextForFrame(frame); 118 119 lldb::RegisterContextSP reg_ctx_sp; 120 Status error; 121 122 llvm::Optional<std::string> reg_data = GetInterface()->GetRegisterContext(); 123 if (!reg_data) 124 return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 125 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.", 126 error, LLDBLog::Thread); 127 128 DataBufferSP data_sp( 129 std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size())); 130 131 if (!data_sp->GetByteSize()) 132 return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 133 LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error, 134 LLDBLog::Thread); 135 136 std::shared_ptr<RegisterContextMemory> reg_ctx_memory = 137 std::make_shared<RegisterContextMemory>( 138 *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS); 139 if (!reg_ctx_memory) 140 return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 141 LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error, 142 LLDBLog::Thread); 143 144 reg_ctx_memory->SetAllRegisterData(data_sp); 145 m_reg_context_sp = reg_ctx_memory; 146 147 return m_reg_context_sp; 148 } 149 150 bool ScriptedThread::CalculateStopInfo() { 151 StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason(); 152 153 Status error; 154 if (!dict_sp) 155 return GetInterface()->ErrorWithMessage<bool>( 156 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error, 157 LLDBLog::Thread); 158 159 lldb::StopInfoSP stop_info_sp; 160 lldb::StopReason stop_reason_type; 161 162 if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type)) 163 return GetInterface()->ErrorWithMessage<bool>( 164 LLVM_PRETTY_FUNCTION, 165 "Couldn't find value for key 'type' in stop reason dictionary.", error, 166 LLDBLog::Thread); 167 168 StructuredData::Dictionary *data_dict; 169 if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict)) 170 return GetInterface()->ErrorWithMessage<bool>( 171 LLVM_PRETTY_FUNCTION, 172 "Couldn't find value for key 'data' in stop reason dictionary.", error, 173 LLDBLog::Thread); 174 175 switch (stop_reason_type) { 176 case lldb::eStopReasonNone: 177 return true; 178 case lldb::eStopReasonBreakpoint: { 179 lldb::break_id_t break_id; 180 data_dict->GetValueForKeyAsInteger("break_id", break_id, 181 LLDB_INVALID_BREAK_ID); 182 stop_info_sp = 183 StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id); 184 } break; 185 case lldb::eStopReasonSignal: { 186 int signal; 187 llvm::StringRef description; 188 data_dict->GetValueForKeyAsInteger("signal", signal, 189 LLDB_INVALID_SIGNAL_NUMBER); 190 data_dict->GetValueForKeyAsString("desc", description); 191 stop_info_sp = 192 StopInfo::CreateStopReasonWithSignal(*this, signal, description.data()); 193 } break; 194 case lldb::eStopReasonException: { 195 llvm::StringRef description; 196 data_dict->GetValueForKeyAsString("desc", description); 197 198 stop_info_sp = 199 StopInfo::CreateStopReasonWithException(*this, description.data()); 200 } break; 201 default: 202 return GetInterface()->ErrorWithMessage<bool>( 203 LLVM_PRETTY_FUNCTION, 204 llvm::Twine("Unsupported stop reason type (" + 205 llvm::Twine(stop_reason_type) + llvm::Twine(").")) 206 .str(), 207 error, LLDBLog::Thread); 208 } 209 210 if (!stop_info_sp) 211 return false; 212 213 SetStopInfo(stop_info_sp); 214 return true; 215 } 216 217 void ScriptedThread::RefreshStateAfterStop() { 218 GetRegisterContext()->InvalidateIfNeeded(/*force=*/false); 219 } 220 221 lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const { 222 return m_scripted_thread_interface_sp; 223 } 224 225 std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() { 226 CheckInterpreterAndScriptObject(); 227 228 if (!m_register_info_sp) { 229 StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo(); 230 231 Status error; 232 if (!reg_info) 233 return GetInterface() 234 ->ErrorWithMessage<std::shared_ptr<DynamicRegisterInfo>>( 235 LLVM_PRETTY_FUNCTION, 236 "Failed to get scripted thread registers info.", error, 237 LLDBLog::Thread); 238 239 m_register_info_sp = std::make_shared<DynamicRegisterInfo>( 240 *reg_info, m_scripted_process.GetTarget().GetArchitecture()); 241 } 242 243 return m_register_info_sp; 244 } 245