xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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