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