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
CheckInterpreterAndScriptObject() const24 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>>
Create(ScriptedProcess & process,StructuredData::Generic * script_object)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
ScriptedThread(ScriptedProcess & process,ScriptedThreadInterfaceSP interface_sp,lldb::tid_t tid,StructuredData::GenericSP script_object_sp)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
~ScriptedThread()83 ScriptedThread::~ScriptedThread() { DestroyThread(); }
84
GetName()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
GetQueueName()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
WillResume(StateType resume_state)101 void ScriptedThread::WillResume(StateType resume_state) {}
102
ClearStackFrames()103 void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); }
104
GetRegisterContext()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
CreateRegisterContextForFrame(StackFrame * frame)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
LoadArtificialStackFrames()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
CalculateStopInfo()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
RefreshStateAfterStop()284 void ScriptedThread::RefreshStateAfterStop() {
285 GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
286 LoadArtificialStackFrames();
287 }
288
GetInterface() const289 lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {
290 return m_scripted_thread_interface_sp;
291 }
292
GetDynamicRegisterInfo()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