1*349cc55cSDimitry Andric //===-- ScriptedThread.cpp ------------------------------------------------===// 2*349cc55cSDimitry Andric // 3*349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*349cc55cSDimitry Andric // 7*349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8*349cc55cSDimitry Andric 9*349cc55cSDimitry Andric #include "ScriptedThread.h" 10*349cc55cSDimitry Andric 11*349cc55cSDimitry Andric #include "Plugins/Process/Utility/RegisterContextThreadMemory.h" 12*349cc55cSDimitry Andric #include "lldb/Target/OperatingSystem.h" 13*349cc55cSDimitry Andric #include "lldb/Target/Process.h" 14*349cc55cSDimitry Andric #include "lldb/Target/RegisterContext.h" 15*349cc55cSDimitry Andric #include "lldb/Target/StopInfo.h" 16*349cc55cSDimitry Andric #include "lldb/Target/Unwind.h" 17*349cc55cSDimitry Andric #include "lldb/Utility/DataBufferHeap.h" 18*349cc55cSDimitry Andric #include "lldb/Utility/Log.h" 19*349cc55cSDimitry Andric #include "lldb/Utility/Logging.h" 20*349cc55cSDimitry Andric 21*349cc55cSDimitry Andric #include <memory> 22*349cc55cSDimitry Andric 23*349cc55cSDimitry Andric using namespace lldb; 24*349cc55cSDimitry Andric using namespace lldb_private; 25*349cc55cSDimitry Andric 26*349cc55cSDimitry Andric void ScriptedThread::CheckInterpreterAndScriptObject() const { 27*349cc55cSDimitry Andric lldbassert(m_script_object_sp && "Invalid Script Object."); 28*349cc55cSDimitry Andric lldbassert(GetInterface() && "Invalid Scripted Thread Interface."); 29*349cc55cSDimitry Andric } 30*349cc55cSDimitry Andric 31*349cc55cSDimitry Andric ScriptedThread::ScriptedThread(ScriptedProcess &process, Status &error) 32*349cc55cSDimitry Andric : Thread(process, LLDB_INVALID_THREAD_ID), m_scripted_process(process) { 33*349cc55cSDimitry Andric if (!process.IsValid()) { 34*349cc55cSDimitry Andric error.SetErrorString("Invalid scripted process"); 35*349cc55cSDimitry Andric return; 36*349cc55cSDimitry Andric } 37*349cc55cSDimitry Andric 38*349cc55cSDimitry Andric process.CheckInterpreterAndScriptObject(); 39*349cc55cSDimitry Andric 40*349cc55cSDimitry Andric auto scripted_thread_interface = GetInterface(); 41*349cc55cSDimitry Andric if (!scripted_thread_interface) { 42*349cc55cSDimitry Andric error.SetErrorString("Failed to get scripted thread interface."); 43*349cc55cSDimitry Andric return; 44*349cc55cSDimitry Andric } 45*349cc55cSDimitry Andric 46*349cc55cSDimitry Andric llvm::Optional<std::string> class_name = 47*349cc55cSDimitry Andric process.GetInterface().GetScriptedThreadPluginName(); 48*349cc55cSDimitry Andric if (!class_name || class_name->empty()) { 49*349cc55cSDimitry Andric error.SetErrorString("Failed to get scripted thread class name."); 50*349cc55cSDimitry Andric return; 51*349cc55cSDimitry Andric } 52*349cc55cSDimitry Andric 53*349cc55cSDimitry Andric ExecutionContext exe_ctx(process); 54*349cc55cSDimitry Andric 55*349cc55cSDimitry Andric StructuredData::GenericSP object_sp = 56*349cc55cSDimitry Andric scripted_thread_interface->CreatePluginObject( 57*349cc55cSDimitry Andric class_name->c_str(), exe_ctx, 58*349cc55cSDimitry Andric process.m_scripted_process_info.GetArgsSP()); 59*349cc55cSDimitry Andric if (!object_sp || !object_sp->IsValid()) { 60*349cc55cSDimitry Andric error.SetErrorString("Failed to create valid script object"); 61*349cc55cSDimitry Andric return; 62*349cc55cSDimitry Andric } 63*349cc55cSDimitry Andric 64*349cc55cSDimitry Andric m_script_object_sp = object_sp; 65*349cc55cSDimitry Andric 66*349cc55cSDimitry Andric SetID(scripted_thread_interface->GetThreadID()); 67*349cc55cSDimitry Andric } 68*349cc55cSDimitry Andric 69*349cc55cSDimitry Andric ScriptedThread::~ScriptedThread() { DestroyThread(); } 70*349cc55cSDimitry Andric 71*349cc55cSDimitry Andric const char *ScriptedThread::GetName() { 72*349cc55cSDimitry Andric CheckInterpreterAndScriptObject(); 73*349cc55cSDimitry Andric llvm::Optional<std::string> thread_name = GetInterface()->GetName(); 74*349cc55cSDimitry Andric if (!thread_name) 75*349cc55cSDimitry Andric return nullptr; 76*349cc55cSDimitry Andric return ConstString(thread_name->c_str()).AsCString(); 77*349cc55cSDimitry Andric } 78*349cc55cSDimitry Andric 79*349cc55cSDimitry Andric const char *ScriptedThread::GetQueueName() { 80*349cc55cSDimitry Andric CheckInterpreterAndScriptObject(); 81*349cc55cSDimitry Andric llvm::Optional<std::string> queue_name = GetInterface()->GetQueue(); 82*349cc55cSDimitry Andric if (!queue_name) 83*349cc55cSDimitry Andric return nullptr; 84*349cc55cSDimitry Andric return ConstString(queue_name->c_str()).AsCString(); 85*349cc55cSDimitry Andric } 86*349cc55cSDimitry Andric 87*349cc55cSDimitry Andric void ScriptedThread::WillResume(StateType resume_state) {} 88*349cc55cSDimitry Andric 89*349cc55cSDimitry Andric void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); } 90*349cc55cSDimitry Andric 91*349cc55cSDimitry Andric RegisterContextSP ScriptedThread::GetRegisterContext() { 92*349cc55cSDimitry Andric if (!m_reg_context_sp) 93*349cc55cSDimitry Andric m_reg_context_sp = CreateRegisterContextForFrame(nullptr); 94*349cc55cSDimitry Andric return m_reg_context_sp; 95*349cc55cSDimitry Andric } 96*349cc55cSDimitry Andric 97*349cc55cSDimitry Andric RegisterContextSP 98*349cc55cSDimitry Andric ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) { 99*349cc55cSDimitry Andric const uint32_t concrete_frame_idx = 100*349cc55cSDimitry Andric frame ? frame->GetConcreteFrameIndex() : 0; 101*349cc55cSDimitry Andric 102*349cc55cSDimitry Andric if (concrete_frame_idx) 103*349cc55cSDimitry Andric return GetUnwinder().CreateRegisterContextForFrame(frame); 104*349cc55cSDimitry Andric 105*349cc55cSDimitry Andric lldb::RegisterContextSP reg_ctx_sp; 106*349cc55cSDimitry Andric Status error; 107*349cc55cSDimitry Andric 108*349cc55cSDimitry Andric llvm::Optional<std::string> reg_data = GetInterface()->GetRegisterContext(); 109*349cc55cSDimitry Andric if (!reg_data) 110*349cc55cSDimitry Andric return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 111*349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.", 112*349cc55cSDimitry Andric error, LIBLLDB_LOG_THREAD); 113*349cc55cSDimitry Andric 114*349cc55cSDimitry Andric DataBufferSP data_sp( 115*349cc55cSDimitry Andric std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size())); 116*349cc55cSDimitry Andric 117*349cc55cSDimitry Andric if (!data_sp->GetByteSize()) 118*349cc55cSDimitry Andric return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 119*349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error, 120*349cc55cSDimitry Andric LIBLLDB_LOG_THREAD); 121*349cc55cSDimitry Andric 122*349cc55cSDimitry Andric std::shared_ptr<RegisterContextMemory> reg_ctx_memory = 123*349cc55cSDimitry Andric std::make_shared<RegisterContextMemory>( 124*349cc55cSDimitry Andric *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS); 125*349cc55cSDimitry Andric if (!reg_ctx_memory) 126*349cc55cSDimitry Andric return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 127*349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error, 128*349cc55cSDimitry Andric LIBLLDB_LOG_THREAD); 129*349cc55cSDimitry Andric 130*349cc55cSDimitry Andric reg_ctx_memory->SetAllRegisterData(data_sp); 131*349cc55cSDimitry Andric m_reg_context_sp = reg_ctx_memory; 132*349cc55cSDimitry Andric 133*349cc55cSDimitry Andric return m_reg_context_sp; 134*349cc55cSDimitry Andric } 135*349cc55cSDimitry Andric 136*349cc55cSDimitry Andric bool ScriptedThread::CalculateStopInfo() { 137*349cc55cSDimitry Andric StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason(); 138*349cc55cSDimitry Andric 139*349cc55cSDimitry Andric Status error; 140*349cc55cSDimitry Andric lldb::StopInfoSP stop_info_sp; 141*349cc55cSDimitry Andric lldb::StopReason stop_reason_type; 142*349cc55cSDimitry Andric 143*349cc55cSDimitry Andric if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type)) 144*349cc55cSDimitry Andric return GetInterface()->ErrorWithMessage<bool>( 145*349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, 146*349cc55cSDimitry Andric "Couldn't find value for key 'type' in stop reason dictionary.", error, 147*349cc55cSDimitry Andric LIBLLDB_LOG_THREAD); 148*349cc55cSDimitry Andric 149*349cc55cSDimitry Andric StructuredData::Dictionary *data_dict; 150*349cc55cSDimitry Andric if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict)) 151*349cc55cSDimitry Andric return GetInterface()->ErrorWithMessage<bool>( 152*349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, 153*349cc55cSDimitry Andric "Couldn't find value for key 'type' in stop reason dictionary.", error, 154*349cc55cSDimitry Andric LIBLLDB_LOG_THREAD); 155*349cc55cSDimitry Andric 156*349cc55cSDimitry Andric switch (stop_reason_type) { 157*349cc55cSDimitry Andric case lldb::eStopReasonNone: 158*349cc55cSDimitry Andric break; 159*349cc55cSDimitry Andric case lldb::eStopReasonBreakpoint: { 160*349cc55cSDimitry Andric lldb::break_id_t break_id; 161*349cc55cSDimitry Andric data_dict->GetValueForKeyAsInteger("break_id", break_id, 162*349cc55cSDimitry Andric LLDB_INVALID_BREAK_ID); 163*349cc55cSDimitry Andric stop_info_sp = 164*349cc55cSDimitry Andric StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id); 165*349cc55cSDimitry Andric } break; 166*349cc55cSDimitry Andric case lldb::eStopReasonSignal: { 167*349cc55cSDimitry Andric int signal; 168*349cc55cSDimitry Andric llvm::StringRef description; 169*349cc55cSDimitry Andric data_dict->GetValueForKeyAsInteger("signal", signal, 170*349cc55cSDimitry Andric LLDB_INVALID_SIGNAL_NUMBER); 171*349cc55cSDimitry Andric data_dict->GetValueForKeyAsString("desc", description); 172*349cc55cSDimitry Andric stop_info_sp = 173*349cc55cSDimitry Andric StopInfo::CreateStopReasonWithSignal(*this, signal, description.data()); 174*349cc55cSDimitry Andric } break; 175*349cc55cSDimitry Andric default: 176*349cc55cSDimitry Andric return GetInterface()->ErrorWithMessage<bool>( 177*349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, 178*349cc55cSDimitry Andric llvm::Twine("Unsupported stop reason type (" + 179*349cc55cSDimitry Andric llvm::Twine(stop_reason_type) + llvm::Twine(").")) 180*349cc55cSDimitry Andric .str(), 181*349cc55cSDimitry Andric error, LIBLLDB_LOG_THREAD); 182*349cc55cSDimitry Andric } 183*349cc55cSDimitry Andric 184*349cc55cSDimitry Andric SetStopInfo(stop_info_sp); 185*349cc55cSDimitry Andric return true; 186*349cc55cSDimitry Andric } 187*349cc55cSDimitry Andric 188*349cc55cSDimitry Andric void ScriptedThread::RefreshStateAfterStop() { 189*349cc55cSDimitry Andric GetRegisterContext()->InvalidateIfNeeded(/*force=*/false); 190*349cc55cSDimitry Andric } 191*349cc55cSDimitry Andric 192*349cc55cSDimitry Andric lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const { 193*349cc55cSDimitry Andric return m_scripted_process.GetInterface().GetScriptedThreadInterface(); 194*349cc55cSDimitry Andric } 195*349cc55cSDimitry Andric 196*349cc55cSDimitry Andric std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() { 197*349cc55cSDimitry Andric CheckInterpreterAndScriptObject(); 198*349cc55cSDimitry Andric 199*349cc55cSDimitry Andric if (!m_register_info_sp) { 200*349cc55cSDimitry Andric StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo(); 201*349cc55cSDimitry Andric if (!reg_info) 202*349cc55cSDimitry Andric return nullptr; 203*349cc55cSDimitry Andric 204*349cc55cSDimitry Andric m_register_info_sp = std::make_shared<DynamicRegisterInfo>( 205*349cc55cSDimitry Andric *reg_info, m_scripted_process.GetTarget().GetArchitecture()); 206*349cc55cSDimitry Andric assert(m_register_info_sp->GetNumRegisters() > 0); 207*349cc55cSDimitry Andric assert(m_register_info_sp->GetNumRegisterSets() > 0); 208*349cc55cSDimitry Andric } 209*349cc55cSDimitry Andric 210*349cc55cSDimitry Andric return m_register_info_sp; 211*349cc55cSDimitry Andric } 212