LLDB mainline
ScriptedThread.cpp
Go to the documentation of this file.
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
14#include "lldb/Target/Process.h"
17#include "lldb/Target/Unwind.h"
20#include <memory>
21#include <optional>
22
23using namespace lldb;
24using namespace lldb_private;
25
27 lldbassert(m_script_object_sp && "Invalid Script Object.");
28 lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");
29}
30
31llvm::Expected<std::shared_ptr<ScriptedThread>>
33 StructuredData::Generic *script_object) {
34 if (!process.IsValid())
35 return llvm::createStringError(llvm::inconvertibleErrorCode(),
36 "Invalid scripted process.");
37
38 process.CheckScriptedInterface();
39
40 auto scripted_thread_interface =
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 std::optional<std::string> class_name =
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, process.m_scripted_metadata.GetArgsSP(),
62 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
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
86
89 std::optional<std::string> thread_name = GetInterface()->GetName();
90 if (!thread_name)
91 return nullptr;
92 return ConstString(thread_name->c_str()).AsCString();
93}
94
97 std::optional<std::string> queue_name = GetInterface()->GetQueue();
98 if (!queue_name)
99 return nullptr;
100 return ConstString(queue_name->c_str()).AsCString();
101}
102
104
106
108 if (!m_reg_context_sp)
110 return m_reg_context_sp;
111}
112
115 const uint32_t concrete_frame_idx =
116 frame ? frame->GetConcreteFrameIndex() : 0;
117
118 if (concrete_frame_idx)
120
121 lldb::RegisterContextSP reg_ctx_sp;
123
124 std::optional<std::string> reg_data = GetInterface()->GetRegisterContext();
125 if (!reg_data)
126 return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(
127 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.",
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 ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(
135 LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error,
137
138 std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
139 std::make_shared<RegisterContextMemory>(
141 if (!reg_ctx_memory)
142 return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(
143 LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error,
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
153 StructuredData::ArraySP arr_sp = GetInterface()->GetStackFrames();
154
156 if (!arr_sp)
157 return ScriptedInterface::ErrorWithMessage<bool>(
158 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stackframes.",
160
161 size_t arr_size = arr_sp->GetSize();
162 if (arr_size > std::numeric_limits<uint32_t>::max())
163 return ScriptedInterface::ErrorWithMessage<bool>(
164 LLVM_PRETTY_FUNCTION,
165 llvm::Twine(
166 "StackFrame array size (" + llvm::Twine(arr_size) +
167 llvm::Twine(
168 ") is greater than maximum authorized for a StackFrameList."))
169 .str(),
171
173
174 for (size_t idx = 0; idx < arr_size; idx++) {
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(),
184
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,
191
192 Address symbol_addr;
193 symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget());
194
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(),
212 }
213
214 return true;
215}
216
218 StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();
219
221 if (!dict_sp)
222 return ScriptedInterface::ErrorWithMessage<bool>(
223 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error,
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,
234
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,
241
242 switch (stop_reason_type) {
244 return true;
246 lldb::break_id_t break_id;
247 data_dict->GetValueForKeyAsInteger("break_id", break_id,
249 stop_info_sp =
251 } break;
253 uint32_t signal;
254 llvm::StringRef description;
255 if (!data_dict->GetValueForKeyAsInteger("signal", signal)) {
257 return false;
258 }
259 data_dict->GetValueForKeyAsString("desc", description);
260 stop_info_sp =
261 StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());
262 } break;
264 stop_info_sp = StopInfo::CreateStopReasonToTrace(*this);
265 } break;
267#if defined(__APPLE__)
268 StructuredData::Dictionary *mach_exception;
269 if (data_dict->GetValueForKeyAsDictionary("mach_exception",
270 mach_exception)) {
271 llvm::StringRef value;
272 mach_exception->GetValueForKeyAsString("type", value);
273 auto exc_type =
274 StopInfoMachException::MachException::ExceptionCode(value.data());
275
276 if (!exc_type)
277 return false;
278
279 uint32_t exc_data_size = 0;
280 llvm::SmallVector<uint64_t, 3> raw_codes;
281
282 StructuredData::Array *exc_rawcodes;
283 mach_exception->GetValueForKeyAsArray("rawCodes", exc_rawcodes);
284 if (exc_rawcodes) {
285 auto fetch_data = [&raw_codes](StructuredData::Object *obj) {
286 if (!obj)
287 return false;
288 raw_codes.push_back(obj->GetUnsignedIntegerValue());
289 return true;
290 };
291
292 exc_rawcodes->ForEach(fetch_data);
293 exc_data_size = raw_codes.size();
294 }
295
297 *this, *exc_type, exc_data_size,
298 exc_data_size >= 1 ? raw_codes[0] : 0,
299 exc_data_size >= 2 ? raw_codes[1] : 0,
300 exc_data_size >= 3 ? raw_codes[2] : 0);
301
302 break;
303 }
304#endif
305 stop_info_sp =
306 StopInfo::CreateStopReasonWithException(*this, "EXC_BAD_ACCESS");
307 } break;
308 default:
309 return ScriptedInterface::ErrorWithMessage<bool>(
310 LLVM_PRETTY_FUNCTION,
311 llvm::Twine("Unsupported stop reason type (" +
312 llvm::Twine(stop_reason_type) + llvm::Twine(")."))
313 .str(),
315 }
316
317 if (!stop_info_sp)
318 return false;
319
320 SetStopInfo(stop_info_sp);
321 return true;
322}
323
325 GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
327}
328
331}
332
333std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {
335
336 if (!m_register_info_sp) {
337 StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
338
340 if (!reg_info)
342 std::shared_ptr<DynamicRegisterInfo>>(
343 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers info.",
345
348 }
349
350 return m_register_info_sp;
351}
352
355
357 StructuredData::ArraySP extended_info_sp = GetInterface()->GetExtendedInfo();
358
359 if (!extended_info_sp || !extended_info_sp->GetSize())
360 return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
361 LLVM_PRETTY_FUNCTION, "No extended information found", error);
362
363 return extended_info_sp;
364}
static llvm::raw_ostream & error(Stream &strm)
#define lldbassert(x)
Definition: LLDBAssert.h:15
A section + offset based address class.
Definition: Address.h:59
bool SetLoadAddress(lldb::addr_t load_addr, Target *target, bool allow_section_end=false)
Set the address to represent load_addr.
Definition: Address.cpp:1040
uint32_t CalculateSymbolContext(SymbolContext *sc, lldb::SymbolContextItem resolve_scope=lldb::eSymbolContextEverything) const
Reconstruct a symbol context from an address.
Definition: Address.cpp:825
A uniqued constant string class.
Definition: ConstString.h:40
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
Definition: ConstString.h:182
static std::unique_ptr< DynamicRegisterInfo > Create(const StructuredData::Dictionary &dict, const ArchSpec &arch)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
bool IsValid() const
Return whether this object is valid (i.e.
Definition: Process.h:567
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1242
static Ret ErrorWithMessage(llvm::StringRef caller_name, llvm::StringRef error_msg, Status &error, LLDBLog log_caterogy=LLDBLog::Process)
StructuredData::DictionarySP GetArgsSP() const
virtual lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface()
virtual std::optional< std::string > GetScriptedThreadPluginName()
const ScriptedMetadata m_scripted_metadata
ScriptedProcessInterface & GetInterface() const
void CheckInterpreterAndScriptObject() const
std::shared_ptr< DynamicRegisterInfo > GetDynamicRegisterInfo()
lldb_private::StructuredData::GenericSP m_script_object_sp
const char * GetQueueName() override
Retrieve the Queue name for the queue currently using this Thread.
lldb::RegisterContextSP CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override
std::shared_ptr< DynamicRegisterInfo > m_register_info_sp
lldb::ScriptedThreadInterfaceSP GetInterface() const
StructuredData::ObjectSP FetchThreadExtendedInfo() override
lldb::ScriptedThreadInterfaceSP m_scripted_thread_interface_sp
static llvm::Expected< std::shared_ptr< ScriptedThread > > Create(ScriptedProcess &process, StructuredData::Generic *script_object=nullptr)
void RefreshStateAfterStop() override
void WillResume(lldb::StateType resume_state) override
ScriptedThread(ScriptedProcess &process, lldb::ScriptedThreadInterfaceSP interface_sp, lldb::tid_t tid, StructuredData::GenericSP script_object_sp=nullptr)
const char * GetName() override
const ScriptedProcess & m_scripted_process
lldb::RegisterContextSP GetRegisterContext() override
This base class provides an interface to stack frames.
Definition: StackFrame.h:41
uint32_t GetConcreteFrameIndex() const
Query this frame to find what frame it is in this Thread's StackFrameList, not counting inlined frame...
Definition: StackFrame.h:412
@ Artificial
An artificial stack frame (e.g.
An error handling class.
Definition: Status.h:44
static lldb::StopInfoSP CreateStopReasonWithMachException(Thread &thread, uint32_t exc_type, uint32_t exc_data_count, uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code, bool pc_already_adjusted=true, bool adjust_pc_if_needed=false)
static lldb::StopInfoSP CreateStopReasonToTrace(Thread &thread)
Definition: StopInfo.cpp:1386
static lldb::StopInfoSP CreateStopReasonWithSignal(Thread &thread, int signo, const char *description=nullptr, std::optional< int > code=std::nullopt)
Definition: StopInfo.cpp:1379
static lldb::StopInfoSP CreateStopReasonWithException(Thread &thread, const char *description)
Definition: StopInfo.cpp:1397
static lldb::StopInfoSP CreateStopReasonWithBreakpointSiteID(Thread &thread, lldb::break_id_t break_id)
bool ForEach(std::function< bool(Object *object)> const &foreach_callback) const
bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const
bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result) const
bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const
bool GetValueForKeyAsDictionary(llvm::StringRef key, Dictionary *&result) const
std::shared_ptr< Generic > GenericSP
std::shared_ptr< Dictionary > DictionarySP
std::shared_ptr< Object > ObjectSP
std::shared_ptr< Array > ArraySP
Defines a symbol context baton that can be handed other debug core functions.
Definition: SymbolContext.h:33
const ArchSpec & GetArchitecture() const
Definition: Target.h:1009
void SetStopInfo(const lldb::StopInfoSP &stop_info_sp)
Definition: Thread.cpp:448
virtual void DestroyThread()
Definition: Thread.cpp:245
virtual void ClearStackFrames()
Definition: Thread.cpp:1409
virtual Unwind & GetUnwinder()
Definition: Thread.cpp:1861
lldb::ProcessSP GetProcess() const
Definition: Thread.h:153
lldb::StackFrameListSP GetStackFrameList()
Definition: Thread.cpp:1399
lldb::RegisterContextSP m_reg_context_sp
The register context for this thread's current register state.
Definition: Thread.h:1274
lldb::RegisterContextSP CreateRegisterContextForFrame(StackFrame *frame)
Definition: Unwind.h:56
#define LLDB_INVALID_BREAK_ID
Definition: lldb-defines.h:37
#define LLDB_INVALID_SIGNAL_NUMBER
Definition: lldb-defines.h:86
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:76
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
Definition: lldb-forward.h:399
StateType
Process and Thread States.
int32_t break_id_t
Definition: lldb-types.h:84
std::shared_ptr< lldb_private::ScriptedThreadInterface > ScriptedThreadInterfaceSP
Definition: lldb-forward.h:392
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
Definition: lldb-forward.h:318
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
Definition: lldb-forward.h:406
uint64_t addr_t
Definition: lldb-types.h:79
StopReason
Thread stop reasons.
@ eStopReasonTrace
@ eStopReasonBreakpoint
@ eStopReasonException
@ eStopReasonSignal
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
Definition: lldb-forward.h:373
uint64_t tid_t
Definition: lldb-types.h:82
std::shared_ptr< lldb_private::StackFrameList > StackFrameListSP
Definition: lldb-forward.h:401