1 //===-- ScriptedThread.cpp ------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "ScriptedThread.h"
11 #include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
12 #include "Plugins/Process/Utility/StopInfoMachException.h"
13 #include "lldb/Target/OperatingSystem.h"
14 #include "lldb/Target/Process.h"
15 #include "lldb/Target/RegisterContext.h"
16 #include "lldb/Target/StopInfo.h"
17 #include "lldb/Target/Unwind.h"
18 #include "lldb/Utility/DataBufferHeap.h"
19 #include "lldb/Utility/LLDBLog.h"
24 using namespace lldb_private
;
26 void ScriptedThread::CheckInterpreterAndScriptObject() const {
27 lldbassert(m_script_object_sp
&& "Invalid Script Object.");
28 lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");
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.");
38 process
.CheckScriptedInterface();
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.");
47 llvm::StringRef thread_class_name
;
49 std::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
;
58 ExecutionContext
exe_ctx(process
);
59 auto obj_or_err
= scripted_thread_interface
->CreatePluginObject(
60 thread_class_name
, exe_ctx
, process
.m_scripted_metadata
.GetArgsSP(),
64 llvm::consumeError(obj_or_err
.takeError());
65 return llvm::createStringError(llvm::inconvertibleErrorCode(),
66 "Failed to create script object.");
69 StructuredData::GenericSP owned_script_object_sp
= *obj_or_err
;
71 if (!owned_script_object_sp
->IsValid())
72 return llvm::createStringError(llvm::inconvertibleErrorCode(),
73 "Created script object is invalid.");
75 lldb::tid_t tid
= scripted_thread_interface
->GetThreadID();
77 return std::make_shared
<ScriptedThread
>(process
, scripted_thread_interface
,
78 tid
, owned_script_object_sp
);
81 ScriptedThread::ScriptedThread(ScriptedProcess
&process
,
82 ScriptedThreadInterfaceSP interface_sp
,
84 StructuredData::GenericSP script_object_sp
)
85 : Thread(process
, tid
), m_scripted_process(process
),
86 m_scripted_thread_interface_sp(interface_sp
),
87 m_script_object_sp(script_object_sp
) {}
89 ScriptedThread::~ScriptedThread() { DestroyThread(); }
91 const char *ScriptedThread::GetName() {
92 CheckInterpreterAndScriptObject();
93 std::optional
<std::string
> thread_name
= GetInterface()->GetName();
96 return ConstString(thread_name
->c_str()).AsCString();
99 const char *ScriptedThread::GetQueueName() {
100 CheckInterpreterAndScriptObject();
101 std::optional
<std::string
> queue_name
= GetInterface()->GetQueue();
104 return ConstString(queue_name
->c_str()).AsCString();
107 void ScriptedThread::WillResume(StateType resume_state
) {}
109 void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); }
111 RegisterContextSP
ScriptedThread::GetRegisterContext() {
112 if (!m_reg_context_sp
)
113 m_reg_context_sp
= CreateRegisterContextForFrame(nullptr);
114 return m_reg_context_sp
;
118 ScriptedThread::CreateRegisterContextForFrame(StackFrame
*frame
) {
119 const uint32_t concrete_frame_idx
=
120 frame
? frame
->GetConcreteFrameIndex() : 0;
122 if (concrete_frame_idx
)
123 return GetUnwinder().CreateRegisterContextForFrame(frame
);
125 lldb::RegisterContextSP reg_ctx_sp
;
128 std::optional
<std::string
> reg_data
= GetInterface()->GetRegisterContext();
130 return ScriptedInterface::ErrorWithMessage
<lldb::RegisterContextSP
>(
131 LLVM_PRETTY_FUNCTION
, "Failed to get scripted thread registers data.",
132 error
, LLDBLog::Thread
);
134 DataBufferSP
data_sp(
135 std::make_shared
<DataBufferHeap
>(reg_data
->c_str(), reg_data
->size()));
137 if (!data_sp
->GetByteSize())
138 return ScriptedInterface::ErrorWithMessage
<lldb::RegisterContextSP
>(
139 LLVM_PRETTY_FUNCTION
, "Failed to copy raw registers data.", error
,
142 std::shared_ptr
<RegisterContextMemory
> reg_ctx_memory
=
143 std::make_shared
<RegisterContextMemory
>(
144 *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS
);
146 return ScriptedInterface::ErrorWithMessage
<lldb::RegisterContextSP
>(
147 LLVM_PRETTY_FUNCTION
, "Failed to create a register context.", error
,
150 reg_ctx_memory
->SetAllRegisterData(data_sp
);
151 m_reg_context_sp
= reg_ctx_memory
;
153 return m_reg_context_sp
;
156 bool ScriptedThread::LoadArtificialStackFrames() {
157 StructuredData::ArraySP arr_sp
= GetInterface()->GetStackFrames();
161 return ScriptedInterface::ErrorWithMessage
<bool>(
162 LLVM_PRETTY_FUNCTION
, "Failed to get scripted thread stackframes.",
163 error
, LLDBLog::Thread
);
165 size_t arr_size
= arr_sp
->GetSize();
166 if (arr_size
> std::numeric_limits
<uint32_t>::max())
167 return ScriptedInterface::ErrorWithMessage
<bool>(
168 LLVM_PRETTY_FUNCTION
,
170 "StackFrame array size (" + llvm::Twine(arr_size
) +
172 ") is greater than maximum authorized for a StackFrameList."))
174 error
, LLDBLog::Thread
);
176 StackFrameListSP frames
= GetStackFrameList();
178 for (size_t idx
= 0; idx
< arr_size
; idx
++) {
179 StructuredData::Dictionary
*dict
;
180 if (!arr_sp
->GetItemAtIndexAsDictionary(idx
, dict
) || !dict
)
181 return ScriptedInterface::ErrorWithMessage
<bool>(
182 LLVM_PRETTY_FUNCTION
,
184 "Couldn't get artificial stackframe dictionary at index (" +
185 llvm::Twine(idx
) + llvm::Twine(") from stackframe array."))
187 error
, LLDBLog::Thread
);
190 if (!dict
->GetValueForKeyAsInteger("pc", pc
))
191 return ScriptedInterface::ErrorWithMessage
<bool>(
192 LLVM_PRETTY_FUNCTION
,
193 "Couldn't find value for key 'pc' in stackframe dictionary.", error
,
197 symbol_addr
.SetLoadAddress(pc
, &this->GetProcess()->GetTarget());
199 lldb::addr_t cfa
= LLDB_INVALID_ADDRESS
;
200 bool cfa_is_valid
= false;
201 const bool behaves_like_zeroth_frame
= false;
203 symbol_addr
.CalculateSymbolContext(&sc
);
205 StackFrameSP synth_frame_sp
= std::make_shared
<StackFrame
>(
206 this->shared_from_this(), idx
, idx
, cfa
, cfa_is_valid
, pc
,
207 StackFrame::Kind::Artificial
, behaves_like_zeroth_frame
, &sc
);
209 if (!frames
->SetFrameAtIndex(static_cast<uint32_t>(idx
), synth_frame_sp
))
210 return ScriptedInterface::ErrorWithMessage
<bool>(
211 LLVM_PRETTY_FUNCTION
,
212 llvm::Twine("Couldn't add frame (" + llvm::Twine(idx
) +
213 llvm::Twine(") to ScriptedThread StackFrameList."))
215 error
, LLDBLog::Thread
);
221 bool ScriptedThread::CalculateStopInfo() {
222 StructuredData::DictionarySP dict_sp
= GetInterface()->GetStopReason();
226 return ScriptedInterface::ErrorWithMessage
<bool>(
227 LLVM_PRETTY_FUNCTION
, "Failed to get scripted thread stop info.", error
,
230 lldb::StopInfoSP stop_info_sp
;
231 lldb::StopReason stop_reason_type
;
233 if (!dict_sp
->GetValueForKeyAsInteger("type", stop_reason_type
))
234 return ScriptedInterface::ErrorWithMessage
<bool>(
235 LLVM_PRETTY_FUNCTION
,
236 "Couldn't find value for key 'type' in stop reason dictionary.", error
,
239 StructuredData::Dictionary
*data_dict
;
240 if (!dict_sp
->GetValueForKeyAsDictionary("data", data_dict
))
241 return ScriptedInterface::ErrorWithMessage
<bool>(
242 LLVM_PRETTY_FUNCTION
,
243 "Couldn't find value for key 'data' in stop reason dictionary.", error
,
246 switch (stop_reason_type
) {
247 case lldb::eStopReasonNone
:
249 case lldb::eStopReasonBreakpoint
: {
250 lldb::break_id_t break_id
;
251 data_dict
->GetValueForKeyAsInteger("break_id", break_id
,
252 LLDB_INVALID_BREAK_ID
);
254 StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id
);
256 case lldb::eStopReasonSignal
: {
258 llvm::StringRef description
;
259 if (!data_dict
->GetValueForKeyAsInteger("signal", signal
)) {
260 signal
= LLDB_INVALID_SIGNAL_NUMBER
;
263 data_dict
->GetValueForKeyAsString("desc", description
);
265 StopInfo::CreateStopReasonWithSignal(*this, signal
, description
.data());
267 case lldb::eStopReasonTrace
: {
268 stop_info_sp
= StopInfo::CreateStopReasonToTrace(*this);
270 case lldb::eStopReasonException
: {
271 #if defined(__APPLE__)
272 StructuredData::Dictionary
*mach_exception
;
273 if (data_dict
->GetValueForKeyAsDictionary("mach_exception",
275 llvm::StringRef value
;
276 mach_exception
->GetValueForKeyAsString("type", value
);
278 StopInfoMachException::MachException::ExceptionCode(value
.data());
283 uint32_t exc_data_size
= 0;
284 llvm::SmallVector
<uint64_t, 3> raw_codes
;
286 StructuredData::Array
*exc_rawcodes
;
287 mach_exception
->GetValueForKeyAsArray("rawCodes", exc_rawcodes
);
289 auto fetch_data
= [&raw_codes
](StructuredData::Object
*obj
) {
292 raw_codes
.push_back(obj
->GetUnsignedIntegerValue());
296 exc_rawcodes
->ForEach(fetch_data
);
297 exc_data_size
= raw_codes
.size();
300 stop_info_sp
= StopInfoMachException::CreateStopReasonWithMachException(
301 *this, *exc_type
, exc_data_size
,
302 exc_data_size
>= 1 ? raw_codes
[0] : 0,
303 exc_data_size
>= 2 ? raw_codes
[1] : 0,
304 exc_data_size
>= 3 ? raw_codes
[2] : 0);
310 StopInfo::CreateStopReasonWithException(*this, "EXC_BAD_ACCESS");
313 return ScriptedInterface::ErrorWithMessage
<bool>(
314 LLVM_PRETTY_FUNCTION
,
315 llvm::Twine("Unsupported stop reason type (" +
316 llvm::Twine(stop_reason_type
) + llvm::Twine(")."))
318 error
, LLDBLog::Thread
);
324 SetStopInfo(stop_info_sp
);
328 void ScriptedThread::RefreshStateAfterStop() {
329 GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
330 LoadArtificialStackFrames();
333 lldb::ScriptedThreadInterfaceSP
ScriptedThread::GetInterface() const {
334 return m_scripted_thread_interface_sp
;
337 std::shared_ptr
<DynamicRegisterInfo
> ScriptedThread::GetDynamicRegisterInfo() {
338 CheckInterpreterAndScriptObject();
340 if (!m_register_info_sp
) {
341 StructuredData::DictionarySP reg_info
= GetInterface()->GetRegisterInfo();
345 return ScriptedInterface::ErrorWithMessage
<
346 std::shared_ptr
<DynamicRegisterInfo
>>(
347 LLVM_PRETTY_FUNCTION
, "Failed to get scripted thread registers info.",
348 error
, LLDBLog::Thread
);
350 m_register_info_sp
= DynamicRegisterInfo::Create(
351 *reg_info
, m_scripted_process
.GetTarget().GetArchitecture());
354 return m_register_info_sp
;
357 StructuredData::ObjectSP
ScriptedThread::FetchThreadExtendedInfo() {
358 CheckInterpreterAndScriptObject();
361 StructuredData::ArraySP extended_info_sp
= GetInterface()->GetExtendedInfo();
363 if (!extended_info_sp
|| !extended_info_sp
->GetSize())
364 return ScriptedInterface::ErrorWithMessage
<StructuredData::ObjectSP
>(
365 LLVM_PRETTY_FUNCTION
, "No extended information found", error
);
367 return extended_info_sp
;