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