xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
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>
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 
CheckInterpreterAndScriptObject() const26 void ScriptedThread::CheckInterpreterAndScriptObject() const {
27   lldbassert(m_script_object_sp && "Invalid Script Object.");
28   lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");
29 }
30 
31 llvm::Expected<std::shared_ptr<ScriptedThread>>
Create(ScriptedProcess & process,StructuredData::Generic * script_object)32 ScriptedThread::Create(ScriptedProcess &process,
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 =
41       process.GetInterface().CreateScriptedThreadInterface();
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 =
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;
56   }
57 
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);
62 
63   if (!obj_or_err) {
64     llvm::consumeError(obj_or_err.takeError());
65     return llvm::createStringError(llvm::inconvertibleErrorCode(),
66                                    "Failed to create script object.");
67   }
68 
69   StructuredData::GenericSP owned_script_object_sp = *obj_or_err;
70 
71   if (!owned_script_object_sp->IsValid())
72     return llvm::createStringError(llvm::inconvertibleErrorCode(),
73                                    "Created script object is invalid.");
74 
75   lldb::tid_t tid = scripted_thread_interface->GetThreadID();
76 
77   return std::make_shared<ScriptedThread>(process, scripted_thread_interface,
78                                           tid, owned_script_object_sp);
79 }
80 
ScriptedThread(ScriptedProcess & process,ScriptedThreadInterfaceSP interface_sp,lldb::tid_t tid,StructuredData::GenericSP 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) {}
88 
~ScriptedThread()89 ScriptedThread::~ScriptedThread() { DestroyThread(); }
90 
GetName()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();
97 }
98 
GetQueueName()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();
105 }
106 
WillResume(StateType resume_state)107 void ScriptedThread::WillResume(StateType resume_state) {}
108 
ClearStackFrames()109 void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); }
110 
GetRegisterContext()111 RegisterContextSP ScriptedThread::GetRegisterContext() {
112   if (!m_reg_context_sp)
113     m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
114   return m_reg_context_sp;
115 }
116 
117 RegisterContextSP
CreateRegisterContextForFrame(StackFrame * frame)118 ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) {
119   const uint32_t concrete_frame_idx =
120       frame ? frame->GetConcreteFrameIndex() : 0;
121 
122   if (concrete_frame_idx)
123     return GetUnwinder().CreateRegisterContextForFrame(frame);
124 
125   lldb::RegisterContextSP reg_ctx_sp;
126   Status error;
127 
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);
133 
134   DataBufferSP data_sp(
135       std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
136 
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);
141 
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);
149 
150   reg_ctx_memory->SetAllRegisterData(data_sp);
151   m_reg_context_sp = reg_ctx_memory;
152 
153   return m_reg_context_sp;
154 }
155 
LoadArtificialStackFrames()156 bool ScriptedThread::LoadArtificialStackFrames() {
157   StructuredData::ArraySP arr_sp = GetInterface()->GetStackFrames();
158 
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);
164 
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);
175 
176   StackFrameListSP frames = GetStackFrameList();
177 
178   for (size_t idx = 0; idx < arr_size; idx++) {
179     std::optional<StructuredData::Dictionary *> maybe_dict =
180         arr_sp->GetItemAtIndexAsDictionary(idx);
181     if (!maybe_dict)
182       return ScriptedInterface::ErrorWithMessage<bool>(
183           LLVM_PRETTY_FUNCTION,
184           llvm::Twine(
185               "Couldn't get artificial stackframe dictionary at index (" +
186               llvm::Twine(idx) + llvm::Twine(") from stackframe array."))
187               .str(),
188           error, LLDBLog::Thread);
189     StructuredData::Dictionary *dict = *maybe_dict;
190 
191     lldb::addr_t pc;
192     if (!dict->GetValueForKeyAsInteger("pc", pc))
193       return ScriptedInterface::ErrorWithMessage<bool>(
194           LLVM_PRETTY_FUNCTION,
195           "Couldn't find value for key 'pc' in stackframe dictionary.", error,
196           LLDBLog::Thread);
197 
198     Address symbol_addr;
199     symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget());
200 
201     lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
202     bool cfa_is_valid = false;
203     const bool behaves_like_zeroth_frame = false;
204     SymbolContext sc;
205     symbol_addr.CalculateSymbolContext(&sc);
206 
207     StackFrameSP synth_frame_sp = std::make_shared<StackFrame>(
208         this->shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
209         StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc);
210 
211     if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp))
212       return ScriptedInterface::ErrorWithMessage<bool>(
213           LLVM_PRETTY_FUNCTION,
214           llvm::Twine("Couldn't add frame (" + llvm::Twine(idx) +
215                       llvm::Twine(") to ScriptedThread StackFrameList."))
216               .str(),
217           error, LLDBLog::Thread);
218   }
219 
220   return true;
221 }
222 
CalculateStopInfo()223 bool ScriptedThread::CalculateStopInfo() {
224   StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();
225 
226   Status error;
227   if (!dict_sp)
228     return ScriptedInterface::ErrorWithMessage<bool>(
229         LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error,
230         LLDBLog::Thread);
231 
232   // If we're at a BreakpointSite, mark that we stopped there and
233   // need to hit the breakpoint when we resume.  This will be cleared
234   // if we CreateStopReasonWithBreakpointSiteID.
235   if (RegisterContextSP reg_ctx_sp = GetRegisterContext()) {
236     addr_t pc = reg_ctx_sp->GetPC();
237     if (BreakpointSiteSP bp_site_sp =
238             GetProcess()->GetBreakpointSiteList().FindByAddress(pc))
239       if (bp_site_sp->IsEnabled())
240         SetThreadStoppedAtUnexecutedBP(pc);
241   }
242 
243   lldb::StopInfoSP stop_info_sp;
244   lldb::StopReason stop_reason_type;
245 
246   if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type))
247     return ScriptedInterface::ErrorWithMessage<bool>(
248         LLVM_PRETTY_FUNCTION,
249         "Couldn't find value for key 'type' in stop reason dictionary.", error,
250         LLDBLog::Thread);
251 
252   StructuredData::Dictionary *data_dict;
253   if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict))
254     return ScriptedInterface::ErrorWithMessage<bool>(
255         LLVM_PRETTY_FUNCTION,
256         "Couldn't find value for key 'data' in stop reason dictionary.", error,
257         LLDBLog::Thread);
258 
259   switch (stop_reason_type) {
260   case lldb::eStopReasonNone:
261     return true;
262   case lldb::eStopReasonBreakpoint: {
263     lldb::break_id_t break_id;
264     data_dict->GetValueForKeyAsInteger("break_id", break_id,
265                                        LLDB_INVALID_BREAK_ID);
266     stop_info_sp =
267         StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id);
268   } break;
269   case lldb::eStopReasonSignal: {
270     uint32_t signal;
271     llvm::StringRef description;
272     if (!data_dict->GetValueForKeyAsInteger("signal", signal)) {
273         signal = LLDB_INVALID_SIGNAL_NUMBER;
274         return false;
275     }
276     data_dict->GetValueForKeyAsString("desc", description);
277     stop_info_sp =
278         StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());
279   } break;
280   case lldb::eStopReasonTrace: {
281     stop_info_sp = StopInfo::CreateStopReasonToTrace(*this);
282   } break;
283   case lldb::eStopReasonException: {
284 #if defined(__APPLE__)
285     StructuredData::Dictionary *mach_exception;
286     if (data_dict->GetValueForKeyAsDictionary("mach_exception",
287                                               mach_exception)) {
288       llvm::StringRef value;
289       mach_exception->GetValueForKeyAsString("type", value);
290       auto exc_type =
291           StopInfoMachException::MachException::ExceptionCode(value.data());
292 
293       if (!exc_type)
294         return false;
295 
296       uint32_t exc_data_size = 0;
297       llvm::SmallVector<uint64_t, 3> raw_codes;
298 
299       StructuredData::Array *exc_rawcodes;
300       mach_exception->GetValueForKeyAsArray("rawCodes", exc_rawcodes);
301       if (exc_rawcodes) {
302         auto fetch_data = [&raw_codes](StructuredData::Object *obj) {
303           if (!obj)
304             return false;
305           raw_codes.push_back(obj->GetUnsignedIntegerValue());
306           return true;
307         };
308 
309         exc_rawcodes->ForEach(fetch_data);
310         exc_data_size = raw_codes.size();
311       }
312 
313       stop_info_sp = StopInfoMachException::CreateStopReasonWithMachException(
314           *this, *exc_type, exc_data_size,
315           exc_data_size >= 1 ? raw_codes[0] : 0,
316           exc_data_size >= 2 ? raw_codes[1] : 0,
317           exc_data_size >= 3 ? raw_codes[2] : 0);
318 
319       break;
320     }
321 #endif
322     stop_info_sp =
323         StopInfo::CreateStopReasonWithException(*this, "EXC_BAD_ACCESS");
324   } break;
325   default:
326     return ScriptedInterface::ErrorWithMessage<bool>(
327         LLVM_PRETTY_FUNCTION,
328         llvm::Twine("Unsupported stop reason type (" +
329                     llvm::Twine(stop_reason_type) + llvm::Twine(")."))
330             .str(),
331         error, LLDBLog::Thread);
332   }
333 
334   if (!stop_info_sp)
335     return false;
336 
337   SetStopInfo(stop_info_sp);
338   return true;
339 }
340 
RefreshStateAfterStop()341 void ScriptedThread::RefreshStateAfterStop() {
342   GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
343   LoadArtificialStackFrames();
344 }
345 
GetInterface() const346 lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {
347   return m_scripted_thread_interface_sp;
348 }
349 
GetDynamicRegisterInfo()350 std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {
351   CheckInterpreterAndScriptObject();
352 
353   if (!m_register_info_sp) {
354     StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
355 
356     Status error;
357     if (!reg_info)
358       return ScriptedInterface::ErrorWithMessage<
359           std::shared_ptr<DynamicRegisterInfo>>(
360           LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers info.",
361           error, LLDBLog::Thread);
362 
363     m_register_info_sp = DynamicRegisterInfo::Create(
364         *reg_info, m_scripted_process.GetTarget().GetArchitecture());
365   }
366 
367   return m_register_info_sp;
368 }
369 
FetchThreadExtendedInfo()370 StructuredData::ObjectSP ScriptedThread::FetchThreadExtendedInfo() {
371   CheckInterpreterAndScriptObject();
372 
373   Status error;
374   StructuredData::ArraySP extended_info_sp = GetInterface()->GetExtendedInfo();
375 
376   if (!extended_info_sp || !extended_info_sp->GetSize())
377     return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
378         LLVM_PRETTY_FUNCTION, "No extended information found", error);
379 
380   return extended_info_sp;
381 }
382