xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp (revision 0eae32dcef82f6f06de6419a0d623d7def0cc8f6)
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"
18349cc55cSDimitry Andric #include "lldb/Utility/Log.h"
19349cc55cSDimitry Andric #include "lldb/Utility/Logging.h"
20349cc55cSDimitry Andric 
21349cc55cSDimitry Andric #include <memory>
22349cc55cSDimitry Andric 
23349cc55cSDimitry Andric using namespace lldb;
24349cc55cSDimitry Andric using namespace lldb_private;
25349cc55cSDimitry Andric 
26349cc55cSDimitry Andric void ScriptedThread::CheckInterpreterAndScriptObject() const {
27349cc55cSDimitry Andric   lldbassert(m_script_object_sp && "Invalid Script Object.");
28349cc55cSDimitry Andric   lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");
29349cc55cSDimitry Andric }
30349cc55cSDimitry Andric 
31349cc55cSDimitry Andric ScriptedThread::ScriptedThread(ScriptedProcess &process, Status &error)
32349cc55cSDimitry Andric     : Thread(process, LLDB_INVALID_THREAD_ID), m_scripted_process(process) {
33349cc55cSDimitry Andric   if (!process.IsValid()) {
34349cc55cSDimitry Andric     error.SetErrorString("Invalid scripted process");
35349cc55cSDimitry Andric     return;
36349cc55cSDimitry Andric   }
37349cc55cSDimitry Andric 
38349cc55cSDimitry Andric   process.CheckInterpreterAndScriptObject();
39349cc55cSDimitry Andric 
40349cc55cSDimitry Andric   auto scripted_thread_interface = GetInterface();
41349cc55cSDimitry Andric   if (!scripted_thread_interface) {
42349cc55cSDimitry Andric     error.SetErrorString("Failed to get scripted thread interface.");
43349cc55cSDimitry Andric     return;
44349cc55cSDimitry Andric   }
45349cc55cSDimitry Andric 
46349cc55cSDimitry Andric   llvm::Optional<std::string> class_name =
47349cc55cSDimitry Andric       process.GetInterface().GetScriptedThreadPluginName();
48349cc55cSDimitry Andric   if (!class_name || class_name->empty()) {
49349cc55cSDimitry Andric     error.SetErrorString("Failed to get scripted thread class name.");
50349cc55cSDimitry Andric     return;
51349cc55cSDimitry Andric   }
52349cc55cSDimitry Andric 
53349cc55cSDimitry Andric   ExecutionContext exe_ctx(process);
54349cc55cSDimitry Andric 
55349cc55cSDimitry Andric   StructuredData::GenericSP object_sp =
56349cc55cSDimitry Andric       scripted_thread_interface->CreatePluginObject(
57349cc55cSDimitry Andric           class_name->c_str(), exe_ctx,
58349cc55cSDimitry Andric           process.m_scripted_process_info.GetArgsSP());
59349cc55cSDimitry Andric   if (!object_sp || !object_sp->IsValid()) {
60349cc55cSDimitry Andric     error.SetErrorString("Failed to create valid script object");
61349cc55cSDimitry Andric     return;
62349cc55cSDimitry Andric   }
63349cc55cSDimitry Andric 
64349cc55cSDimitry Andric   m_script_object_sp = object_sp;
65349cc55cSDimitry Andric 
66349cc55cSDimitry Andric   SetID(scripted_thread_interface->GetThreadID());
67349cc55cSDimitry Andric }
68349cc55cSDimitry Andric 
69349cc55cSDimitry Andric ScriptedThread::~ScriptedThread() { DestroyThread(); }
70349cc55cSDimitry Andric 
71349cc55cSDimitry Andric const char *ScriptedThread::GetName() {
72349cc55cSDimitry Andric   CheckInterpreterAndScriptObject();
73349cc55cSDimitry Andric   llvm::Optional<std::string> thread_name = GetInterface()->GetName();
74349cc55cSDimitry Andric   if (!thread_name)
75349cc55cSDimitry Andric     return nullptr;
76349cc55cSDimitry Andric   return ConstString(thread_name->c_str()).AsCString();
77349cc55cSDimitry Andric }
78349cc55cSDimitry Andric 
79349cc55cSDimitry Andric const char *ScriptedThread::GetQueueName() {
80349cc55cSDimitry Andric   CheckInterpreterAndScriptObject();
81349cc55cSDimitry Andric   llvm::Optional<std::string> queue_name = GetInterface()->GetQueue();
82349cc55cSDimitry Andric   if (!queue_name)
83349cc55cSDimitry Andric     return nullptr;
84349cc55cSDimitry Andric   return ConstString(queue_name->c_str()).AsCString();
85349cc55cSDimitry Andric }
86349cc55cSDimitry Andric 
87349cc55cSDimitry Andric void ScriptedThread::WillResume(StateType resume_state) {}
88349cc55cSDimitry Andric 
89349cc55cSDimitry Andric void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); }
90349cc55cSDimitry Andric 
91349cc55cSDimitry Andric RegisterContextSP ScriptedThread::GetRegisterContext() {
92349cc55cSDimitry Andric   if (!m_reg_context_sp)
93349cc55cSDimitry Andric     m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
94349cc55cSDimitry Andric   return m_reg_context_sp;
95349cc55cSDimitry Andric }
96349cc55cSDimitry Andric 
97349cc55cSDimitry Andric RegisterContextSP
98349cc55cSDimitry Andric ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) {
99349cc55cSDimitry Andric   const uint32_t concrete_frame_idx =
100349cc55cSDimitry Andric       frame ? frame->GetConcreteFrameIndex() : 0;
101349cc55cSDimitry Andric 
102349cc55cSDimitry Andric   if (concrete_frame_idx)
103349cc55cSDimitry Andric     return GetUnwinder().CreateRegisterContextForFrame(frame);
104349cc55cSDimitry Andric 
105349cc55cSDimitry Andric   lldb::RegisterContextSP reg_ctx_sp;
106349cc55cSDimitry Andric   Status error;
107349cc55cSDimitry Andric 
108349cc55cSDimitry Andric   llvm::Optional<std::string> reg_data = GetInterface()->GetRegisterContext();
109349cc55cSDimitry Andric   if (!reg_data)
110349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>(
111349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.",
112349cc55cSDimitry Andric         error, LIBLLDB_LOG_THREAD);
113349cc55cSDimitry Andric 
114349cc55cSDimitry Andric   DataBufferSP data_sp(
115349cc55cSDimitry Andric       std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
116349cc55cSDimitry Andric 
117349cc55cSDimitry Andric   if (!data_sp->GetByteSize())
118349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>(
119349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error,
120349cc55cSDimitry Andric         LIBLLDB_LOG_THREAD);
121349cc55cSDimitry Andric 
122349cc55cSDimitry Andric   std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
123349cc55cSDimitry Andric       std::make_shared<RegisterContextMemory>(
124349cc55cSDimitry Andric           *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);
125349cc55cSDimitry Andric   if (!reg_ctx_memory)
126349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>(
127349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error,
128349cc55cSDimitry Andric         LIBLLDB_LOG_THREAD);
129349cc55cSDimitry Andric 
130349cc55cSDimitry Andric   reg_ctx_memory->SetAllRegisterData(data_sp);
131349cc55cSDimitry Andric   m_reg_context_sp = reg_ctx_memory;
132349cc55cSDimitry Andric 
133349cc55cSDimitry Andric   return m_reg_context_sp;
134349cc55cSDimitry Andric }
135349cc55cSDimitry Andric 
136349cc55cSDimitry Andric bool ScriptedThread::CalculateStopInfo() {
137349cc55cSDimitry Andric   StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();
138349cc55cSDimitry Andric 
139349cc55cSDimitry Andric   Status error;
140349cc55cSDimitry Andric   lldb::StopInfoSP stop_info_sp;
141349cc55cSDimitry Andric   lldb::StopReason stop_reason_type;
142349cc55cSDimitry Andric 
143349cc55cSDimitry Andric   if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type))
144349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<bool>(
145349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION,
146349cc55cSDimitry Andric         "Couldn't find value for key 'type' in stop reason dictionary.", error,
147349cc55cSDimitry Andric         LIBLLDB_LOG_THREAD);
148349cc55cSDimitry Andric 
149349cc55cSDimitry Andric   StructuredData::Dictionary *data_dict;
150349cc55cSDimitry Andric   if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict))
151349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<bool>(
152349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION,
153349cc55cSDimitry Andric         "Couldn't find value for key 'type' in stop reason dictionary.", error,
154349cc55cSDimitry Andric         LIBLLDB_LOG_THREAD);
155349cc55cSDimitry Andric 
156349cc55cSDimitry Andric   switch (stop_reason_type) {
157349cc55cSDimitry Andric   case lldb::eStopReasonNone:
158349cc55cSDimitry Andric     break;
159349cc55cSDimitry Andric   case lldb::eStopReasonBreakpoint: {
160349cc55cSDimitry Andric     lldb::break_id_t break_id;
161349cc55cSDimitry Andric     data_dict->GetValueForKeyAsInteger("break_id", break_id,
162349cc55cSDimitry Andric                                        LLDB_INVALID_BREAK_ID);
163349cc55cSDimitry Andric     stop_info_sp =
164349cc55cSDimitry Andric         StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id);
165349cc55cSDimitry Andric   } break;
166349cc55cSDimitry Andric   case lldb::eStopReasonSignal: {
167349cc55cSDimitry Andric     int signal;
168349cc55cSDimitry Andric     llvm::StringRef description;
169349cc55cSDimitry Andric     data_dict->GetValueForKeyAsInteger("signal", signal,
170349cc55cSDimitry Andric                                        LLDB_INVALID_SIGNAL_NUMBER);
171349cc55cSDimitry Andric     data_dict->GetValueForKeyAsString("desc", description);
172349cc55cSDimitry Andric     stop_info_sp =
173349cc55cSDimitry Andric         StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());
174349cc55cSDimitry Andric   } break;
175349cc55cSDimitry Andric   default:
176349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<bool>(
177349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION,
178349cc55cSDimitry Andric         llvm::Twine("Unsupported stop reason type (" +
179349cc55cSDimitry Andric                     llvm::Twine(stop_reason_type) + llvm::Twine(")."))
180349cc55cSDimitry Andric             .str(),
181349cc55cSDimitry Andric         error, LIBLLDB_LOG_THREAD);
182349cc55cSDimitry Andric   }
183349cc55cSDimitry Andric 
184349cc55cSDimitry Andric   SetStopInfo(stop_info_sp);
185349cc55cSDimitry Andric   return true;
186349cc55cSDimitry Andric }
187349cc55cSDimitry Andric 
188349cc55cSDimitry Andric void ScriptedThread::RefreshStateAfterStop() {
189349cc55cSDimitry Andric   GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
190349cc55cSDimitry Andric }
191349cc55cSDimitry Andric 
192349cc55cSDimitry Andric lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {
193349cc55cSDimitry Andric   return m_scripted_process.GetInterface().GetScriptedThreadInterface();
194349cc55cSDimitry Andric }
195349cc55cSDimitry Andric 
196349cc55cSDimitry Andric std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {
197349cc55cSDimitry Andric   CheckInterpreterAndScriptObject();
198349cc55cSDimitry Andric 
199349cc55cSDimitry Andric   if (!m_register_info_sp) {
200349cc55cSDimitry Andric     StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
201*0eae32dcSDimitry Andric 
202*0eae32dcSDimitry Andric     Status error;
203349cc55cSDimitry Andric     if (!reg_info)
204*0eae32dcSDimitry Andric       return GetInterface()
205*0eae32dcSDimitry Andric           ->ErrorWithMessage<std::shared_ptr<DynamicRegisterInfo>>(
206*0eae32dcSDimitry Andric               LLVM_PRETTY_FUNCTION,
207*0eae32dcSDimitry Andric               "Failed to get scripted thread registers info.", error,
208*0eae32dcSDimitry Andric               LIBLLDB_LOG_THREAD);
209349cc55cSDimitry Andric 
210349cc55cSDimitry Andric     m_register_info_sp = std::make_shared<DynamicRegisterInfo>(
211349cc55cSDimitry Andric         *reg_info, m_scripted_process.GetTarget().GetArchitecture());
212349cc55cSDimitry Andric   }
213349cc55cSDimitry Andric 
214349cc55cSDimitry Andric   return m_register_info_sp;
215349cc55cSDimitry Andric }
216