xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
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 
31*04eeddc0SDimitry Andric llvm::Expected<std::shared_ptr<ScriptedThread>>
32*04eeddc0SDimitry Andric ScriptedThread::Create(ScriptedProcess &process,
33*04eeddc0SDimitry Andric                        StructuredData::Generic *script_object) {
34*04eeddc0SDimitry Andric   if (!process.IsValid())
35*04eeddc0SDimitry Andric     return llvm::createStringError(llvm::inconvertibleErrorCode(),
36*04eeddc0SDimitry Andric                                    "Invalid scripted process.");
37349cc55cSDimitry Andric 
38349cc55cSDimitry Andric   process.CheckInterpreterAndScriptObject();
39349cc55cSDimitry Andric 
40*04eeddc0SDimitry Andric   auto scripted_thread_interface =
41*04eeddc0SDimitry Andric       process.GetInterface().CreateScriptedThreadInterface();
42*04eeddc0SDimitry Andric   if (!scripted_thread_interface)
43*04eeddc0SDimitry Andric     return llvm::createStringError(
44*04eeddc0SDimitry Andric         llvm::inconvertibleErrorCode(),
45*04eeddc0SDimitry Andric         "Failed to create scripted thread interface.");
46349cc55cSDimitry Andric 
47*04eeddc0SDimitry Andric   llvm::StringRef thread_class_name;
48*04eeddc0SDimitry Andric   if (!script_object) {
49349cc55cSDimitry Andric     llvm::Optional<std::string> class_name =
50349cc55cSDimitry Andric         process.GetInterface().GetScriptedThreadPluginName();
51*04eeddc0SDimitry Andric     if (!class_name || class_name->empty())
52*04eeddc0SDimitry Andric       return llvm::createStringError(
53*04eeddc0SDimitry Andric           llvm::inconvertibleErrorCode(),
54*04eeddc0SDimitry Andric           "Failed to get scripted thread class name.");
55*04eeddc0SDimitry Andric     thread_class_name = *class_name;
56349cc55cSDimitry Andric   }
57349cc55cSDimitry Andric 
58349cc55cSDimitry Andric   ExecutionContext exe_ctx(process);
59*04eeddc0SDimitry Andric   StructuredData::GenericSP owned_script_object_sp =
60349cc55cSDimitry Andric       scripted_thread_interface->CreatePluginObject(
61*04eeddc0SDimitry Andric           thread_class_name, exe_ctx,
62*04eeddc0SDimitry Andric           process.m_scripted_process_info.GetArgsSP(), script_object);
63*04eeddc0SDimitry Andric 
64*04eeddc0SDimitry Andric   if (!owned_script_object_sp)
65*04eeddc0SDimitry Andric     return llvm::createStringError(llvm::inconvertibleErrorCode(),
66*04eeddc0SDimitry Andric                                    "Failed to create script object.");
67*04eeddc0SDimitry Andric   if (!owned_script_object_sp->IsValid())
68*04eeddc0SDimitry Andric     return llvm::createStringError(llvm::inconvertibleErrorCode(),
69*04eeddc0SDimitry Andric                                    "Created script object is invalid.");
70*04eeddc0SDimitry Andric 
71*04eeddc0SDimitry Andric   lldb::tid_t tid = scripted_thread_interface->GetThreadID();
72*04eeddc0SDimitry Andric 
73*04eeddc0SDimitry Andric   return std::make_shared<ScriptedThread>(process, scripted_thread_interface,
74*04eeddc0SDimitry Andric                                           tid, owned_script_object_sp);
75349cc55cSDimitry Andric }
76349cc55cSDimitry Andric 
77*04eeddc0SDimitry Andric ScriptedThread::ScriptedThread(ScriptedProcess &process,
78*04eeddc0SDimitry Andric                                ScriptedThreadInterfaceSP interface_sp,
79*04eeddc0SDimitry Andric                                lldb::tid_t tid,
80*04eeddc0SDimitry Andric                                StructuredData::GenericSP script_object_sp)
81*04eeddc0SDimitry Andric     : Thread(process, tid), m_scripted_process(process),
82*04eeddc0SDimitry Andric       m_scripted_thread_interface_sp(interface_sp),
83*04eeddc0SDimitry Andric       m_script_object_sp(script_object_sp) {}
84349cc55cSDimitry Andric 
85349cc55cSDimitry Andric ScriptedThread::~ScriptedThread() { DestroyThread(); }
86349cc55cSDimitry Andric 
87349cc55cSDimitry Andric const char *ScriptedThread::GetName() {
88349cc55cSDimitry Andric   CheckInterpreterAndScriptObject();
89349cc55cSDimitry Andric   llvm::Optional<std::string> thread_name = GetInterface()->GetName();
90349cc55cSDimitry Andric   if (!thread_name)
91349cc55cSDimitry Andric     return nullptr;
92349cc55cSDimitry Andric   return ConstString(thread_name->c_str()).AsCString();
93349cc55cSDimitry Andric }
94349cc55cSDimitry Andric 
95349cc55cSDimitry Andric const char *ScriptedThread::GetQueueName() {
96349cc55cSDimitry Andric   CheckInterpreterAndScriptObject();
97349cc55cSDimitry Andric   llvm::Optional<std::string> queue_name = GetInterface()->GetQueue();
98349cc55cSDimitry Andric   if (!queue_name)
99349cc55cSDimitry Andric     return nullptr;
100349cc55cSDimitry Andric   return ConstString(queue_name->c_str()).AsCString();
101349cc55cSDimitry Andric }
102349cc55cSDimitry Andric 
103349cc55cSDimitry Andric void ScriptedThread::WillResume(StateType resume_state) {}
104349cc55cSDimitry Andric 
105349cc55cSDimitry Andric void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); }
106349cc55cSDimitry Andric 
107349cc55cSDimitry Andric RegisterContextSP ScriptedThread::GetRegisterContext() {
108349cc55cSDimitry Andric   if (!m_reg_context_sp)
109349cc55cSDimitry Andric     m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
110349cc55cSDimitry Andric   return m_reg_context_sp;
111349cc55cSDimitry Andric }
112349cc55cSDimitry Andric 
113349cc55cSDimitry Andric RegisterContextSP
114349cc55cSDimitry Andric ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) {
115349cc55cSDimitry Andric   const uint32_t concrete_frame_idx =
116349cc55cSDimitry Andric       frame ? frame->GetConcreteFrameIndex() : 0;
117349cc55cSDimitry Andric 
118349cc55cSDimitry Andric   if (concrete_frame_idx)
119349cc55cSDimitry Andric     return GetUnwinder().CreateRegisterContextForFrame(frame);
120349cc55cSDimitry Andric 
121349cc55cSDimitry Andric   lldb::RegisterContextSP reg_ctx_sp;
122349cc55cSDimitry Andric   Status error;
123349cc55cSDimitry Andric 
124349cc55cSDimitry Andric   llvm::Optional<std::string> reg_data = GetInterface()->GetRegisterContext();
125349cc55cSDimitry Andric   if (!reg_data)
126349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>(
127349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.",
128349cc55cSDimitry Andric         error, LIBLLDB_LOG_THREAD);
129349cc55cSDimitry Andric 
130349cc55cSDimitry Andric   DataBufferSP data_sp(
131349cc55cSDimitry Andric       std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
132349cc55cSDimitry Andric 
133349cc55cSDimitry Andric   if (!data_sp->GetByteSize())
134349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>(
135349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error,
136349cc55cSDimitry Andric         LIBLLDB_LOG_THREAD);
137349cc55cSDimitry Andric 
138349cc55cSDimitry Andric   std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
139349cc55cSDimitry Andric       std::make_shared<RegisterContextMemory>(
140349cc55cSDimitry Andric           *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);
141349cc55cSDimitry Andric   if (!reg_ctx_memory)
142349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>(
143349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error,
144349cc55cSDimitry Andric         LIBLLDB_LOG_THREAD);
145349cc55cSDimitry Andric 
146349cc55cSDimitry Andric   reg_ctx_memory->SetAllRegisterData(data_sp);
147349cc55cSDimitry Andric   m_reg_context_sp = reg_ctx_memory;
148349cc55cSDimitry Andric 
149349cc55cSDimitry Andric   return m_reg_context_sp;
150349cc55cSDimitry Andric }
151349cc55cSDimitry Andric 
152349cc55cSDimitry Andric bool ScriptedThread::CalculateStopInfo() {
153349cc55cSDimitry Andric   StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();
154349cc55cSDimitry Andric 
155349cc55cSDimitry Andric   Status error;
156*04eeddc0SDimitry Andric   if (!dict_sp)
157*04eeddc0SDimitry Andric     return GetInterface()->ErrorWithMessage<bool>(
158*04eeddc0SDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error,
159*04eeddc0SDimitry Andric         LIBLLDB_LOG_THREAD);
160*04eeddc0SDimitry Andric 
161349cc55cSDimitry Andric   lldb::StopInfoSP stop_info_sp;
162349cc55cSDimitry Andric   lldb::StopReason stop_reason_type;
163349cc55cSDimitry Andric 
164349cc55cSDimitry Andric   if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type))
165349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<bool>(
166349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION,
167349cc55cSDimitry Andric         "Couldn't find value for key 'type' in stop reason dictionary.", error,
168349cc55cSDimitry Andric         LIBLLDB_LOG_THREAD);
169349cc55cSDimitry Andric 
170349cc55cSDimitry Andric   StructuredData::Dictionary *data_dict;
171349cc55cSDimitry Andric   if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict))
172349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<bool>(
173349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION,
174*04eeddc0SDimitry Andric         "Couldn't find value for key 'data' in stop reason dictionary.", error,
175349cc55cSDimitry Andric         LIBLLDB_LOG_THREAD);
176349cc55cSDimitry Andric 
177349cc55cSDimitry Andric   switch (stop_reason_type) {
178349cc55cSDimitry Andric   case lldb::eStopReasonNone:
179*04eeddc0SDimitry Andric     return true;
180349cc55cSDimitry Andric   case lldb::eStopReasonBreakpoint: {
181349cc55cSDimitry Andric     lldb::break_id_t break_id;
182349cc55cSDimitry Andric     data_dict->GetValueForKeyAsInteger("break_id", break_id,
183349cc55cSDimitry Andric                                        LLDB_INVALID_BREAK_ID);
184349cc55cSDimitry Andric     stop_info_sp =
185349cc55cSDimitry Andric         StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id);
186349cc55cSDimitry Andric   } break;
187349cc55cSDimitry Andric   case lldb::eStopReasonSignal: {
188349cc55cSDimitry Andric     int signal;
189349cc55cSDimitry Andric     llvm::StringRef description;
190349cc55cSDimitry Andric     data_dict->GetValueForKeyAsInteger("signal", signal,
191349cc55cSDimitry Andric                                        LLDB_INVALID_SIGNAL_NUMBER);
192349cc55cSDimitry Andric     data_dict->GetValueForKeyAsString("desc", description);
193349cc55cSDimitry Andric     stop_info_sp =
194349cc55cSDimitry Andric         StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());
195349cc55cSDimitry Andric   } break;
196*04eeddc0SDimitry Andric   case lldb::eStopReasonException: {
197*04eeddc0SDimitry Andric     llvm::StringRef description;
198*04eeddc0SDimitry Andric     data_dict->GetValueForKeyAsString("desc", description);
199*04eeddc0SDimitry Andric 
200*04eeddc0SDimitry Andric     stop_info_sp =
201*04eeddc0SDimitry Andric         StopInfo::CreateStopReasonWithException(*this, description.data());
202*04eeddc0SDimitry Andric   } break;
203349cc55cSDimitry Andric   default:
204349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<bool>(
205349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION,
206349cc55cSDimitry Andric         llvm::Twine("Unsupported stop reason type (" +
207349cc55cSDimitry Andric                     llvm::Twine(stop_reason_type) + llvm::Twine(")."))
208349cc55cSDimitry Andric             .str(),
209349cc55cSDimitry Andric         error, LIBLLDB_LOG_THREAD);
210349cc55cSDimitry Andric   }
211349cc55cSDimitry Andric 
212*04eeddc0SDimitry Andric   if (!stop_info_sp)
213*04eeddc0SDimitry Andric     return false;
214*04eeddc0SDimitry Andric 
215349cc55cSDimitry Andric   SetStopInfo(stop_info_sp);
216349cc55cSDimitry Andric   return true;
217349cc55cSDimitry Andric }
218349cc55cSDimitry Andric 
219349cc55cSDimitry Andric void ScriptedThread::RefreshStateAfterStop() {
220349cc55cSDimitry Andric   GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
221349cc55cSDimitry Andric }
222349cc55cSDimitry Andric 
223349cc55cSDimitry Andric lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {
224*04eeddc0SDimitry Andric   return m_scripted_thread_interface_sp;
225349cc55cSDimitry Andric }
226349cc55cSDimitry Andric 
227349cc55cSDimitry Andric std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {
228349cc55cSDimitry Andric   CheckInterpreterAndScriptObject();
229349cc55cSDimitry Andric 
230349cc55cSDimitry Andric   if (!m_register_info_sp) {
231349cc55cSDimitry Andric     StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
2320eae32dcSDimitry Andric 
2330eae32dcSDimitry Andric     Status error;
234349cc55cSDimitry Andric     if (!reg_info)
2350eae32dcSDimitry Andric       return GetInterface()
2360eae32dcSDimitry Andric           ->ErrorWithMessage<std::shared_ptr<DynamicRegisterInfo>>(
2370eae32dcSDimitry Andric               LLVM_PRETTY_FUNCTION,
2380eae32dcSDimitry Andric               "Failed to get scripted thread registers info.", error,
2390eae32dcSDimitry Andric               LIBLLDB_LOG_THREAD);
240349cc55cSDimitry Andric 
241349cc55cSDimitry Andric     m_register_info_sp = std::make_shared<DynamicRegisterInfo>(
242349cc55cSDimitry Andric         *reg_info, m_scripted_process.GetTarget().GetArchitecture());
243349cc55cSDimitry Andric   }
244349cc55cSDimitry Andric 
245349cc55cSDimitry Andric   return m_register_info_sp;
246349cc55cSDimitry Andric }
247