Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / source / Plugins / Process / scripted / ScriptedThread.cpp
blobaa2796db15cd00ad7b832c5958ee5baa5ef402a0
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 //===----------------------------------------------------------------------===//
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"
20 #include <memory>
21 #include <optional>
23 using namespace lldb;
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;
48 if (!script_object) {
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(),
61 script_object);
63 if (!obj_or_err) {
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,
83 lldb::tid_t tid,
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();
94 if (!thread_name)
95 return nullptr;
96 return ConstString(thread_name->c_str()).AsCString();
99 const char *ScriptedThread::GetQueueName() {
100 CheckInterpreterAndScriptObject();
101 std::optional<std::string> queue_name = GetInterface()->GetQueue();
102 if (!queue_name)
103 return nullptr;
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;
117 RegisterContextSP
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;
126 Status error;
128 std::optional<std::string> reg_data = GetInterface()->GetRegisterContext();
129 if (!reg_data)
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,
140 LLDBLog::Thread);
142 std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
143 std::make_shared<RegisterContextMemory>(
144 *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);
145 if (!reg_ctx_memory)
146 return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(
147 LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error,
148 LLDBLog::Thread);
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();
159 Status error;
160 if (!arr_sp)
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,
169 llvm::Twine(
170 "StackFrame array size (" + llvm::Twine(arr_size) +
171 llvm::Twine(
172 ") is greater than maximum authorized for a StackFrameList."))
173 .str(),
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,
183 llvm::Twine(
184 "Couldn't get artificial stackframe dictionary at index (" +
185 llvm::Twine(idx) + llvm::Twine(") from stackframe array."))
186 .str(),
187 error, LLDBLog::Thread);
189 lldb::addr_t pc;
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,
194 LLDBLog::Thread);
196 Address symbol_addr;
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;
202 SymbolContext sc;
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."))
214 .str(),
215 error, LLDBLog::Thread);
218 return true;
221 bool ScriptedThread::CalculateStopInfo() {
222 StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();
224 Status error;
225 if (!dict_sp)
226 return ScriptedInterface::ErrorWithMessage<bool>(
227 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error,
228 LLDBLog::Thread);
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,
237 LLDBLog::Thread);
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,
244 LLDBLog::Thread);
246 switch (stop_reason_type) {
247 case lldb::eStopReasonNone:
248 return true;
249 case lldb::eStopReasonBreakpoint: {
250 lldb::break_id_t break_id;
251 data_dict->GetValueForKeyAsInteger("break_id", break_id,
252 LLDB_INVALID_BREAK_ID);
253 stop_info_sp =
254 StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id);
255 } break;
256 case lldb::eStopReasonSignal: {
257 uint32_t signal;
258 llvm::StringRef description;
259 if (!data_dict->GetValueForKeyAsInteger("signal", signal)) {
260 signal = LLDB_INVALID_SIGNAL_NUMBER;
261 return false;
263 data_dict->GetValueForKeyAsString("desc", description);
264 stop_info_sp =
265 StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());
266 } break;
267 case lldb::eStopReasonTrace: {
268 stop_info_sp = StopInfo::CreateStopReasonToTrace(*this);
269 } break;
270 case lldb::eStopReasonException: {
271 #if defined(__APPLE__)
272 StructuredData::Dictionary *mach_exception;
273 if (data_dict->GetValueForKeyAsDictionary("mach_exception",
274 mach_exception)) {
275 llvm::StringRef value;
276 mach_exception->GetValueForKeyAsString("type", value);
277 auto exc_type =
278 StopInfoMachException::MachException::ExceptionCode(value.data());
280 if (!exc_type)
281 return false;
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);
288 if (exc_rawcodes) {
289 auto fetch_data = [&raw_codes](StructuredData::Object *obj) {
290 if (!obj)
291 return false;
292 raw_codes.push_back(obj->GetUnsignedIntegerValue());
293 return true;
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);
306 break;
308 #endif
309 stop_info_sp =
310 StopInfo::CreateStopReasonWithException(*this, "EXC_BAD_ACCESS");
311 } break;
312 default:
313 return ScriptedInterface::ErrorWithMessage<bool>(
314 LLVM_PRETTY_FUNCTION,
315 llvm::Twine("Unsupported stop reason type (" +
316 llvm::Twine(stop_reason_type) + llvm::Twine(")."))
317 .str(),
318 error, LLDBLog::Thread);
321 if (!stop_info_sp)
322 return false;
324 SetStopInfo(stop_info_sp);
325 return true;
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();
343 Status error;
344 if (!reg_info)
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();
360 Status error;
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;