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 3159d8dd79SMed Ismail Bennani ScriptedThread::ScriptedThread(ScriptedProcess &process, Status &error) 32*1b86344fSMed Ismail Bennani : Thread(process, LLDB_INVALID_THREAD_ID), m_scripted_process(process), 33*1b86344fSMed Ismail Bennani m_scripted_thread_interface_sp( 34*1b86344fSMed Ismail Bennani m_scripted_process.GetInterface().CreateScriptedThreadInterface()) { 3559d8dd79SMed Ismail Bennani if (!process.IsValid()) { 3659d8dd79SMed Ismail Bennani error.SetErrorString("Invalid scripted process"); 3759d8dd79SMed Ismail Bennani return; 3859d8dd79SMed Ismail Bennani } 3959d8dd79SMed Ismail Bennani 4059d8dd79SMed Ismail Bennani process.CheckInterpreterAndScriptObject(); 4159d8dd79SMed Ismail Bennani 4259d8dd79SMed Ismail Bennani auto scripted_thread_interface = GetInterface(); 4359d8dd79SMed Ismail Bennani if (!scripted_thread_interface) { 4459d8dd79SMed Ismail Bennani error.SetErrorString("Failed to get scripted thread interface."); 4559d8dd79SMed Ismail Bennani return; 4659d8dd79SMed Ismail Bennani } 4759d8dd79SMed Ismail Bennani 4859d8dd79SMed Ismail Bennani llvm::Optional<std::string> class_name = 4959d8dd79SMed Ismail Bennani process.GetInterface().GetScriptedThreadPluginName(); 5059d8dd79SMed Ismail Bennani if (!class_name || class_name->empty()) { 5159d8dd79SMed Ismail Bennani error.SetErrorString("Failed to get scripted thread class name."); 5259d8dd79SMed Ismail Bennani return; 5359d8dd79SMed Ismail Bennani } 5459d8dd79SMed Ismail Bennani 5559d8dd79SMed Ismail Bennani ExecutionContext exe_ctx(process); 5659d8dd79SMed Ismail Bennani 5759d8dd79SMed Ismail Bennani StructuredData::GenericSP object_sp = 5859d8dd79SMed Ismail Bennani scripted_thread_interface->CreatePluginObject( 5959d8dd79SMed Ismail Bennani class_name->c_str(), exe_ctx, 60ad0f7d3dSMed Ismail Bennani process.m_scripted_process_info.GetArgsSP()); 6159d8dd79SMed Ismail Bennani if (!object_sp || !object_sp->IsValid()) { 6259d8dd79SMed Ismail Bennani error.SetErrorString("Failed to create valid script object"); 6359d8dd79SMed Ismail Bennani return; 6459d8dd79SMed Ismail Bennani } 6559d8dd79SMed Ismail Bennani 6659d8dd79SMed Ismail Bennani m_script_object_sp = object_sp; 6759d8dd79SMed Ismail Bennani 6859d8dd79SMed Ismail Bennani SetID(scripted_thread_interface->GetThreadID()); 6959d8dd79SMed Ismail Bennani } 7059d8dd79SMed Ismail Bennani 7159d8dd79SMed Ismail Bennani ScriptedThread::~ScriptedThread() { DestroyThread(); } 7259d8dd79SMed Ismail Bennani 7359d8dd79SMed Ismail Bennani const char *ScriptedThread::GetName() { 7459d8dd79SMed Ismail Bennani CheckInterpreterAndScriptObject(); 7559d8dd79SMed Ismail Bennani llvm::Optional<std::string> thread_name = GetInterface()->GetName(); 7659d8dd79SMed Ismail Bennani if (!thread_name) 7759d8dd79SMed Ismail Bennani return nullptr; 7859d8dd79SMed Ismail Bennani return ConstString(thread_name->c_str()).AsCString(); 7959d8dd79SMed Ismail Bennani } 8059d8dd79SMed Ismail Bennani 8159d8dd79SMed Ismail Bennani const char *ScriptedThread::GetQueueName() { 8259d8dd79SMed Ismail Bennani CheckInterpreterAndScriptObject(); 8359d8dd79SMed Ismail Bennani llvm::Optional<std::string> queue_name = GetInterface()->GetQueue(); 8459d8dd79SMed Ismail Bennani if (!queue_name) 8559d8dd79SMed Ismail Bennani return nullptr; 8659d8dd79SMed Ismail Bennani return ConstString(queue_name->c_str()).AsCString(); 8759d8dd79SMed Ismail Bennani } 8859d8dd79SMed Ismail Bennani 8959d8dd79SMed Ismail Bennani void ScriptedThread::WillResume(StateType resume_state) {} 9059d8dd79SMed Ismail Bennani 9159d8dd79SMed Ismail Bennani void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); } 9259d8dd79SMed Ismail Bennani 9359d8dd79SMed Ismail Bennani RegisterContextSP ScriptedThread::GetRegisterContext() { 94676576b6SMed Ismail Bennani if (!m_reg_context_sp) 95676576b6SMed Ismail Bennani m_reg_context_sp = CreateRegisterContextForFrame(nullptr); 9659d8dd79SMed Ismail Bennani return m_reg_context_sp; 9759d8dd79SMed Ismail Bennani } 9859d8dd79SMed Ismail Bennani 9959d8dd79SMed Ismail Bennani RegisterContextSP 10059d8dd79SMed Ismail Bennani ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) { 101676576b6SMed Ismail Bennani const uint32_t concrete_frame_idx = 102676576b6SMed Ismail Bennani frame ? frame->GetConcreteFrameIndex() : 0; 10359d8dd79SMed Ismail Bennani 104676576b6SMed Ismail Bennani if (concrete_frame_idx) 10559d8dd79SMed Ismail Bennani return GetUnwinder().CreateRegisterContextForFrame(frame); 106676576b6SMed Ismail Bennani 107676576b6SMed Ismail Bennani lldb::RegisterContextSP reg_ctx_sp; 108676576b6SMed Ismail Bennani Status error; 109676576b6SMed Ismail Bennani 110676576b6SMed Ismail Bennani llvm::Optional<std::string> reg_data = GetInterface()->GetRegisterContext(); 111676576b6SMed Ismail Bennani if (!reg_data) 112676576b6SMed Ismail Bennani return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 113676576b6SMed Ismail Bennani LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.", 114676576b6SMed Ismail Bennani error, LIBLLDB_LOG_THREAD); 115676576b6SMed Ismail Bennani 116676576b6SMed Ismail Bennani DataBufferSP data_sp( 117676576b6SMed Ismail Bennani std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size())); 118676576b6SMed Ismail Bennani 119676576b6SMed Ismail Bennani if (!data_sp->GetByteSize()) 120676576b6SMed Ismail Bennani return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 121676576b6SMed Ismail Bennani LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error, 122676576b6SMed Ismail Bennani LIBLLDB_LOG_THREAD); 123676576b6SMed Ismail Bennani 124676576b6SMed Ismail Bennani std::shared_ptr<RegisterContextMemory> reg_ctx_memory = 125676576b6SMed Ismail Bennani std::make_shared<RegisterContextMemory>( 126676576b6SMed Ismail Bennani *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS); 127676576b6SMed Ismail Bennani if (!reg_ctx_memory) 128676576b6SMed Ismail Bennani return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 129676576b6SMed Ismail Bennani LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error, 130676576b6SMed Ismail Bennani LIBLLDB_LOG_THREAD); 131676576b6SMed Ismail Bennani 132676576b6SMed Ismail Bennani reg_ctx_memory->SetAllRegisterData(data_sp); 133676576b6SMed Ismail Bennani m_reg_context_sp = reg_ctx_memory; 134676576b6SMed Ismail Bennani 135676576b6SMed Ismail Bennani return m_reg_context_sp; 13659d8dd79SMed Ismail Bennani } 13759d8dd79SMed Ismail Bennani 13859d8dd79SMed Ismail Bennani bool ScriptedThread::CalculateStopInfo() { 13959d8dd79SMed Ismail Bennani StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason(); 14059d8dd79SMed Ismail Bennani 14159d8dd79SMed Ismail Bennani Status error; 14259d8dd79SMed Ismail Bennani lldb::StopInfoSP stop_info_sp; 14359d8dd79SMed Ismail Bennani lldb::StopReason stop_reason_type; 14459d8dd79SMed Ismail Bennani 14559d8dd79SMed Ismail Bennani if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type)) 14659d8dd79SMed Ismail Bennani return GetInterface()->ErrorWithMessage<bool>( 14788a941baSMed Ismail Bennani LLVM_PRETTY_FUNCTION, 148676576b6SMed Ismail Bennani "Couldn't find value for key 'type' in stop reason dictionary.", error, 149676576b6SMed Ismail Bennani LIBLLDB_LOG_THREAD); 15059d8dd79SMed Ismail Bennani 15159d8dd79SMed Ismail Bennani StructuredData::Dictionary *data_dict; 15259d8dd79SMed Ismail Bennani if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict)) 15359d8dd79SMed Ismail Bennani return GetInterface()->ErrorWithMessage<bool>( 15488a941baSMed Ismail Bennani LLVM_PRETTY_FUNCTION, 155676576b6SMed Ismail Bennani "Couldn't find value for key 'type' in stop reason dictionary.", error, 156676576b6SMed Ismail Bennani LIBLLDB_LOG_THREAD); 15759d8dd79SMed Ismail Bennani 15859d8dd79SMed Ismail Bennani switch (stop_reason_type) { 15959d8dd79SMed Ismail Bennani case lldb::eStopReasonNone: 16059d8dd79SMed Ismail Bennani break; 16159d8dd79SMed Ismail Bennani case lldb::eStopReasonBreakpoint: { 16259d8dd79SMed Ismail Bennani lldb::break_id_t break_id; 16359d8dd79SMed Ismail Bennani data_dict->GetValueForKeyAsInteger("break_id", break_id, 16459d8dd79SMed Ismail Bennani LLDB_INVALID_BREAK_ID); 16559d8dd79SMed Ismail Bennani stop_info_sp = 16659d8dd79SMed Ismail Bennani StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id); 16759d8dd79SMed Ismail Bennani } break; 16859d8dd79SMed Ismail Bennani case lldb::eStopReasonSignal: { 16959d8dd79SMed Ismail Bennani int signal; 17059d8dd79SMed Ismail Bennani llvm::StringRef description; 17159d8dd79SMed Ismail Bennani data_dict->GetValueForKeyAsInteger("signal", signal, 17259d8dd79SMed Ismail Bennani LLDB_INVALID_SIGNAL_NUMBER); 17359d8dd79SMed Ismail Bennani data_dict->GetValueForKeyAsString("desc", description); 17459d8dd79SMed Ismail Bennani stop_info_sp = 17559d8dd79SMed Ismail Bennani StopInfo::CreateStopReasonWithSignal(*this, signal, description.data()); 17659d8dd79SMed Ismail Bennani } break; 17759d8dd79SMed Ismail Bennani default: 17859d8dd79SMed Ismail Bennani return GetInterface()->ErrorWithMessage<bool>( 17988a941baSMed Ismail Bennani LLVM_PRETTY_FUNCTION, 18059d8dd79SMed Ismail Bennani llvm::Twine("Unsupported stop reason type (" + 18159d8dd79SMed Ismail Bennani llvm::Twine(stop_reason_type) + llvm::Twine(").")) 18259d8dd79SMed Ismail Bennani .str(), 183676576b6SMed Ismail Bennani error, LIBLLDB_LOG_THREAD); 18459d8dd79SMed Ismail Bennani } 18559d8dd79SMed Ismail Bennani 18659d8dd79SMed Ismail Bennani SetStopInfo(stop_info_sp); 18759d8dd79SMed Ismail Bennani return true; 18859d8dd79SMed Ismail Bennani } 18959d8dd79SMed Ismail Bennani 19059d8dd79SMed Ismail Bennani void ScriptedThread::RefreshStateAfterStop() { 191676576b6SMed Ismail Bennani GetRegisterContext()->InvalidateIfNeeded(/*force=*/false); 19259d8dd79SMed Ismail Bennani } 19359d8dd79SMed Ismail Bennani 19459d8dd79SMed Ismail Bennani lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const { 195*1b86344fSMed Ismail Bennani return m_scripted_thread_interface_sp; 19659d8dd79SMed Ismail Bennani } 19759d8dd79SMed Ismail Bennani 19859d8dd79SMed Ismail Bennani std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() { 19959d8dd79SMed Ismail Bennani CheckInterpreterAndScriptObject(); 20059d8dd79SMed Ismail Bennani 20159d8dd79SMed Ismail Bennani if (!m_register_info_sp) { 20259d8dd79SMed Ismail Bennani StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo(); 203caea440aSMed Ismail Bennani 204caea440aSMed Ismail Bennani Status error; 20559d8dd79SMed Ismail Bennani if (!reg_info) 206caea440aSMed Ismail Bennani return GetInterface() 207caea440aSMed Ismail Bennani ->ErrorWithMessage<std::shared_ptr<DynamicRegisterInfo>>( 208caea440aSMed Ismail Bennani LLVM_PRETTY_FUNCTION, 209caea440aSMed Ismail Bennani "Failed to get scripted thread registers info.", error, 210caea440aSMed Ismail Bennani LIBLLDB_LOG_THREAD); 21159d8dd79SMed Ismail Bennani 21259d8dd79SMed Ismail Bennani m_register_info_sp = std::make_shared<DynamicRegisterInfo>( 21359d8dd79SMed Ismail Bennani *reg_info, m_scripted_process.GetTarget().GetArchitecture()); 21459d8dd79SMed Ismail Bennani } 21559d8dd79SMed Ismail Bennani 21659d8dd79SMed Ismail Bennani return m_register_info_sp; 21759d8dd79SMed Ismail Bennani } 218