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/LLDBLog.h"
19 #include <memory>
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 
24 void ScriptedThread::CheckInterpreterAndScriptObject() const {
25   lldbassert(m_script_object_sp && "Invalid Script Object.");
26   lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");
27 }
28 
29 llvm::Expected<std::shared_ptr<ScriptedThread>>
30 ScriptedThread::Create(ScriptedProcess &process,
31                        StructuredData::Generic *script_object) {
32   if (!process.IsValid())
33     return llvm::createStringError(llvm::inconvertibleErrorCode(),
34                                    "Invalid scripted process.");
35 
36   process.CheckInterpreterAndScriptObject();
37 
38   auto scripted_thread_interface =
39       process.GetInterface().CreateScriptedThreadInterface();
40   if (!scripted_thread_interface)
41     return llvm::createStringError(
42         llvm::inconvertibleErrorCode(),
43         "Failed to create scripted thread interface.");
44 
45   llvm::StringRef thread_class_name;
46   if (!script_object) {
47     llvm::Optional<std::string> class_name =
48         process.GetInterface().GetScriptedThreadPluginName();
49     if (!class_name || class_name->empty())
50       return llvm::createStringError(
51           llvm::inconvertibleErrorCode(),
52           "Failed to get scripted thread class name.");
53     thread_class_name = *class_name;
54   }
55 
56   ExecutionContext exe_ctx(process);
57   StructuredData::GenericSP owned_script_object_sp =
58       scripted_thread_interface->CreatePluginObject(
59           thread_class_name, exe_ctx,
60           process.m_scripted_process_info.GetArgsSP(), script_object);
61 
62   if (!owned_script_object_sp)
63     return llvm::createStringError(llvm::inconvertibleErrorCode(),
64                                    "Failed to create script object.");
65   if (!owned_script_object_sp->IsValid())
66     return llvm::createStringError(llvm::inconvertibleErrorCode(),
67                                    "Created script object is invalid.");
68 
69   lldb::tid_t tid = scripted_thread_interface->GetThreadID();
70 
71   return std::make_shared<ScriptedThread>(process, scripted_thread_interface,
72                                           tid, owned_script_object_sp);
73 }
74 
75 ScriptedThread::ScriptedThread(ScriptedProcess &process,
76                                ScriptedThreadInterfaceSP interface_sp,
77                                lldb::tid_t tid,
78                                StructuredData::GenericSP script_object_sp)
79     : Thread(process, tid), m_scripted_process(process),
80       m_scripted_thread_interface_sp(interface_sp),
81       m_script_object_sp(script_object_sp) {}
82 
83 ScriptedThread::~ScriptedThread() { DestroyThread(); }
84 
85 const char *ScriptedThread::GetName() {
86   CheckInterpreterAndScriptObject();
87   llvm::Optional<std::string> thread_name = GetInterface()->GetName();
88   if (!thread_name)
89     return nullptr;
90   return ConstString(thread_name->c_str()).AsCString();
91 }
92 
93 const char *ScriptedThread::GetQueueName() {
94   CheckInterpreterAndScriptObject();
95   llvm::Optional<std::string> queue_name = GetInterface()->GetQueue();
96   if (!queue_name)
97     return nullptr;
98   return ConstString(queue_name->c_str()).AsCString();
99 }
100 
101 void ScriptedThread::WillResume(StateType resume_state) {}
102 
103 void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); }
104 
105 RegisterContextSP ScriptedThread::GetRegisterContext() {
106   if (!m_reg_context_sp)
107     m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
108   return m_reg_context_sp;
109 }
110 
111 RegisterContextSP
112 ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) {
113   const uint32_t concrete_frame_idx =
114       frame ? frame->GetConcreteFrameIndex() : 0;
115 
116   if (concrete_frame_idx)
117     return GetUnwinder().CreateRegisterContextForFrame(frame);
118 
119   lldb::RegisterContextSP reg_ctx_sp;
120   Status error;
121 
122   llvm::Optional<std::string> reg_data = GetInterface()->GetRegisterContext();
123   if (!reg_data)
124     return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(
125         LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.",
126         error, LLDBLog::Thread);
127 
128   DataBufferSP data_sp(
129       std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
130 
131   if (!data_sp->GetByteSize())
132     return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(
133         LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error,
134         LLDBLog::Thread);
135 
136   std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
137       std::make_shared<RegisterContextMemory>(
138           *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);
139   if (!reg_ctx_memory)
140     return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(
141         LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error,
142         LLDBLog::Thread);
143 
144   reg_ctx_memory->SetAllRegisterData(data_sp);
145   m_reg_context_sp = reg_ctx_memory;
146 
147   return m_reg_context_sp;
148 }
149 
150 bool ScriptedThread::LoadArtificialStackFrames() {
151   StructuredData::ArraySP arr_sp = GetInterface()->GetStackFrames();
152 
153   Status error;
154   if (!arr_sp)
155     return ScriptedInterface::ErrorWithMessage<bool>(
156         LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stackframes.",
157         error, LLDBLog::Thread);
158 
159   size_t arr_size = arr_sp->GetSize();
160   if (arr_size > std::numeric_limits<uint32_t>::max())
161     return ScriptedInterface::ErrorWithMessage<bool>(
162         LLVM_PRETTY_FUNCTION,
163         llvm::Twine(
164             "StackFrame array size (" + llvm::Twine(arr_size) +
165             llvm::Twine(
166                 ") is greater than maximum autorized for a StackFrameList."))
167             .str(),
168         error, LLDBLog::Thread);
169 
170   StackFrameListSP frames = GetStackFrameList();
171 
172   for (size_t idx = 0; idx < arr_size; idx++) {
173 
174     StructuredData::Dictionary *dict;
175 
176     if (!arr_sp->GetItemAtIndexAsDictionary(idx, dict) || !dict)
177       return ScriptedInterface::ErrorWithMessage<bool>(
178           LLVM_PRETTY_FUNCTION,
179           llvm::Twine(
180               "Couldn't get artificial stackframe dictionary at index (" +
181               llvm::Twine(idx) + llvm::Twine(") from stackframe array."))
182               .str(),
183           error, LLDBLog::Thread);
184 
185     lldb::addr_t pc;
186     if (!dict->GetValueForKeyAsInteger("pc", pc))
187       return ScriptedInterface::ErrorWithMessage<bool>(
188           LLVM_PRETTY_FUNCTION,
189           "Couldn't find value for key 'pc' in stackframe dictionary.", error,
190           LLDBLog::Thread);
191 
192     Address symbol_addr;
193     symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget());
194 
195     lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
196     bool cfa_is_valid = false;
197     const bool behaves_like_zeroth_frame = false;
198     SymbolContext sc;
199     symbol_addr.CalculateSymbolContext(&sc);
200 
201     StackFrameSP synth_frame_sp = std::make_shared<StackFrame>(
202         this->shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
203         StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc);
204 
205     if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp))
206       return ScriptedInterface::ErrorWithMessage<bool>(
207           LLVM_PRETTY_FUNCTION,
208           llvm::Twine("Couldn't add frame (" + llvm::Twine(idx) +
209                       llvm::Twine(") to ScriptedThread StackFrameList."))
210               .str(),
211           error, LLDBLog::Thread);
212   }
213 
214   return true;
215 }
216 
217 bool ScriptedThread::CalculateStopInfo() {
218   StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();
219 
220   Status error;
221   if (!dict_sp)
222     return ScriptedInterface::ErrorWithMessage<bool>(
223         LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error,
224         LLDBLog::Thread);
225 
226   lldb::StopInfoSP stop_info_sp;
227   lldb::StopReason stop_reason_type;
228 
229   if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type))
230     return ScriptedInterface::ErrorWithMessage<bool>(
231         LLVM_PRETTY_FUNCTION,
232         "Couldn't find value for key 'type' in stop reason dictionary.", error,
233         LLDBLog::Thread);
234 
235   StructuredData::Dictionary *data_dict;
236   if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict))
237     return ScriptedInterface::ErrorWithMessage<bool>(
238         LLVM_PRETTY_FUNCTION,
239         "Couldn't find value for key 'data' in stop reason dictionary.", error,
240         LLDBLog::Thread);
241 
242   switch (stop_reason_type) {
243   case lldb::eStopReasonNone:
244     return true;
245   case lldb::eStopReasonBreakpoint: {
246     lldb::break_id_t break_id;
247     data_dict->GetValueForKeyAsInteger("break_id", break_id,
248                                        LLDB_INVALID_BREAK_ID);
249     stop_info_sp =
250         StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id);
251   } break;
252   case lldb::eStopReasonSignal: {
253     int signal;
254     llvm::StringRef description;
255     data_dict->GetValueForKeyAsInteger("signal", signal,
256                                        LLDB_INVALID_SIGNAL_NUMBER);
257     data_dict->GetValueForKeyAsString("desc", description);
258     stop_info_sp =
259         StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());
260   } break;
261   case lldb::eStopReasonException: {
262     llvm::StringRef description;
263     data_dict->GetValueForKeyAsString("desc", description);
264 
265     stop_info_sp =
266         StopInfo::CreateStopReasonWithException(*this, description.data());
267   } break;
268   default:
269     return ScriptedInterface::ErrorWithMessage<bool>(
270         LLVM_PRETTY_FUNCTION,
271         llvm::Twine("Unsupported stop reason type (" +
272                     llvm::Twine(stop_reason_type) + llvm::Twine(")."))
273             .str(),
274         error, LLDBLog::Thread);
275   }
276 
277   if (!stop_info_sp)
278     return false;
279 
280   SetStopInfo(stop_info_sp);
281   return true;
282 }
283 
284 void ScriptedThread::RefreshStateAfterStop() {
285   GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
286   LoadArtificialStackFrames();
287 }
288 
289 lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {
290   return m_scripted_thread_interface_sp;
291 }
292 
293 std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {
294   CheckInterpreterAndScriptObject();
295 
296   if (!m_register_info_sp) {
297     StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
298 
299     Status error;
300     if (!reg_info)
301       return GetInterface()
302           ->ErrorWithMessage<std::shared_ptr<DynamicRegisterInfo>>(
303               LLVM_PRETTY_FUNCTION,
304               "Failed to get scripted thread registers info.", error,
305               LLDBLog::Thread);
306 
307     m_register_info_sp = std::make_shared<DynamicRegisterInfo>(
308         *reg_info, m_scripted_process.GetTarget().GetArchitecture());
309   }
310 
311   return m_register_info_sp;
312 }
313