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 m_scripted_thread_interface_sp( 34 m_scripted_process.GetInterface().CreateScriptedThreadInterface()) { 35 if (!process.IsValid()) { 36 error.SetErrorString("Invalid scripted process"); 37 return; 38 } 39 40 process.CheckInterpreterAndScriptObject(); 41 42 auto scripted_thread_interface = GetInterface(); 43 if (!scripted_thread_interface) { 44 error.SetErrorString("Failed to get scripted thread interface."); 45 return; 46 } 47 48 llvm::Optional<std::string> class_name = 49 process.GetInterface().GetScriptedThreadPluginName(); 50 if (!class_name || class_name->empty()) { 51 error.SetErrorString("Failed to get scripted thread class name."); 52 return; 53 } 54 55 ExecutionContext exe_ctx(process); 56 57 StructuredData::GenericSP object_sp = 58 scripted_thread_interface->CreatePluginObject( 59 class_name->c_str(), exe_ctx, 60 process.m_scripted_process_info.GetArgsSP()); 61 if (!object_sp || !object_sp->IsValid()) { 62 error.SetErrorString("Failed to create valid script object"); 63 return; 64 } 65 66 m_script_object_sp = object_sp; 67 68 SetID(scripted_thread_interface->GetThreadID()); 69 } 70 71 ScriptedThread::~ScriptedThread() { DestroyThread(); } 72 73 const char *ScriptedThread::GetName() { 74 CheckInterpreterAndScriptObject(); 75 llvm::Optional<std::string> thread_name = GetInterface()->GetName(); 76 if (!thread_name) 77 return nullptr; 78 return ConstString(thread_name->c_str()).AsCString(); 79 } 80 81 const char *ScriptedThread::GetQueueName() { 82 CheckInterpreterAndScriptObject(); 83 llvm::Optional<std::string> queue_name = GetInterface()->GetQueue(); 84 if (!queue_name) 85 return nullptr; 86 return ConstString(queue_name->c_str()).AsCString(); 87 } 88 89 void ScriptedThread::WillResume(StateType resume_state) {} 90 91 void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); } 92 93 RegisterContextSP ScriptedThread::GetRegisterContext() { 94 if (!m_reg_context_sp) 95 m_reg_context_sp = CreateRegisterContextForFrame(nullptr); 96 return m_reg_context_sp; 97 } 98 99 RegisterContextSP 100 ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) { 101 const uint32_t concrete_frame_idx = 102 frame ? frame->GetConcreteFrameIndex() : 0; 103 104 if (concrete_frame_idx) 105 return GetUnwinder().CreateRegisterContextForFrame(frame); 106 107 lldb::RegisterContextSP reg_ctx_sp; 108 Status error; 109 110 llvm::Optional<std::string> reg_data = GetInterface()->GetRegisterContext(); 111 if (!reg_data) 112 return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 113 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.", 114 error, LIBLLDB_LOG_THREAD); 115 116 DataBufferSP data_sp( 117 std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size())); 118 119 if (!data_sp->GetByteSize()) 120 return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 121 LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error, 122 LIBLLDB_LOG_THREAD); 123 124 std::shared_ptr<RegisterContextMemory> reg_ctx_memory = 125 std::make_shared<RegisterContextMemory>( 126 *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS); 127 if (!reg_ctx_memory) 128 return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( 129 LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error, 130 LIBLLDB_LOG_THREAD); 131 132 reg_ctx_memory->SetAllRegisterData(data_sp); 133 m_reg_context_sp = reg_ctx_memory; 134 135 return m_reg_context_sp; 136 } 137 138 bool ScriptedThread::CalculateStopInfo() { 139 StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason(); 140 141 Status error; 142 lldb::StopInfoSP stop_info_sp; 143 lldb::StopReason stop_reason_type; 144 145 if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type)) 146 return GetInterface()->ErrorWithMessage<bool>( 147 LLVM_PRETTY_FUNCTION, 148 "Couldn't find value for key 'type' in stop reason dictionary.", error, 149 LIBLLDB_LOG_THREAD); 150 151 StructuredData::Dictionary *data_dict; 152 if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict)) 153 return GetInterface()->ErrorWithMessage<bool>( 154 LLVM_PRETTY_FUNCTION, 155 "Couldn't find value for key 'type' in stop reason dictionary.", error, 156 LIBLLDB_LOG_THREAD); 157 158 switch (stop_reason_type) { 159 case lldb::eStopReasonNone: 160 break; 161 case lldb::eStopReasonBreakpoint: { 162 lldb::break_id_t break_id; 163 data_dict->GetValueForKeyAsInteger("break_id", break_id, 164 LLDB_INVALID_BREAK_ID); 165 stop_info_sp = 166 StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id); 167 } break; 168 case lldb::eStopReasonSignal: { 169 int signal; 170 llvm::StringRef description; 171 data_dict->GetValueForKeyAsInteger("signal", signal, 172 LLDB_INVALID_SIGNAL_NUMBER); 173 data_dict->GetValueForKeyAsString("desc", description); 174 stop_info_sp = 175 StopInfo::CreateStopReasonWithSignal(*this, signal, description.data()); 176 } break; 177 default: 178 return GetInterface()->ErrorWithMessage<bool>( 179 LLVM_PRETTY_FUNCTION, 180 llvm::Twine("Unsupported stop reason type (" + 181 llvm::Twine(stop_reason_type) + llvm::Twine(").")) 182 .str(), 183 error, LIBLLDB_LOG_THREAD); 184 } 185 186 SetStopInfo(stop_info_sp); 187 return true; 188 } 189 190 void ScriptedThread::RefreshStateAfterStop() { 191 GetRegisterContext()->InvalidateIfNeeded(/*force=*/false); 192 } 193 194 lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const { 195 return m_scripted_thread_interface_sp; 196 } 197 198 std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() { 199 CheckInterpreterAndScriptObject(); 200 201 if (!m_register_info_sp) { 202 StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo(); 203 204 Status error; 205 if (!reg_info) 206 return GetInterface() 207 ->ErrorWithMessage<std::shared_ptr<DynamicRegisterInfo>>( 208 LLVM_PRETTY_FUNCTION, 209 "Failed to get scripted thread registers info.", error, 210 LIBLLDB_LOG_THREAD); 211 212 m_register_info_sp = std::make_shared<DynamicRegisterInfo>( 213 *reg_info, m_scripted_process.GetTarget().GetArchitecture()); 214 } 215 216 return m_register_info_sp; 217 } 218