1349cc55cSDimitry Andric //===-- ScriptedThread.cpp ------------------------------------------------===// 2349cc55cSDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6349cc55cSDimitry Andric // 7349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8349cc55cSDimitry Andric 9349cc55cSDimitry Andric #include "ScriptedThread.h" 10349cc55cSDimitry Andric 11349cc55cSDimitry Andric #include "Plugins/Process/Utility/RegisterContextThreadMemory.h" 12349cc55cSDimitry Andric #include "lldb/Target/OperatingSystem.h" 13349cc55cSDimitry Andric #include "lldb/Target/Process.h" 14349cc55cSDimitry Andric #include "lldb/Target/RegisterContext.h" 15349cc55cSDimitry Andric #include "lldb/Target/StopInfo.h" 16349cc55cSDimitry Andric #include "lldb/Target/Unwind.h" 17349cc55cSDimitry Andric #include "lldb/Utility/DataBufferHeap.h" 18349cc55cSDimitry Andric #include "lldb/Utility/Log.h" 19349cc55cSDimitry Andric #include "lldb/Utility/Logging.h" 20349cc55cSDimitry Andric 21349cc55cSDimitry Andric #include <memory> 22349cc55cSDimitry Andric 23349cc55cSDimitry Andric using namespace lldb; 24349cc55cSDimitry Andric using namespace lldb_private; 25349cc55cSDimitry Andric 26349cc55cSDimitry Andric void ScriptedThread::CheckInterpreterAndScriptObject() const { 27349cc55cSDimitry Andric lldbassert(m_script_object_sp && "Invalid Script Object."); 28349cc55cSDimitry Andric lldbassert(GetInterface() && "Invalid Scripted Thread Interface."); 29349cc55cSDimitry Andric } 30349cc55cSDimitry Andric 31*04eeddc0SDimitry Andric llvm::Expected<std::shared_ptr<ScriptedThread>> 32*04eeddc0SDimitry Andric ScriptedThread::Create(ScriptedProcess &process, 33*04eeddc0SDimitry Andric StructuredData::Generic *script_object) { 34*04eeddc0SDimitry Andric if (!process.IsValid()) 35*04eeddc0SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 36*04eeddc0SDimitry Andric "Invalid scripted process."); 37349cc55cSDimitry Andric 38349cc55cSDimitry Andric process.CheckInterpreterAndScriptObject(); 39349cc55cSDimitry Andric 40*04eeddc0SDimitry Andric auto scripted_thread_interface = 41*04eeddc0SDimitry Andric process.GetInterface().CreateScriptedThreadInterface(); 42*04eeddc0SDimitry Andric if (!scripted_thread_interface) 43*04eeddc0SDimitry Andric return llvm::createStringError( 44*04eeddc0SDimitry Andric llvm::inconvertibleErrorCode(), 45*04eeddc0SDimitry Andric "Failed to create scripted thread interface."); 46349cc55cSDimitry Andric 47*04eeddc0SDimitry Andric llvm::StringRef thread_class_name; 48*04eeddc0SDimitry Andric if (!script_object) { 49349cc55cSDimitry Andric llvm::Optional<std::string> class_name = 50349cc55cSDimitry Andric process.GetInterface().GetScriptedThreadPluginName(); 51*04eeddc0SDimitry Andric if (!class_name || class_name->empty()) 52*04eeddc0SDimitry Andric return llvm::createStringError( 53*04eeddc0SDimitry Andric llvm::inconvertibleErrorCode(), 54*04eeddc0SDimitry Andric "Failed to get scripted thread class name."); 55*04eeddc0SDimitry Andric thread_class_name = *class_name; 56349cc55cSDimitry Andric } 57349cc55cSDimitry Andric 58349cc55cSDimitry Andric ExecutionContext exe_ctx(process); 59*04eeddc0SDimitry Andric StructuredData::GenericSP owned_script_object_sp = 60349cc55cSDimitry Andric scripted_thread_interface->CreatePluginObject( 61*04eeddc0SDimitry Andric thread_class_name, exe_ctx, 62*04eeddc0SDimitry Andric process.m_scripted_process_info.GetArgsSP(), script_object); 63*04eeddc0SDimitry Andric 64*04eeddc0SDimitry Andric if (!owned_script_object_sp) 65*04eeddc0SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 66*04eeddc0SDimitry Andric "Failed to create script object."); 67*04eeddc0SDimitry Andric if (!owned_script_object_sp->IsValid()) 68*04eeddc0SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 69*04eeddc0SDimitry Andric "Created script object is invalid."); 70*04eeddc0SDimitry Andric 71*04eeddc0SDimitry Andric lldb::tid_t tid = scripted_thread_interface->GetThreadID(); 72*04eeddc0SDimitry Andric 73*04eeddc0SDimitry Andric return std::make_shared<ScriptedThread>(process, scripted_thread_interface, 74*04eeddc0SDimitry Andric tid, owned_script_object_sp); 75349cc55cSDimitry Andric } 76349cc55cSDimitry Andric 77*04eeddc0SDimitry Andric ScriptedThread::ScriptedThread(ScriptedProcess &process, 78*04eeddc0SDimitry Andric ScriptedThreadInterfaceSP interface_sp, 79*04eeddc0SDimitry Andric lldb::tid_t tid, 80*04eeddc0SDimitry Andric StructuredData::GenericSP script_object_sp) 81*04eeddc0SDimitry Andric : Thread(process, tid), m_scripted_process(process), 82*04eeddc0SDimitry Andric m_scripted_thread_interface_sp(interface_sp), 83*04eeddc0SDimitry Andric m_script_object_sp(script_object_sp) {} 84349cc55cSDimitry Andric 85349cc55cSDimitry Andric ScriptedThread::~ScriptedThread() { DestroyThread(); } 86349cc55cSDimitry Andric 87349cc55cSDimitry Andric const char *ScriptedThread::GetName() { 88349cc55cSDimitry Andric CheckInterpreterAndScriptObject(); 89349cc55cSDimitry Andric llvm::Optional<std::string> thread_name = GetInterface()->GetName(); 90349cc55cSDimitry Andric if (!thread_name) 91349cc55cSDimitry Andric return nullptr; 92349cc55cSDimitry Andric return ConstString(thread_name->c_str()).AsCString(); 93349cc55cSDimitry Andric } 94349cc55cSDimitry Andric 95349cc55cSDimitry Andric const char *ScriptedThread::GetQueueName() { 96349cc55cSDimitry Andric CheckInterpreterAndScriptObject(); 97349cc55cSDimitry Andric llvm::Optional<std::string> queue_name = GetInterface()->GetQueue(); 98349cc55cSDimitry Andric if (!queue_name) 99349cc55cSDimitry Andric return nullptr; 100349cc55cSDimitry Andric return ConstString(queue_name->c_str()).AsCString(); 101349cc55cSDimitry Andric } 102349cc55cSDimitry Andric 103349cc55cSDimitry Andric void ScriptedThread::WillResume(StateType resume_state) {} 104349cc55cSDimitry Andric 105349cc55cSDimitry Andric void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); } 106349cc55cSDimitry Andric 107349cc55cSDimitry Andric RegisterContextSP ScriptedThread::GetRegisterContext() { 108349cc55cSDimitry Andric if (!m_reg_context_sp) 109349cc55cSDimitry Andric m_reg_context_sp = CreateRegisterContextForFrame(nullptr); 110349cc55cSDimitry Andric return m_reg_context_sp; 111349cc55cSDimitry Andric } 112349cc55cSDimitry Andric 113349cc55cSDimitry Andric RegisterContextSP 114349cc55cSDimitry Andric ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) { 115349cc55cSDimitry Andric const uint32_t concrete_frame_idx = 116349cc55cSDimitry Andric frame ? frame->GetConcreteFrameIndex() : 0; 117349cc55cSDimitry Andric 118349cc55cSDimitry Andric if (concrete_frame_idx) 119349cc55cSDimitry Andric return GetUnwinder().CreateRegisterContextForFrame(frame); 120349cc55cSDimitry Andric 121349cc55cSDimitry Andric lldb::RegisterContextSP reg_ctx_sp; 122349cc55cSDimitry Andric Status error; 123349cc55cSDimitry Andric 124349cc55cSDimitry Andric llvm::Optional<std::string> reg_data = GetInterface()->GetRegisterContext(); 125349cc55cSDimitry Andric if (!reg_data) 126349cc55cSDimitry Andric return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 127349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.", 128349cc55cSDimitry Andric error, LIBLLDB_LOG_THREAD); 129349cc55cSDimitry Andric 130349cc55cSDimitry Andric DataBufferSP data_sp( 131349cc55cSDimitry Andric std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size())); 132349cc55cSDimitry Andric 133349cc55cSDimitry Andric if (!data_sp->GetByteSize()) 134349cc55cSDimitry Andric return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 135349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error, 136349cc55cSDimitry Andric LIBLLDB_LOG_THREAD); 137349cc55cSDimitry Andric 138349cc55cSDimitry Andric std::shared_ptr<RegisterContextMemory> reg_ctx_memory = 139349cc55cSDimitry Andric std::make_shared<RegisterContextMemory>( 140349cc55cSDimitry Andric *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS); 141349cc55cSDimitry Andric if (!reg_ctx_memory) 142349cc55cSDimitry Andric return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 143349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error, 144349cc55cSDimitry Andric LIBLLDB_LOG_THREAD); 145349cc55cSDimitry Andric 146349cc55cSDimitry Andric reg_ctx_memory->SetAllRegisterData(data_sp); 147349cc55cSDimitry Andric m_reg_context_sp = reg_ctx_memory; 148349cc55cSDimitry Andric 149349cc55cSDimitry Andric return m_reg_context_sp; 150349cc55cSDimitry Andric } 151349cc55cSDimitry Andric 152349cc55cSDimitry Andric bool ScriptedThread::CalculateStopInfo() { 153349cc55cSDimitry Andric StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason(); 154349cc55cSDimitry Andric 155349cc55cSDimitry Andric Status error; 156*04eeddc0SDimitry Andric if (!dict_sp) 157*04eeddc0SDimitry Andric return GetInterface()->ErrorWithMessage<bool>( 158*04eeddc0SDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error, 159*04eeddc0SDimitry Andric LIBLLDB_LOG_THREAD); 160*04eeddc0SDimitry Andric 161349cc55cSDimitry Andric lldb::StopInfoSP stop_info_sp; 162349cc55cSDimitry Andric lldb::StopReason stop_reason_type; 163349cc55cSDimitry Andric 164349cc55cSDimitry Andric if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type)) 165349cc55cSDimitry Andric return GetInterface()->ErrorWithMessage<bool>( 166349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, 167349cc55cSDimitry Andric "Couldn't find value for key 'type' in stop reason dictionary.", error, 168349cc55cSDimitry Andric LIBLLDB_LOG_THREAD); 169349cc55cSDimitry Andric 170349cc55cSDimitry Andric StructuredData::Dictionary *data_dict; 171349cc55cSDimitry Andric if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict)) 172349cc55cSDimitry Andric return GetInterface()->ErrorWithMessage<bool>( 173349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, 174*04eeddc0SDimitry Andric "Couldn't find value for key 'data' in stop reason dictionary.", error, 175349cc55cSDimitry Andric LIBLLDB_LOG_THREAD); 176349cc55cSDimitry Andric 177349cc55cSDimitry Andric switch (stop_reason_type) { 178349cc55cSDimitry Andric case lldb::eStopReasonNone: 179*04eeddc0SDimitry Andric return true; 180349cc55cSDimitry Andric case lldb::eStopReasonBreakpoint: { 181349cc55cSDimitry Andric lldb::break_id_t break_id; 182349cc55cSDimitry Andric data_dict->GetValueForKeyAsInteger("break_id", break_id, 183349cc55cSDimitry Andric LLDB_INVALID_BREAK_ID); 184349cc55cSDimitry Andric stop_info_sp = 185349cc55cSDimitry Andric StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id); 186349cc55cSDimitry Andric } break; 187349cc55cSDimitry Andric case lldb::eStopReasonSignal: { 188349cc55cSDimitry Andric int signal; 189349cc55cSDimitry Andric llvm::StringRef description; 190349cc55cSDimitry Andric data_dict->GetValueForKeyAsInteger("signal", signal, 191349cc55cSDimitry Andric LLDB_INVALID_SIGNAL_NUMBER); 192349cc55cSDimitry Andric data_dict->GetValueForKeyAsString("desc", description); 193349cc55cSDimitry Andric stop_info_sp = 194349cc55cSDimitry Andric StopInfo::CreateStopReasonWithSignal(*this, signal, description.data()); 195349cc55cSDimitry Andric } break; 196*04eeddc0SDimitry Andric case lldb::eStopReasonException: { 197*04eeddc0SDimitry Andric llvm::StringRef description; 198*04eeddc0SDimitry Andric data_dict->GetValueForKeyAsString("desc", description); 199*04eeddc0SDimitry Andric 200*04eeddc0SDimitry Andric stop_info_sp = 201*04eeddc0SDimitry Andric StopInfo::CreateStopReasonWithException(*this, description.data()); 202*04eeddc0SDimitry Andric } break; 203349cc55cSDimitry Andric default: 204349cc55cSDimitry Andric return GetInterface()->ErrorWithMessage<bool>( 205349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, 206349cc55cSDimitry Andric llvm::Twine("Unsupported stop reason type (" + 207349cc55cSDimitry Andric llvm::Twine(stop_reason_type) + llvm::Twine(").")) 208349cc55cSDimitry Andric .str(), 209349cc55cSDimitry Andric error, LIBLLDB_LOG_THREAD); 210349cc55cSDimitry Andric } 211349cc55cSDimitry Andric 212*04eeddc0SDimitry Andric if (!stop_info_sp) 213*04eeddc0SDimitry Andric return false; 214*04eeddc0SDimitry Andric 215349cc55cSDimitry Andric SetStopInfo(stop_info_sp); 216349cc55cSDimitry Andric return true; 217349cc55cSDimitry Andric } 218349cc55cSDimitry Andric 219349cc55cSDimitry Andric void ScriptedThread::RefreshStateAfterStop() { 220349cc55cSDimitry Andric GetRegisterContext()->InvalidateIfNeeded(/*force=*/false); 221349cc55cSDimitry Andric } 222349cc55cSDimitry Andric 223349cc55cSDimitry Andric lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const { 224*04eeddc0SDimitry Andric return m_scripted_thread_interface_sp; 225349cc55cSDimitry Andric } 226349cc55cSDimitry Andric 227349cc55cSDimitry Andric std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() { 228349cc55cSDimitry Andric CheckInterpreterAndScriptObject(); 229349cc55cSDimitry Andric 230349cc55cSDimitry Andric if (!m_register_info_sp) { 231349cc55cSDimitry Andric StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo(); 2320eae32dcSDimitry Andric 2330eae32dcSDimitry Andric Status error; 234349cc55cSDimitry Andric if (!reg_info) 2350eae32dcSDimitry Andric return GetInterface() 2360eae32dcSDimitry Andric ->ErrorWithMessage<std::shared_ptr<DynamicRegisterInfo>>( 2370eae32dcSDimitry Andric LLVM_PRETTY_FUNCTION, 2380eae32dcSDimitry Andric "Failed to get scripted thread registers info.", error, 2390eae32dcSDimitry Andric LIBLLDB_LOG_THREAD); 240349cc55cSDimitry Andric 241349cc55cSDimitry Andric m_register_info_sp = std::make_shared<DynamicRegisterInfo>( 242349cc55cSDimitry Andric *reg_info, m_scripted_process.GetTarget().GetArchitecture()); 243349cc55cSDimitry Andric } 244349cc55cSDimitry Andric 245349cc55cSDimitry Andric return m_register_info_sp; 246349cc55cSDimitry Andric } 247