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