159d8dd79SMed Ismail Bennani //===-- ScriptedThread.cpp ------------------------------------------------===// 259d8dd79SMed Ismail Bennani // 359d8dd79SMed Ismail Bennani // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 459d8dd79SMed Ismail Bennani // See https://llvm.org/LICENSE.txt for license information. 559d8dd79SMed Ismail Bennani // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 659d8dd79SMed Ismail Bennani // 759d8dd79SMed Ismail Bennani //===----------------------------------------------------------------------===// 859d8dd79SMed Ismail Bennani 959d8dd79SMed Ismail Bennani #include "ScriptedThread.h" 1059d8dd79SMed Ismail Bennani 1159d8dd79SMed Ismail Bennani #include "Plugins/Process/Utility/RegisterContextThreadMemory.h" 1259d8dd79SMed Ismail Bennani #include "lldb/Target/OperatingSystem.h" 1359d8dd79SMed Ismail Bennani #include "lldb/Target/Process.h" 1459d8dd79SMed Ismail Bennani #include "lldb/Target/RegisterContext.h" 1559d8dd79SMed Ismail Bennani #include "lldb/Target/StopInfo.h" 1659d8dd79SMed Ismail Bennani #include "lldb/Target/Unwind.h" 1759d8dd79SMed Ismail Bennani #include "lldb/Utility/DataBufferHeap.h" 1859d8dd79SMed Ismail Bennani #include "lldb/Utility/Log.h" 1959d8dd79SMed Ismail Bennani #include "lldb/Utility/Logging.h" 2059d8dd79SMed Ismail Bennani 2159d8dd79SMed Ismail Bennani #include <memory> 2259d8dd79SMed Ismail Bennani 2359d8dd79SMed Ismail Bennani using namespace lldb; 2459d8dd79SMed Ismail Bennani using namespace lldb_private; 2559d8dd79SMed Ismail Bennani 2659d8dd79SMed Ismail Bennani void ScriptedThread::CheckInterpreterAndScriptObject() const { 2759d8dd79SMed Ismail Bennani lldbassert(m_script_object_sp && "Invalid Script Object."); 2859d8dd79SMed Ismail Bennani lldbassert(GetInterface() && "Invalid Scripted Thread Interface."); 2959d8dd79SMed Ismail Bennani } 3059d8dd79SMed Ismail Bennani 3145148bfeSMed Ismail Bennani llvm::Expected<std::shared_ptr<ScriptedThread>> 3245148bfeSMed Ismail Bennani ScriptedThread::Create(ScriptedProcess &process, 3345148bfeSMed Ismail Bennani StructuredData::Generic *script_object) { 3445148bfeSMed Ismail Bennani if (!process.IsValid()) 3545148bfeSMed Ismail Bennani return llvm::createStringError(llvm::inconvertibleErrorCode(), 3645148bfeSMed Ismail Bennani "Invalid scripted process."); 3759d8dd79SMed Ismail Bennani 3859d8dd79SMed Ismail Bennani process.CheckInterpreterAndScriptObject(); 3959d8dd79SMed Ismail Bennani 4045148bfeSMed Ismail Bennani auto scripted_thread_interface = 4145148bfeSMed Ismail Bennani process.GetInterface().CreateScriptedThreadInterface(); 4245148bfeSMed Ismail Bennani if (!scripted_thread_interface) 4345148bfeSMed Ismail Bennani return llvm::createStringError( 4445148bfeSMed Ismail Bennani llvm::inconvertibleErrorCode(), 4545148bfeSMed Ismail Bennani "Failed to create scripted thread interface."); 4659d8dd79SMed Ismail Bennani 4745148bfeSMed Ismail Bennani llvm::StringRef thread_class_name; 4845148bfeSMed Ismail Bennani if (!script_object) { 4959d8dd79SMed Ismail Bennani llvm::Optional<std::string> class_name = 5059d8dd79SMed Ismail Bennani process.GetInterface().GetScriptedThreadPluginName(); 5145148bfeSMed Ismail Bennani if (!class_name || class_name->empty()) 5245148bfeSMed Ismail Bennani return llvm::createStringError( 5345148bfeSMed Ismail Bennani llvm::inconvertibleErrorCode(), 5445148bfeSMed Ismail Bennani "Failed to get scripted thread class name."); 5545148bfeSMed Ismail Bennani thread_class_name = *class_name; 5659d8dd79SMed Ismail Bennani } 5759d8dd79SMed Ismail Bennani 5859d8dd79SMed Ismail Bennani ExecutionContext exe_ctx(process); 5945148bfeSMed Ismail Bennani StructuredData::GenericSP owned_script_object_sp = 6045148bfeSMed Ismail Bennani scripted_thread_interface->CreatePluginObject( 6145148bfeSMed Ismail Bennani thread_class_name, exe_ctx, 6245148bfeSMed Ismail Bennani process.m_scripted_process_info.GetArgsSP(), script_object); 6359d8dd79SMed Ismail Bennani 6445148bfeSMed Ismail Bennani if (!owned_script_object_sp) 6545148bfeSMed Ismail Bennani return llvm::createStringError(llvm::inconvertibleErrorCode(), 6645148bfeSMed Ismail Bennani "Failed to create script object."); 6745148bfeSMed Ismail Bennani if (!owned_script_object_sp->IsValid()) 6845148bfeSMed Ismail Bennani return llvm::createStringError(llvm::inconvertibleErrorCode(), 6945148bfeSMed Ismail Bennani "Created script object is invalid."); 7059d8dd79SMed Ismail Bennani 71d3e0f7e1SMed Ismail Bennani lldb::tid_t tid = scripted_thread_interface->GetThreadID(); 7245148bfeSMed Ismail Bennani 7345148bfeSMed Ismail Bennani return std::make_shared<ScriptedThread>(process, scripted_thread_interface, 7445148bfeSMed Ismail Bennani tid, owned_script_object_sp); 7559d8dd79SMed Ismail Bennani } 7659d8dd79SMed Ismail Bennani 7745148bfeSMed Ismail Bennani ScriptedThread::ScriptedThread(ScriptedProcess &process, 7845148bfeSMed Ismail Bennani ScriptedThreadInterfaceSP interface_sp, 7945148bfeSMed Ismail Bennani lldb::tid_t tid, 8045148bfeSMed Ismail Bennani StructuredData::GenericSP script_object_sp) 8145148bfeSMed Ismail Bennani : Thread(process, tid), m_scripted_process(process), 8245148bfeSMed Ismail Bennani m_scripted_thread_interface_sp(interface_sp), 8345148bfeSMed Ismail Bennani m_script_object_sp(script_object_sp) {} 8445148bfeSMed Ismail Bennani 8559d8dd79SMed Ismail Bennani ScriptedThread::~ScriptedThread() { DestroyThread(); } 8659d8dd79SMed Ismail Bennani 8759d8dd79SMed Ismail Bennani const char *ScriptedThread::GetName() { 8859d8dd79SMed Ismail Bennani CheckInterpreterAndScriptObject(); 8959d8dd79SMed Ismail Bennani llvm::Optional<std::string> thread_name = GetInterface()->GetName(); 9059d8dd79SMed Ismail Bennani if (!thread_name) 9159d8dd79SMed Ismail Bennani return nullptr; 9259d8dd79SMed Ismail Bennani return ConstString(thread_name->c_str()).AsCString(); 9359d8dd79SMed Ismail Bennani } 9459d8dd79SMed Ismail Bennani 9559d8dd79SMed Ismail Bennani const char *ScriptedThread::GetQueueName() { 9659d8dd79SMed Ismail Bennani CheckInterpreterAndScriptObject(); 9759d8dd79SMed Ismail Bennani llvm::Optional<std::string> queue_name = GetInterface()->GetQueue(); 9859d8dd79SMed Ismail Bennani if (!queue_name) 9959d8dd79SMed Ismail Bennani return nullptr; 10059d8dd79SMed Ismail Bennani return ConstString(queue_name->c_str()).AsCString(); 10159d8dd79SMed Ismail Bennani } 10259d8dd79SMed Ismail Bennani 10359d8dd79SMed Ismail Bennani void ScriptedThread::WillResume(StateType resume_state) {} 10459d8dd79SMed Ismail Bennani 10559d8dd79SMed Ismail Bennani void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); } 10659d8dd79SMed Ismail Bennani 10759d8dd79SMed Ismail Bennani RegisterContextSP ScriptedThread::GetRegisterContext() { 108676576b6SMed Ismail Bennani if (!m_reg_context_sp) 109676576b6SMed Ismail Bennani m_reg_context_sp = CreateRegisterContextForFrame(nullptr); 11059d8dd79SMed Ismail Bennani return m_reg_context_sp; 11159d8dd79SMed Ismail Bennani } 11259d8dd79SMed Ismail Bennani 11359d8dd79SMed Ismail Bennani RegisterContextSP 11459d8dd79SMed Ismail Bennani ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) { 115676576b6SMed Ismail Bennani const uint32_t concrete_frame_idx = 116676576b6SMed Ismail Bennani frame ? frame->GetConcreteFrameIndex() : 0; 11759d8dd79SMed Ismail Bennani 118676576b6SMed Ismail Bennani if (concrete_frame_idx) 11959d8dd79SMed Ismail Bennani return GetUnwinder().CreateRegisterContextForFrame(frame); 120676576b6SMed Ismail Bennani 121676576b6SMed Ismail Bennani lldb::RegisterContextSP reg_ctx_sp; 122676576b6SMed Ismail Bennani Status error; 123676576b6SMed Ismail Bennani 124676576b6SMed Ismail Bennani llvm::Optional<std::string> reg_data = GetInterface()->GetRegisterContext(); 125676576b6SMed Ismail Bennani if (!reg_data) 126676576b6SMed Ismail Bennani return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 127676576b6SMed Ismail Bennani LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.", 128*a007a6d8SPavel Labath error, LLDBLog::Thread); 129676576b6SMed Ismail Bennani 130676576b6SMed Ismail Bennani DataBufferSP data_sp( 131676576b6SMed Ismail Bennani std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size())); 132676576b6SMed Ismail Bennani 133676576b6SMed Ismail Bennani if (!data_sp->GetByteSize()) 134676576b6SMed Ismail Bennani return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 135676576b6SMed Ismail Bennani LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error, 136*a007a6d8SPavel Labath LLDBLog::Thread); 137676576b6SMed Ismail Bennani 138676576b6SMed Ismail Bennani std::shared_ptr<RegisterContextMemory> reg_ctx_memory = 139676576b6SMed Ismail Bennani std::make_shared<RegisterContextMemory>( 140676576b6SMed Ismail Bennani *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS); 141676576b6SMed Ismail Bennani if (!reg_ctx_memory) 142676576b6SMed Ismail Bennani return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 143676576b6SMed Ismail Bennani LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error, 144*a007a6d8SPavel Labath LLDBLog::Thread); 145676576b6SMed Ismail Bennani 146676576b6SMed Ismail Bennani reg_ctx_memory->SetAllRegisterData(data_sp); 147676576b6SMed Ismail Bennani m_reg_context_sp = reg_ctx_memory; 148676576b6SMed Ismail Bennani 149676576b6SMed Ismail Bennani return m_reg_context_sp; 15059d8dd79SMed Ismail Bennani } 15159d8dd79SMed Ismail Bennani 15259d8dd79SMed Ismail Bennani bool ScriptedThread::CalculateStopInfo() { 15359d8dd79SMed Ismail Bennani StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason(); 15459d8dd79SMed Ismail Bennani 15559d8dd79SMed Ismail Bennani Status error; 156cfa55bfeSMed Ismail Bennani if (!dict_sp) 157cfa55bfeSMed Ismail Bennani return GetInterface()->ErrorWithMessage<bool>( 158cfa55bfeSMed Ismail Bennani LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error, 159*a007a6d8SPavel Labath LLDBLog::Thread); 160cfa55bfeSMed Ismail Bennani 16159d8dd79SMed Ismail Bennani lldb::StopInfoSP stop_info_sp; 16259d8dd79SMed Ismail Bennani lldb::StopReason stop_reason_type; 16359d8dd79SMed Ismail Bennani 16459d8dd79SMed Ismail Bennani if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type)) 16559d8dd79SMed Ismail Bennani return GetInterface()->ErrorWithMessage<bool>( 16688a941baSMed Ismail Bennani LLVM_PRETTY_FUNCTION, 167676576b6SMed Ismail Bennani "Couldn't find value for key 'type' in stop reason dictionary.", error, 168*a007a6d8SPavel Labath LLDBLog::Thread); 16959d8dd79SMed Ismail Bennani 17059d8dd79SMed Ismail Bennani StructuredData::Dictionary *data_dict; 17159d8dd79SMed Ismail Bennani if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict)) 17259d8dd79SMed Ismail Bennani return GetInterface()->ErrorWithMessage<bool>( 17388a941baSMed Ismail Bennani LLVM_PRETTY_FUNCTION, 174cfa55bfeSMed Ismail Bennani "Couldn't find value for key 'data' in stop reason dictionary.", error, 175*a007a6d8SPavel Labath LLDBLog::Thread); 17659d8dd79SMed Ismail Bennani 17759d8dd79SMed Ismail Bennani switch (stop_reason_type) { 17859d8dd79SMed Ismail Bennani case lldb::eStopReasonNone: 179cfa55bfeSMed Ismail Bennani return true; 18059d8dd79SMed Ismail Bennani case lldb::eStopReasonBreakpoint: { 18159d8dd79SMed Ismail Bennani lldb::break_id_t break_id; 18259d8dd79SMed Ismail Bennani data_dict->GetValueForKeyAsInteger("break_id", break_id, 18359d8dd79SMed Ismail Bennani LLDB_INVALID_BREAK_ID); 18459d8dd79SMed Ismail Bennani stop_info_sp = 18559d8dd79SMed Ismail Bennani StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id); 18659d8dd79SMed Ismail Bennani } break; 18759d8dd79SMed Ismail Bennani case lldb::eStopReasonSignal: { 18859d8dd79SMed Ismail Bennani int signal; 18959d8dd79SMed Ismail Bennani llvm::StringRef description; 19059d8dd79SMed Ismail Bennani data_dict->GetValueForKeyAsInteger("signal", signal, 19159d8dd79SMed Ismail Bennani LLDB_INVALID_SIGNAL_NUMBER); 19259d8dd79SMed Ismail Bennani data_dict->GetValueForKeyAsString("desc", description); 19359d8dd79SMed Ismail Bennani stop_info_sp = 19459d8dd79SMed Ismail Bennani StopInfo::CreateStopReasonWithSignal(*this, signal, description.data()); 19559d8dd79SMed Ismail Bennani } break; 196cfa55bfeSMed Ismail Bennani case lldb::eStopReasonException: { 197cfa55bfeSMed Ismail Bennani llvm::StringRef description; 198cfa55bfeSMed Ismail Bennani data_dict->GetValueForKeyAsString("desc", description); 199cfa55bfeSMed Ismail Bennani 200cfa55bfeSMed Ismail Bennani stop_info_sp = 201cfa55bfeSMed Ismail Bennani StopInfo::CreateStopReasonWithException(*this, description.data()); 202cfa55bfeSMed Ismail Bennani } break; 20359d8dd79SMed Ismail Bennani default: 20459d8dd79SMed Ismail Bennani return GetInterface()->ErrorWithMessage<bool>( 20588a941baSMed Ismail Bennani LLVM_PRETTY_FUNCTION, 20659d8dd79SMed Ismail Bennani llvm::Twine("Unsupported stop reason type (" + 20759d8dd79SMed Ismail Bennani llvm::Twine(stop_reason_type) + llvm::Twine(").")) 20859d8dd79SMed Ismail Bennani .str(), 209*a007a6d8SPavel Labath error, LLDBLog::Thread); 21059d8dd79SMed Ismail Bennani } 21159d8dd79SMed Ismail Bennani 212cfa55bfeSMed Ismail Bennani if (!stop_info_sp) 213cfa55bfeSMed Ismail Bennani return false; 214cfa55bfeSMed Ismail Bennani 21559d8dd79SMed Ismail Bennani SetStopInfo(stop_info_sp); 21659d8dd79SMed Ismail Bennani return true; 21759d8dd79SMed Ismail Bennani } 21859d8dd79SMed Ismail Bennani 21959d8dd79SMed Ismail Bennani void ScriptedThread::RefreshStateAfterStop() { 220676576b6SMed Ismail Bennani GetRegisterContext()->InvalidateIfNeeded(/*force=*/false); 22159d8dd79SMed Ismail Bennani } 22259d8dd79SMed Ismail Bennani 22359d8dd79SMed Ismail Bennani lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const { 2241b86344fSMed Ismail Bennani return m_scripted_thread_interface_sp; 22559d8dd79SMed Ismail Bennani } 22659d8dd79SMed Ismail Bennani 22759d8dd79SMed Ismail Bennani std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() { 22859d8dd79SMed Ismail Bennani CheckInterpreterAndScriptObject(); 22959d8dd79SMed Ismail Bennani 23059d8dd79SMed Ismail Bennani if (!m_register_info_sp) { 23159d8dd79SMed Ismail Bennani StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo(); 232caea440aSMed Ismail Bennani 233caea440aSMed Ismail Bennani Status error; 23459d8dd79SMed Ismail Bennani if (!reg_info) 235caea440aSMed Ismail Bennani return GetInterface() 236caea440aSMed Ismail Bennani ->ErrorWithMessage<std::shared_ptr<DynamicRegisterInfo>>( 237caea440aSMed Ismail Bennani LLVM_PRETTY_FUNCTION, 238caea440aSMed Ismail Bennani "Failed to get scripted thread registers info.", error, 239*a007a6d8SPavel Labath LLDBLog::Thread); 24059d8dd79SMed Ismail Bennani 24159d8dd79SMed Ismail Bennani m_register_info_sp = std::make_shared<DynamicRegisterInfo>( 24259d8dd79SMed Ismail Bennani *reg_info, m_scripted_process.GetTarget().GetArchitecture()); 24359d8dd79SMed Ismail Bennani } 24459d8dd79SMed Ismail Bennani 24559d8dd79SMed Ismail Bennani return m_register_info_sp; 24659d8dd79SMed Ismail Bennani } 247