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
14#include "lldb/Core/Debugger.h"
16#include "lldb/Target/Process.h"
19#include "lldb/Target/Unwind.h"
22#include <memory>
23#include <optional>
24
25using namespace lldb;
26using namespace lldb_private;
27
29 lldbassert(m_script_object_sp && "Invalid Script Object.");
30 lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");
31}
32
33llvm::Expected<std::shared_ptr<ScriptedThread>>
35 StructuredData::Generic *script_object) {
36 if (!process.IsValid())
37 return llvm::createStringError(llvm::inconvertibleErrorCode(),
38 "Invalid scripted process.");
39
40 process.CheckScriptedInterface();
41
42 auto scripted_thread_interface =
44 if (!scripted_thread_interface)
45 return llvm::createStringError(
46 llvm::inconvertibleErrorCode(),
47 "Failed to create scripted thread interface.");
48
49 llvm::StringRef thread_class_name;
50 if (!script_object) {
51 std::optional<std::string> class_name =
53 if (!class_name || class_name->empty())
54 return llvm::createStringError(
55 llvm::inconvertibleErrorCode(),
56 "Failed to get scripted thread class name.");
57 thread_class_name = *class_name;
58 }
59
60 ExecutionContext exe_ctx(process);
61 // The legacy thread-spawn path (no script_object) needs to instantiate a
62 // *thread* Python class whose name comes from the process plugin, not the
63 // process's own class name. Build a thread-specific metadata for that case;
64 // when script_object is non-null the class name is unused so we just forward
65 // the process's metadata.
66 ScriptedMetadata thread_metadata =
67 script_object ? process.m_scripted_metadata
68 : ScriptedMetadata(thread_class_name,
70 auto obj_or_err = scripted_thread_interface->CreatePluginObject(
71 thread_metadata, exe_ctx, script_object);
72
73 if (!obj_or_err)
74 return obj_or_err.takeError();
75
76 StructuredData::GenericSP owned_script_object_sp = *obj_or_err;
77
78 if (!owned_script_object_sp->IsValid())
79 return llvm::createStringError(llvm::inconvertibleErrorCode(),
80 "Created script object is invalid.");
81
82 lldb::tid_t tid = scripted_thread_interface->GetThreadID();
83
84 return std::make_shared<ScriptedThread>(process, scripted_thread_interface,
85 tid, owned_script_object_sp);
86}
87
89 ScriptedThreadInterfaceSP interface_sp,
90 lldb::tid_t tid,
91 StructuredData::GenericSP script_object_sp)
92 : Thread(process, tid), m_scripted_process(process),
94 m_script_object_sp(script_object_sp) {}
95
97
100 std::optional<std::string> thread_name = GetInterface()->GetName();
101 if (!thread_name)
102 return nullptr;
103 return ConstString(*thread_name).AsCString(nullptr);
104}
105
108 std::optional<std::string> queue_name = GetInterface()->GetQueue();
109 if (!queue_name)
110 return nullptr;
111 return ConstString(*queue_name).AsCString(nullptr);
112}
113
115
117
123
126 const uint32_t concrete_frame_idx =
127 frame ? frame->GetConcreteFrameIndex() : 0;
128
129 if (concrete_frame_idx)
131
132 lldb::RegisterContextSP reg_ctx_sp;
134
135 std::optional<std::string> reg_data = GetInterface()->GetRegisterContext();
136 if (!reg_data)
138 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.",
140
141 DataBufferSP data_sp(
142 std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
143
144 if (!data_sp->GetByteSize())
146 LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error,
148
150 if (!register_info_sp)
152 LLVM_PRETTY_FUNCTION,
153 "Failed to create scripted thread registers info.", error,
155
156 std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
157 std::make_shared<RegisterContextMemory>(
158 *this, 0, std::move(register_info_sp), LLDB_INVALID_ADDRESS);
159 if (!reg_ctx_memory)
161 LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error,
163
164 reg_ctx_memory->SetAllRegisterData(data_sp);
165 m_reg_context_sp = reg_ctx_memory;
166
167 return m_reg_context_sp;
168}
169
171 StructuredData::ArraySP arr_sp = GetInterface()->GetStackFrames();
172
174 if (!arr_sp)
176 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stackframes.",
178
179 size_t arr_size = arr_sp->GetSize();
180 if (!arr_size)
182 LLVM_PRETTY_FUNCTION, "StackFrame array is empty.", error,
184
185 if (arr_size > std::numeric_limits<uint32_t>::max())
187 LLVM_PRETTY_FUNCTION,
188 llvm::Twine(
189 "StackFrame array size (" + llvm::Twine(arr_size) +
190 ") is greater than maximum authorized for a StackFrameList.")
191 .str(),
193
194 auto create_frame_from_dict =
195 [this, arr_sp](size_t idx,
196 uint32_t frame_list_idx) -> llvm::Expected<StackFrameSP> {
198 std::optional<StructuredData::Dictionary *> maybe_dict =
199 arr_sp->GetItemAtIndexAsDictionary(idx);
200 if (!maybe_dict) {
202 LLVM_PRETTY_FUNCTION,
203 llvm::Twine(
204 "Couldn't get artificial stackframe dictionary at index (" +
205 llvm::Twine(idx) + llvm::Twine(") from stackframe array."))
206 .str(),
208 return error.ToError();
209 }
210 StructuredData::Dictionary *dict = *maybe_dict;
211
213 if (!dict->GetValueForKeyAsInteger("pc", pc)) {
215 LLVM_PRETTY_FUNCTION,
216 "Couldn't find value for key 'pc' in stackframe dictionary.", error,
218 return error.ToError();
219 }
220
221 Address symbol_addr;
222 symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget());
223
225 bool cfa_is_valid = false;
226 const bool artificial = false;
227 const bool behaves_like_zeroth_frame = (frame_list_idx == 0);
228 SymbolContext sc;
229 symbol_addr.CalculateSymbolContext(&sc);
230
231 return std::make_shared<StackFrame>(shared_from_this(), frame_list_idx, idx,
232 cfa, cfa_is_valid, pc,
233 StackFrame::Kind::Synthetic, artificial,
234 behaves_like_zeroth_frame, &sc);
235 };
236
237 auto create_frame_from_script_object =
238 [this, arr_sp](size_t idx) -> llvm::Expected<StackFrameSP> {
240 StructuredData::ObjectSP object_sp = arr_sp->GetItemAtIndex(idx);
241 if (!object_sp || !object_sp->GetAsGeneric()) {
243 LLVM_PRETTY_FUNCTION,
244 llvm::Twine("Couldn't get artificial stackframe object at index (" +
245 llvm::Twine(idx) +
246 llvm::Twine(") from stackframe array."))
247 .str(),
249 return error.ToError();
250 }
251
252 auto frame_or_error = ScriptedFrame::Create(
253 shared_from_this(), GetInterface(), nullptr, object_sp->GetAsGeneric());
254
255 if (!frame_or_error) {
257 LLVM_PRETTY_FUNCTION, toString(frame_or_error.takeError()), error);
258 return error.ToError();
259 }
260
261 StackFrameSP frame_sp = frame_or_error.get();
262 lldbassert(frame_sp && "Couldn't initialize scripted frame.");
263
264 return frame_sp;
265 };
266
268 uint32_t frame_list_idx = 0;
269
270 for (size_t idx = 0; idx < arr_size; idx++) {
271 StackFrameSP synth_frame_sp = nullptr;
272
273 auto frame_from_dict_or_err = create_frame_from_dict(idx, frame_list_idx);
274 if (!frame_from_dict_or_err) {
275 auto frame_from_script_obj_or_err = create_frame_from_script_object(idx);
276
277 if (!frame_from_script_obj_or_err) {
278 llvm::consumeError(frame_from_dict_or_err.takeError());
280 llvm::formatv(
281 "couldn't add artificial frame ({0}) to ScriptedThread "
282 "StackFrameList: {1}",
283 idx, llvm::toString(frame_from_script_obj_or_err.takeError()))
284 .str(),
285 GetProcess()->GetTarget().GetDebugger().GetID());
286 return false;
287 } else {
288 llvm::consumeError(frame_from_dict_or_err.takeError());
289 synth_frame_sp = *frame_from_script_obj_or_err;
290 }
291 } else {
292 synth_frame_sp = *frame_from_dict_or_err;
293 }
294
295 if (!frames->SetFrameAtIndex(frame_list_idx, synth_frame_sp))
297 LLVM_PRETTY_FUNCTION,
298 llvm::Twine("Couldn't add frame (" + llvm::Twine(idx) +
299 llvm::Twine(") to ScriptedThread StackFrameList."))
300 .str(),
302 frame_list_idx++;
303
304 // Synthesize inline frames, mirroring StackFrameList::FetchFramesUpTo().
305 frame_list_idx += frames->SynthesizeInlineFrames(
306 synth_frame_sp, /*cfa=*/LLDB_INVALID_ADDRESS);
307 }
308
309 // Mark the stack as fully unwound so the regular unwinder doesn't try to
310 // extend it beyond the artificial frames (e.g. by reading lr/fp from the
311 // register context).
312 frames->SetAllFramesFetched();
313
314 return true;
315}
316
318 StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();
319
321 if (!dict_sp)
323 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error,
325
326 // If we're at a BreakpointSite, mark that we stopped there and
327 // need to hit the breakpoint when we resume. This will be cleared
328 // if we CreateStopReasonWithBreakpointSiteID.
329 if (RegisterContextSP reg_ctx_sp = GetRegisterContext()) {
330 addr_t pc = reg_ctx_sp->GetPC();
331 ProcessSP proc = GetProcess();
332 if (BreakpointSiteSP bp_site_sp =
333 proc->GetBreakpointSiteList().FindByAddress(pc))
334 if (proc->IsBreakpointSitePhysicallyEnabled(*bp_site_sp))
336 }
337
338 lldb::StopInfoSP stop_info_sp;
339 lldb::StopReason stop_reason_type;
340
341 if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type))
343 LLVM_PRETTY_FUNCTION,
344 "Couldn't find value for key 'type' in stop reason dictionary.", error,
346
348 if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict))
350 LLVM_PRETTY_FUNCTION,
351 "Couldn't find value for key 'data' in stop reason dictionary.", error,
353
354 switch (stop_reason_type) {
356 return true;
358 lldb::break_id_t break_id;
359 data_dict->GetValueForKeyAsInteger("break_id", break_id,
361 stop_info_sp =
363 } break;
365 uint32_t signal;
366 llvm::StringRef description;
367 if (!data_dict->GetValueForKeyAsInteger("signal", signal)) {
369 return false;
370 }
371 data_dict->GetValueForKeyAsString("desc", description);
372 stop_info_sp =
373 StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());
374 } break;
376 stop_info_sp = StopInfo::CreateStopReasonToTrace(*this);
377 } break;
379#if defined(__APPLE__)
380 StructuredData::Dictionary *mach_exception;
381 if (data_dict->GetValueForKeyAsDictionary("mach_exception",
382 mach_exception)) {
383 llvm::StringRef value;
384 mach_exception->GetValueForKeyAsString("type", value);
385 auto exc_type =
386 StopInfoMachException::MachException::ExceptionCode(value.data());
387
388 if (!exc_type)
389 return false;
390
391 uint32_t exc_data_size = 0;
392 llvm::SmallVector<uint64_t, 3> raw_codes;
393
394 StructuredData::Array *exc_rawcodes;
395 mach_exception->GetValueForKeyAsArray("rawCodes", exc_rawcodes);
396 if (exc_rawcodes) {
397 auto fetch_data = [&raw_codes](StructuredData::Object *obj) {
398 if (!obj)
399 return false;
400 raw_codes.push_back(obj->GetUnsignedIntegerValue());
401 return true;
402 };
403
404 exc_rawcodes->ForEach(fetch_data);
405 exc_data_size = raw_codes.size();
406 }
407
409 *this, *exc_type, exc_data_size,
410 exc_data_size >= 1 ? raw_codes[0] : 0,
411 exc_data_size >= 2 ? raw_codes[1] : 0,
412 exc_data_size >= 3 ? raw_codes[2] : 0);
413
414 break;
415 }
416#endif
417 stop_info_sp =
418 StopInfo::CreateStopReasonWithException(*this, "EXC_BAD_ACCESS");
419 } break;
420 default:
422 LLVM_PRETTY_FUNCTION,
423 llvm::Twine("Unsupported stop reason type (" +
424 llvm::Twine(stop_reason_type) + llvm::Twine(")."))
425 .str(),
427 }
428
429 if (!stop_info_sp)
430 return false;
431
432 SetStopInfo(stop_info_sp);
433 return true;
434}
435
437 GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
439}
440
444
447
448 StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
449
451 if (!reg_info)
453 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers info.",
455
457 *reg_info, m_scripted_process.GetTarget().GetArchitecture());
458}
459
462
464 StructuredData::ArraySP extended_info_sp = GetInterface()->GetExtendedInfo();
465
466 if (!extended_info_sp || !extended_info_sp->GetSize())
468 LLVM_PRETTY_FUNCTION, "No extended information found", error);
469
470 return extended_info_sp;
471}
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:1028
uint32_t CalculateSymbolContext(SymbolContext *sc, lldb::SymbolContextItem resolve_scope=lldb::eSymbolContextEverything) const
Reconstruct a symbol context from an address.
Definition Address.cpp:819
A uniqued constant string class.
Definition ConstString.h:40
const char * AsCString(const char *value_if_empty) const
Get the string value as a C string.
static void ReportError(std::string message, std::optional< lldb::user_id_t > debugger_id=std::nullopt, std::once_flag *once=nullptr)
Report error events.
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:579
static llvm::Expected< std::shared_ptr< ScriptedFrame > > Create(lldb::ThreadSP thread_sp, lldb::ScriptedThreadInterfaceSP scripted_thread_interface_sp, StructuredData::DictionarySP args_sp, StructuredData::Generic *script_object=nullptr)
Create a ScriptedFrame from a object instanciated in the script interpreter.
static Ret ErrorWithMessage(llvm::StringRef caller_name, llvm::StringRef user_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
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
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
lldb::DynamicRegisterInfoSP GetDynamicRegisterInfo()
virtual uint32_t GetConcreteFrameIndex()
Query this frame to find what frame it is in this Thread's StackFrameList, not counting inlined frame...
Definition StackFrame.h:486
@ Synthetic
An synthetic stack frame (e.g.
Definition StackFrame.h:72
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:479
virtual void DestroyThread()
Definition Thread.cpp:259
virtual void ClearStackFrames()
Definition Thread.cpp:1753
virtual Unwind & GetUnwinder()
Definition Thread.cpp:2256
Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id=false)
Constructor.
Definition Thread.cpp:226
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:403
lldb::ProcessSP GetProcess() const
Definition Thread.h:162
friend class StackFrame
Definition Thread.h:1371
lldb::StackFrameListSP GetStackFrameList()
Definition Thread.cpp:1499
lldb::RegisterContextSP m_reg_context_sp
The register context for this thread's current register state.
Definition Thread.h:1436
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.
std::string toString(FormatterBytecode::OpCodes op)
std::shared_ptr< lldb_private::DynamicRegisterInfo > DynamicRegisterInfoSP
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:88
std::shared_ptr< lldb_private::Process > ProcessSP
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:85
std::shared_ptr< lldb_private::StackFrameList > StackFrameListSP
lldb::user_id_t GetID() const
Get accessor for the user ID.
Definition UserID.h:47