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