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" 18*81ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h" 19349cc55cSDimitry Andric #include <memory> 20349cc55cSDimitry Andric 21349cc55cSDimitry Andric using namespace lldb; 22349cc55cSDimitry Andric using namespace lldb_private; 23349cc55cSDimitry Andric 24349cc55cSDimitry Andric void ScriptedThread::CheckInterpreterAndScriptObject() const { 25349cc55cSDimitry Andric lldbassert(m_script_object_sp && "Invalid Script Object."); 26349cc55cSDimitry Andric lldbassert(GetInterface() && "Invalid Scripted Thread Interface."); 27349cc55cSDimitry Andric } 28349cc55cSDimitry Andric 2904eeddc0SDimitry Andric llvm::Expected<std::shared_ptr<ScriptedThread>> 3004eeddc0SDimitry Andric ScriptedThread::Create(ScriptedProcess &process, 3104eeddc0SDimitry Andric StructuredData::Generic *script_object) { 3204eeddc0SDimitry Andric if (!process.IsValid()) 3304eeddc0SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 3404eeddc0SDimitry Andric "Invalid scripted process."); 35349cc55cSDimitry Andric 36349cc55cSDimitry Andric process.CheckInterpreterAndScriptObject(); 37349cc55cSDimitry Andric 3804eeddc0SDimitry Andric auto scripted_thread_interface = 3904eeddc0SDimitry Andric process.GetInterface().CreateScriptedThreadInterface(); 4004eeddc0SDimitry Andric if (!scripted_thread_interface) 4104eeddc0SDimitry Andric return llvm::createStringError( 4204eeddc0SDimitry Andric llvm::inconvertibleErrorCode(), 4304eeddc0SDimitry Andric "Failed to create scripted thread interface."); 44349cc55cSDimitry Andric 4504eeddc0SDimitry Andric llvm::StringRef thread_class_name; 4604eeddc0SDimitry Andric if (!script_object) { 47349cc55cSDimitry Andric llvm::Optional<std::string> class_name = 48349cc55cSDimitry Andric process.GetInterface().GetScriptedThreadPluginName(); 4904eeddc0SDimitry Andric if (!class_name || class_name->empty()) 5004eeddc0SDimitry Andric return llvm::createStringError( 5104eeddc0SDimitry Andric llvm::inconvertibleErrorCode(), 5204eeddc0SDimitry Andric "Failed to get scripted thread class name."); 5304eeddc0SDimitry Andric thread_class_name = *class_name; 54349cc55cSDimitry Andric } 55349cc55cSDimitry Andric 56349cc55cSDimitry Andric ExecutionContext exe_ctx(process); 5704eeddc0SDimitry Andric StructuredData::GenericSP owned_script_object_sp = 58349cc55cSDimitry Andric scripted_thread_interface->CreatePluginObject( 5904eeddc0SDimitry Andric thread_class_name, exe_ctx, 6004eeddc0SDimitry Andric process.m_scripted_process_info.GetArgsSP(), script_object); 6104eeddc0SDimitry Andric 6204eeddc0SDimitry Andric if (!owned_script_object_sp) 6304eeddc0SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 6404eeddc0SDimitry Andric "Failed to create script object."); 6504eeddc0SDimitry Andric if (!owned_script_object_sp->IsValid()) 6604eeddc0SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 6704eeddc0SDimitry Andric "Created script object is invalid."); 6804eeddc0SDimitry Andric 6904eeddc0SDimitry Andric lldb::tid_t tid = scripted_thread_interface->GetThreadID(); 7004eeddc0SDimitry Andric 7104eeddc0SDimitry Andric return std::make_shared<ScriptedThread>(process, scripted_thread_interface, 7204eeddc0SDimitry Andric tid, owned_script_object_sp); 73349cc55cSDimitry Andric } 74349cc55cSDimitry Andric 7504eeddc0SDimitry Andric ScriptedThread::ScriptedThread(ScriptedProcess &process, 7604eeddc0SDimitry Andric ScriptedThreadInterfaceSP interface_sp, 7704eeddc0SDimitry Andric lldb::tid_t tid, 7804eeddc0SDimitry Andric StructuredData::GenericSP script_object_sp) 7904eeddc0SDimitry Andric : Thread(process, tid), m_scripted_process(process), 8004eeddc0SDimitry Andric m_scripted_thread_interface_sp(interface_sp), 8104eeddc0SDimitry Andric m_script_object_sp(script_object_sp) {} 82349cc55cSDimitry Andric 83349cc55cSDimitry Andric ScriptedThread::~ScriptedThread() { DestroyThread(); } 84349cc55cSDimitry Andric 85349cc55cSDimitry Andric const char *ScriptedThread::GetName() { 86349cc55cSDimitry Andric CheckInterpreterAndScriptObject(); 87349cc55cSDimitry Andric llvm::Optional<std::string> thread_name = GetInterface()->GetName(); 88349cc55cSDimitry Andric if (!thread_name) 89349cc55cSDimitry Andric return nullptr; 90349cc55cSDimitry Andric return ConstString(thread_name->c_str()).AsCString(); 91349cc55cSDimitry Andric } 92349cc55cSDimitry Andric 93349cc55cSDimitry Andric const char *ScriptedThread::GetQueueName() { 94349cc55cSDimitry Andric CheckInterpreterAndScriptObject(); 95349cc55cSDimitry Andric llvm::Optional<std::string> queue_name = GetInterface()->GetQueue(); 96349cc55cSDimitry Andric if (!queue_name) 97349cc55cSDimitry Andric return nullptr; 98349cc55cSDimitry Andric return ConstString(queue_name->c_str()).AsCString(); 99349cc55cSDimitry Andric } 100349cc55cSDimitry Andric 101349cc55cSDimitry Andric void ScriptedThread::WillResume(StateType resume_state) {} 102349cc55cSDimitry Andric 103349cc55cSDimitry Andric void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); } 104349cc55cSDimitry Andric 105349cc55cSDimitry Andric RegisterContextSP ScriptedThread::GetRegisterContext() { 106349cc55cSDimitry Andric if (!m_reg_context_sp) 107349cc55cSDimitry Andric m_reg_context_sp = CreateRegisterContextForFrame(nullptr); 108349cc55cSDimitry Andric return m_reg_context_sp; 109349cc55cSDimitry Andric } 110349cc55cSDimitry Andric 111349cc55cSDimitry Andric RegisterContextSP 112349cc55cSDimitry Andric ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) { 113349cc55cSDimitry Andric const uint32_t concrete_frame_idx = 114349cc55cSDimitry Andric frame ? frame->GetConcreteFrameIndex() : 0; 115349cc55cSDimitry Andric 116349cc55cSDimitry Andric if (concrete_frame_idx) 117349cc55cSDimitry Andric return GetUnwinder().CreateRegisterContextForFrame(frame); 118349cc55cSDimitry Andric 119349cc55cSDimitry Andric lldb::RegisterContextSP reg_ctx_sp; 120349cc55cSDimitry Andric Status error; 121349cc55cSDimitry Andric 122349cc55cSDimitry Andric llvm::Optional<std::string> reg_data = GetInterface()->GetRegisterContext(); 123349cc55cSDimitry Andric if (!reg_data) 124*81ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>( 125349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.", 126*81ad6265SDimitry Andric error, LLDBLog::Thread); 127349cc55cSDimitry Andric 128349cc55cSDimitry Andric DataBufferSP data_sp( 129349cc55cSDimitry Andric std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size())); 130349cc55cSDimitry Andric 131349cc55cSDimitry Andric if (!data_sp->GetByteSize()) 132*81ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>( 133349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error, 134*81ad6265SDimitry Andric LLDBLog::Thread); 135349cc55cSDimitry Andric 136349cc55cSDimitry Andric std::shared_ptr<RegisterContextMemory> reg_ctx_memory = 137349cc55cSDimitry Andric std::make_shared<RegisterContextMemory>( 138349cc55cSDimitry Andric *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS); 139349cc55cSDimitry Andric if (!reg_ctx_memory) 140*81ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>( 141349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error, 142*81ad6265SDimitry Andric LLDBLog::Thread); 143349cc55cSDimitry Andric 144349cc55cSDimitry Andric reg_ctx_memory->SetAllRegisterData(data_sp); 145349cc55cSDimitry Andric m_reg_context_sp = reg_ctx_memory; 146349cc55cSDimitry Andric 147349cc55cSDimitry Andric return m_reg_context_sp; 148349cc55cSDimitry Andric } 149349cc55cSDimitry Andric 150*81ad6265SDimitry Andric bool ScriptedThread::LoadArtificialStackFrames() { 151*81ad6265SDimitry Andric StructuredData::ArraySP arr_sp = GetInterface()->GetStackFrames(); 152*81ad6265SDimitry Andric 153*81ad6265SDimitry Andric Status error; 154*81ad6265SDimitry Andric if (!arr_sp) 155*81ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 156*81ad6265SDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stackframes.", 157*81ad6265SDimitry Andric error, LLDBLog::Thread); 158*81ad6265SDimitry Andric 159*81ad6265SDimitry Andric size_t arr_size = arr_sp->GetSize(); 160*81ad6265SDimitry Andric if (arr_size > std::numeric_limits<uint32_t>::max()) 161*81ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 162*81ad6265SDimitry Andric LLVM_PRETTY_FUNCTION, 163*81ad6265SDimitry Andric llvm::Twine( 164*81ad6265SDimitry Andric "StackFrame array size (" + llvm::Twine(arr_size) + 165*81ad6265SDimitry Andric llvm::Twine( 166*81ad6265SDimitry Andric ") is greater than maximum autorized for a StackFrameList.")) 167*81ad6265SDimitry Andric .str(), 168*81ad6265SDimitry Andric error, LLDBLog::Thread); 169*81ad6265SDimitry Andric 170*81ad6265SDimitry Andric StackFrameListSP frames = GetStackFrameList(); 171*81ad6265SDimitry Andric 172*81ad6265SDimitry Andric for (size_t idx = 0; idx < arr_size; idx++) { 173*81ad6265SDimitry Andric 174*81ad6265SDimitry Andric StructuredData::Dictionary *dict; 175*81ad6265SDimitry Andric 176*81ad6265SDimitry Andric if (!arr_sp->GetItemAtIndexAsDictionary(idx, dict) || !dict) 177*81ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 178*81ad6265SDimitry Andric LLVM_PRETTY_FUNCTION, 179*81ad6265SDimitry Andric llvm::Twine( 180*81ad6265SDimitry Andric "Couldn't get artificial stackframe dictionary at index (" + 181*81ad6265SDimitry Andric llvm::Twine(idx) + llvm::Twine(") from stackframe array.")) 182*81ad6265SDimitry Andric .str(), 183*81ad6265SDimitry Andric error, LLDBLog::Thread); 184*81ad6265SDimitry Andric 185*81ad6265SDimitry Andric lldb::addr_t pc; 186*81ad6265SDimitry Andric if (!dict->GetValueForKeyAsInteger("pc", pc)) 187*81ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 188*81ad6265SDimitry Andric LLVM_PRETTY_FUNCTION, 189*81ad6265SDimitry Andric "Couldn't find value for key 'pc' in stackframe dictionary.", error, 190*81ad6265SDimitry Andric LLDBLog::Thread); 191*81ad6265SDimitry Andric 192*81ad6265SDimitry Andric Address symbol_addr; 193*81ad6265SDimitry Andric symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget()); 194*81ad6265SDimitry Andric 195*81ad6265SDimitry Andric lldb::addr_t cfa = LLDB_INVALID_ADDRESS; 196*81ad6265SDimitry Andric bool cfa_is_valid = false; 197*81ad6265SDimitry Andric const bool behaves_like_zeroth_frame = false; 198*81ad6265SDimitry Andric SymbolContext sc; 199*81ad6265SDimitry Andric symbol_addr.CalculateSymbolContext(&sc); 200*81ad6265SDimitry Andric 201*81ad6265SDimitry Andric StackFrameSP synth_frame_sp = std::make_shared<StackFrame>( 202*81ad6265SDimitry Andric this->shared_from_this(), idx, idx, cfa, cfa_is_valid, pc, 203*81ad6265SDimitry Andric StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc); 204*81ad6265SDimitry Andric 205*81ad6265SDimitry Andric if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp)) 206*81ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 207*81ad6265SDimitry Andric LLVM_PRETTY_FUNCTION, 208*81ad6265SDimitry Andric llvm::Twine("Couldn't add frame (" + llvm::Twine(idx) + 209*81ad6265SDimitry Andric llvm::Twine(") to ScriptedThread StackFrameList.")) 210*81ad6265SDimitry Andric .str(), 211*81ad6265SDimitry Andric error, LLDBLog::Thread); 212*81ad6265SDimitry Andric } 213*81ad6265SDimitry Andric 214*81ad6265SDimitry Andric return true; 215*81ad6265SDimitry Andric } 216*81ad6265SDimitry Andric 217349cc55cSDimitry Andric bool ScriptedThread::CalculateStopInfo() { 218349cc55cSDimitry Andric StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason(); 219349cc55cSDimitry Andric 220349cc55cSDimitry Andric Status error; 22104eeddc0SDimitry Andric if (!dict_sp) 222*81ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 22304eeddc0SDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error, 224*81ad6265SDimitry Andric LLDBLog::Thread); 22504eeddc0SDimitry Andric 226349cc55cSDimitry Andric lldb::StopInfoSP stop_info_sp; 227349cc55cSDimitry Andric lldb::StopReason stop_reason_type; 228349cc55cSDimitry Andric 229349cc55cSDimitry Andric if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type)) 230*81ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 231349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, 232349cc55cSDimitry Andric "Couldn't find value for key 'type' in stop reason dictionary.", error, 233*81ad6265SDimitry Andric LLDBLog::Thread); 234349cc55cSDimitry Andric 235349cc55cSDimitry Andric StructuredData::Dictionary *data_dict; 236349cc55cSDimitry Andric if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict)) 237*81ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 238349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, 23904eeddc0SDimitry Andric "Couldn't find value for key 'data' in stop reason dictionary.", error, 240*81ad6265SDimitry Andric LLDBLog::Thread); 241349cc55cSDimitry Andric 242349cc55cSDimitry Andric switch (stop_reason_type) { 243349cc55cSDimitry Andric case lldb::eStopReasonNone: 24404eeddc0SDimitry Andric return true; 245349cc55cSDimitry Andric case lldb::eStopReasonBreakpoint: { 246349cc55cSDimitry Andric lldb::break_id_t break_id; 247349cc55cSDimitry Andric data_dict->GetValueForKeyAsInteger("break_id", break_id, 248349cc55cSDimitry Andric LLDB_INVALID_BREAK_ID); 249349cc55cSDimitry Andric stop_info_sp = 250349cc55cSDimitry Andric StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id); 251349cc55cSDimitry Andric } break; 252349cc55cSDimitry Andric case lldb::eStopReasonSignal: { 253349cc55cSDimitry Andric int signal; 254349cc55cSDimitry Andric llvm::StringRef description; 255349cc55cSDimitry Andric data_dict->GetValueForKeyAsInteger("signal", signal, 256349cc55cSDimitry Andric LLDB_INVALID_SIGNAL_NUMBER); 257349cc55cSDimitry Andric data_dict->GetValueForKeyAsString("desc", description); 258349cc55cSDimitry Andric stop_info_sp = 259349cc55cSDimitry Andric StopInfo::CreateStopReasonWithSignal(*this, signal, description.data()); 260349cc55cSDimitry Andric } break; 26104eeddc0SDimitry Andric case lldb::eStopReasonException: { 26204eeddc0SDimitry Andric llvm::StringRef description; 26304eeddc0SDimitry Andric data_dict->GetValueForKeyAsString("desc", description); 26404eeddc0SDimitry Andric 26504eeddc0SDimitry Andric stop_info_sp = 26604eeddc0SDimitry Andric StopInfo::CreateStopReasonWithException(*this, description.data()); 26704eeddc0SDimitry Andric } break; 268349cc55cSDimitry Andric default: 269*81ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 270349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, 271349cc55cSDimitry Andric llvm::Twine("Unsupported stop reason type (" + 272349cc55cSDimitry Andric llvm::Twine(stop_reason_type) + llvm::Twine(").")) 273349cc55cSDimitry Andric .str(), 274*81ad6265SDimitry Andric error, LLDBLog::Thread); 275349cc55cSDimitry Andric } 276349cc55cSDimitry Andric 27704eeddc0SDimitry Andric if (!stop_info_sp) 27804eeddc0SDimitry Andric return false; 27904eeddc0SDimitry Andric 280349cc55cSDimitry Andric SetStopInfo(stop_info_sp); 281349cc55cSDimitry Andric return true; 282349cc55cSDimitry Andric } 283349cc55cSDimitry Andric 284349cc55cSDimitry Andric void ScriptedThread::RefreshStateAfterStop() { 285349cc55cSDimitry Andric GetRegisterContext()->InvalidateIfNeeded(/*force=*/false); 286*81ad6265SDimitry Andric LoadArtificialStackFrames(); 287349cc55cSDimitry Andric } 288349cc55cSDimitry Andric 289349cc55cSDimitry Andric lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const { 29004eeddc0SDimitry Andric return m_scripted_thread_interface_sp; 291349cc55cSDimitry Andric } 292349cc55cSDimitry Andric 293349cc55cSDimitry Andric std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() { 294349cc55cSDimitry Andric CheckInterpreterAndScriptObject(); 295349cc55cSDimitry Andric 296349cc55cSDimitry Andric if (!m_register_info_sp) { 297349cc55cSDimitry Andric StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo(); 2980eae32dcSDimitry Andric 2990eae32dcSDimitry Andric Status error; 300349cc55cSDimitry Andric if (!reg_info) 3010eae32dcSDimitry Andric return GetInterface() 3020eae32dcSDimitry Andric ->ErrorWithMessage<std::shared_ptr<DynamicRegisterInfo>>( 3030eae32dcSDimitry Andric LLVM_PRETTY_FUNCTION, 3040eae32dcSDimitry Andric "Failed to get scripted thread registers info.", error, 305*81ad6265SDimitry Andric LLDBLog::Thread); 306349cc55cSDimitry Andric 307349cc55cSDimitry Andric m_register_info_sp = std::make_shared<DynamicRegisterInfo>( 308349cc55cSDimitry Andric *reg_info, m_scripted_process.GetTarget().GetArchitecture()); 309349cc55cSDimitry Andric } 310349cc55cSDimitry Andric 311349cc55cSDimitry Andric return m_register_info_sp; 312349cc55cSDimitry Andric } 313