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#include "ScriptedFrame.h"
11
15#include "lldb/Target/Process.h"
18#include "lldb/Target/Unwind.h"
21#include <memory>
22#include <optional>
23
24using namespace lldb;
25using namespace lldb_private;
26
28 lldbassert(m_script_object_sp && "Invalid Script Object.");
29 lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");
30}
31
32llvm::Expected<std::shared_ptr<ScriptedThread>>
34 StructuredData::Generic *script_object) {
35 if (!process.IsValid())
36 return llvm::createStringError(llvm::inconvertibleErrorCode(),
37 "Invalid scripted process.");
38
39 process.CheckScriptedInterface();
40
41 auto scripted_thread_interface =
43 if (!scripted_thread_interface)
44 return llvm::createStringError(
45 llvm::inconvertibleErrorCode(),
46 "Failed to create scripted thread interface.");
47
48 llvm::StringRef thread_class_name;
49 if (!script_object) {
50 std::optional<std::string> class_name =
52 if (!class_name || class_name->empty())
53 return llvm::createStringError(
54 llvm::inconvertibleErrorCode(),
55 "Failed to get scripted thread class name.");
56 thread_class_name = *class_name;
57 }
58
59 ExecutionContext exe_ctx(process);
60 auto obj_or_err = scripted_thread_interface->CreatePluginObject(
61 thread_class_name, exe_ctx, process.m_scripted_metadata.GetArgsSP(),
62 script_object);
63
64 if (!obj_or_err) {
65 llvm::consumeError(obj_or_err.takeError());
66 return llvm::createStringError(llvm::inconvertibleErrorCode(),
67 "Failed to create script object.");
68 }
69
70 StructuredData::GenericSP owned_script_object_sp = *obj_or_err;
71
72 if (!owned_script_object_sp->IsValid())
73 return llvm::createStringError(llvm::inconvertibleErrorCode(),
74 "Created script object is invalid.");
75
76 lldb::tid_t tid = scripted_thread_interface->GetThreadID();
77
78 return std::make_shared<ScriptedThread>(process, scripted_thread_interface,
79 tid, owned_script_object_sp);
80}
81
83 ScriptedThreadInterfaceSP interface_sp,
84 lldb::tid_t tid,
85 StructuredData::GenericSP script_object_sp)
86 : Thread(process, tid), m_scripted_process(process),
88 m_script_object_sp(script_object_sp) {}
89
91
94 std::optional<std::string> thread_name = GetInterface()->GetName();
95 if (!thread_name)
96 return nullptr;
97 return ConstString(thread_name->c_str()).AsCString();
98}
99
102 std::optional<std::string> queue_name = GetInterface()->GetQueue();
103 if (!queue_name)
104 return nullptr;
105 return ConstString(queue_name->c_str()).AsCString();
106}
107
109
111
117
120 const uint32_t concrete_frame_idx =
121 frame ? frame->GetConcreteFrameIndex() : 0;
122
123 if (concrete_frame_idx)
125
126 lldb::RegisterContextSP reg_ctx_sp;
128
129 std::optional<std::string> reg_data = GetInterface()->GetRegisterContext();
130 if (!reg_data)
132 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.",
134
135 DataBufferSP data_sp(
136 std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
137
138 if (!data_sp->GetByteSize())
140 LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error,
142
143 std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
144 std::make_shared<RegisterContextMemory>(
146 if (!reg_ctx_memory)
148 LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error,
150
151 reg_ctx_memory->SetAllRegisterData(data_sp);
152 m_reg_context_sp = reg_ctx_memory;
153
154 return m_reg_context_sp;
155}
156
158 StructuredData::ArraySP arr_sp = GetInterface()->GetStackFrames();
159
161 if (!arr_sp)
163 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stackframes.",
165
166 size_t arr_size = arr_sp->GetSize();
167 if (arr_size > std::numeric_limits<uint32_t>::max())
169 LLVM_PRETTY_FUNCTION,
170 llvm::Twine(
171 "StackFrame array size (" + llvm::Twine(arr_size) +
172 llvm::Twine(
173 ") is greater than maximum authorized for a StackFrameList."))
174 .str(),
176
177 auto create_frame_from_dict =
178 [this, arr_sp](size_t idx) -> llvm::Expected<StackFrameSP> {
180 std::optional<StructuredData::Dictionary *> maybe_dict =
181 arr_sp->GetItemAtIndexAsDictionary(idx);
182 if (!maybe_dict) {
184 LLVM_PRETTY_FUNCTION,
185 llvm::Twine(
186 "Couldn't get artificial stackframe dictionary at index (" +
187 llvm::Twine(idx) + llvm::Twine(") from stackframe array."))
188 .str(),
190 return error.ToError();
191 }
192 StructuredData::Dictionary *dict = *maybe_dict;
193
195 if (!dict->GetValueForKeyAsInteger("pc", pc)) {
197 LLVM_PRETTY_FUNCTION,
198 "Couldn't find value for key 'pc' in stackframe dictionary.", error,
200 return error.ToError();
201 }
202
203 Address symbol_addr;
204 symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget());
205
207 bool cfa_is_valid = false;
208 const bool artificial = false;
209 const bool behaves_like_zeroth_frame = false;
210 SymbolContext sc;
211 symbol_addr.CalculateSymbolContext(&sc);
212
213 return std::make_shared<StackFrame>(this->shared_from_this(), idx, idx, cfa,
214 cfa_is_valid, pc,
215 StackFrame::Kind::Synthetic, artificial,
216 behaves_like_zeroth_frame, &sc);
217 };
218
219 auto create_frame_from_script_object =
220 [this, arr_sp](size_t idx) -> llvm::Expected<StackFrameSP> {
222 StructuredData::ObjectSP object_sp = arr_sp->GetItemAtIndex(idx);
223 if (!object_sp || !object_sp->GetAsGeneric()) {
225 LLVM_PRETTY_FUNCTION,
226 llvm::Twine("Couldn't get artificial stackframe object at index (" +
227 llvm::Twine(idx) +
228 llvm::Twine(") from stackframe array."))
229 .str(),
231 return error.ToError();
232 }
233
234 auto frame_or_error =
235 ScriptedFrame::Create(*this, nullptr, object_sp->GetAsGeneric());
236
237 if (!frame_or_error) {
239 LLVM_PRETTY_FUNCTION, toString(frame_or_error.takeError()), error);
240 return error.ToError();
241 }
242
243 StackFrameSP frame_sp = frame_or_error.get();
244 lldbassert(frame_sp && "Couldn't initialize scripted frame.");
245
246 return frame_sp;
247 };
248
250
251 for (size_t idx = 0; idx < arr_size; idx++) {
252 StackFrameSP synth_frame_sp = nullptr;
253
254 auto frame_from_dict_or_err = create_frame_from_dict(idx);
255 if (!frame_from_dict_or_err) {
256 auto frame_from_script_obj_or_err = create_frame_from_script_object(idx);
257
258 if (!frame_from_script_obj_or_err) {
260 LLVM_PRETTY_FUNCTION,
261 llvm::Twine("Couldn't add artificial frame (" + llvm::Twine(idx) +
262 llvm::Twine(") to ScriptedThread StackFrameList."))
263 .str(),
265 } else {
266 llvm::consumeError(frame_from_dict_or_err.takeError());
267 synth_frame_sp = *frame_from_script_obj_or_err;
268 }
269 } else {
270 synth_frame_sp = *frame_from_dict_or_err;
271 }
272
273 if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp))
275 LLVM_PRETTY_FUNCTION,
276 llvm::Twine("Couldn't add frame (" + llvm::Twine(idx) +
277 llvm::Twine(") to ScriptedThread StackFrameList."))
278 .str(),
280 }
281
282 return true;
283}
284
286 StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();
287
289 if (!dict_sp)
291 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error,
293
294 // If we're at a BreakpointSite, mark that we stopped there and
295 // need to hit the breakpoint when we resume. This will be cleared
296 // if we CreateStopReasonWithBreakpointSiteID.
297 if (RegisterContextSP reg_ctx_sp = GetRegisterContext()) {
298 addr_t pc = reg_ctx_sp->GetPC();
299 if (BreakpointSiteSP bp_site_sp =
300 GetProcess()->GetBreakpointSiteList().FindByAddress(pc))
301 if (bp_site_sp->IsEnabled())
303 }
304
305 lldb::StopInfoSP stop_info_sp;
306 lldb::StopReason stop_reason_type;
307
308 if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type))
310 LLVM_PRETTY_FUNCTION,
311 "Couldn't find value for key 'type' in stop reason dictionary.", error,
313
315 if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict))
317 LLVM_PRETTY_FUNCTION,
318 "Couldn't find value for key 'data' in stop reason dictionary.", error,
320
321 switch (stop_reason_type) {
323 return true;
325 lldb::break_id_t break_id;
326 data_dict->GetValueForKeyAsInteger("break_id", break_id,
328 stop_info_sp =
330 } break;
332 uint32_t signal;
333 llvm::StringRef description;
334 if (!data_dict->GetValueForKeyAsInteger("signal", signal)) {
336 return false;
337 }
338 data_dict->GetValueForKeyAsString("desc", description);
339 stop_info_sp =
340 StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());
341 } break;
343 stop_info_sp = StopInfo::CreateStopReasonToTrace(*this);
344 } break;
346#if defined(__APPLE__)
347 StructuredData::Dictionary *mach_exception;
348 if (data_dict->GetValueForKeyAsDictionary("mach_exception",
349 mach_exception)) {
350 llvm::StringRef value;
351 mach_exception->GetValueForKeyAsString("type", value);
352 auto exc_type =
353 StopInfoMachException::MachException::ExceptionCode(value.data());
354
355 if (!exc_type)
356 return false;
357
358 uint32_t exc_data_size = 0;
359 llvm::SmallVector<uint64_t, 3> raw_codes;
360
361 StructuredData::Array *exc_rawcodes;
362 mach_exception->GetValueForKeyAsArray("rawCodes", exc_rawcodes);
363 if (exc_rawcodes) {
364 auto fetch_data = [&raw_codes](StructuredData::Object *obj) {
365 if (!obj)
366 return false;
367 raw_codes.push_back(obj->GetUnsignedIntegerValue());
368 return true;
369 };
370
371 exc_rawcodes->ForEach(fetch_data);
372 exc_data_size = raw_codes.size();
373 }
374
376 *this, *exc_type, exc_data_size,
377 exc_data_size >= 1 ? raw_codes[0] : 0,
378 exc_data_size >= 2 ? raw_codes[1] : 0,
379 exc_data_size >= 3 ? raw_codes[2] : 0);
380
381 break;
382 }
383#endif
384 stop_info_sp =
385 StopInfo::CreateStopReasonWithException(*this, "EXC_BAD_ACCESS");
386 } break;
387 default:
389 LLVM_PRETTY_FUNCTION,
390 llvm::Twine("Unsupported stop reason type (" +
391 llvm::Twine(stop_reason_type) + llvm::Twine(")."))
392 .str(),
394 }
395
396 if (!stop_info_sp)
397 return false;
398
399 SetStopInfo(stop_info_sp);
400 return true;
401}
402
404 GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
406}
407
411
412std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {
414
415 if (!m_register_info_sp) {
416 StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
417
419 if (!reg_info)
421 std::shared_ptr<DynamicRegisterInfo>>(
422 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers info.",
424
426 *reg_info, m_scripted_process.GetTarget().GetArchitecture());
427 }
428
429 return m_register_info_sp;
430}
431
434
436 StructuredData::ArraySP extended_info_sp = GetInterface()->GetExtendedInfo();
437
438 if (!extended_info_sp || !extended_info_sp->GetSize())
440 LLVM_PRETTY_FUNCTION, "No extended information found", error);
441
442 return extended_info_sp;
443}
static llvm::raw_ostream & error(Stream &strm)
#define lldbassert(x)
Definition LLDBAssert.h:16
A section + offset based address class.
Definition Address.h:62
bool SetLoadAddress(lldb::addr_t load_addr, Target *target, bool allow_section_end=false)
Set the address to represent load_addr.
Definition Address.cpp:1035
uint32_t CalculateSymbolContext(SymbolContext *sc, lldb::SymbolContextItem resolve_scope=lldb::eSymbolContextEverything) const
Reconstruct a symbol context from an address.
Definition Address.cpp:820
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.
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:591
static llvm::Expected< std::shared_ptr< ScriptedFrame > > Create(ScriptedThread &thread, StructuredData::DictionarySP args_sp, StructuredData::Generic *script_object=nullptr)
static Ret ErrorWithMessage(llvm::StringRef caller_name, llvm::StringRef error_msg, Status &error, LLDBLog log_category=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 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
bool CalculateStopInfo() override
Ask the thread subclass to set its stop info.
const ScriptedProcess & m_scripted_process
lldb::RegisterContextSP GetRegisterContext() override
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:455
@ Synthetic
An synthetic stack frame (e.g.
Definition StackFrame.h:65
An error handling class.
Definition Status.h:118
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)
static lldb::StopInfoSP CreateStopReasonWithSignal(Thread &thread, int signo, const char *description=nullptr, std::optional< int > code=std::nullopt)
static lldb::StopInfoSP CreateStopReasonWithException(Thread &thread, const char *description)
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.
void SetStopInfo(const lldb::StopInfoSP &stop_info_sp)
Definition Thread.cpp:464
virtual void DestroyThread()
Definition Thread.cpp:252
virtual void ClearStackFrames()
Definition Thread.cpp:1453
virtual Unwind & GetUnwinder()
Definition Thread.cpp:1934
Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id=false)
Constructor.
Definition Thread.cpp:219
void SetThreadStoppedAtUnexecutedBP(lldb::addr_t pc)
When a thread stops at an enabled BreakpointSite that has not executed, the Process plugin should cal...
Definition Thread.h:399
lldb::ProcessSP GetProcess() const
Definition Thread.h:158
friend class StackFrame
Definition Thread.h:1303
lldb::StackFrameListSP GetStackFrameList()
Definition Thread.cpp:1439
lldb::RegisterContextSP m_reg_context_sp
The register context for this thread's current register state.
Definition Thread.h:1370
lldb::RegisterContextSP CreateRegisterContextForFrame(StackFrame *frame)
Definition Unwind.h:56
#define LLDB_INVALID_BREAK_ID
#define LLDB_INVALID_SIGNAL_NUMBER
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
const char * toString(AppleArm64ExceptionClass EC)
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::BreakpointSite > BreakpointSiteSP
StateType
Process and Thread States.
int32_t break_id_t
Definition lldb-types.h:86
std::shared_ptr< lldb_private::ScriptedThreadInterface > ScriptedThreadInterfaceSP
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
uint64_t addr_t
Definition lldb-types.h:80
StopReason
Thread stop reasons.
@ eStopReasonBreakpoint
@ eStopReasonException
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
uint64_t tid_t
Definition lldb-types.h:84
std::shared_ptr< lldb_private::StackFrameList > StackFrameListSP