xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
1*349cc55cSDimitry Andric //===-- ScriptedThread.cpp ------------------------------------------------===//
2*349cc55cSDimitry Andric //
3*349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*349cc55cSDimitry Andric //
7*349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8*349cc55cSDimitry Andric 
9*349cc55cSDimitry Andric #include "ScriptedThread.h"
10*349cc55cSDimitry Andric 
11*349cc55cSDimitry Andric #include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
12*349cc55cSDimitry Andric #include "lldb/Target/OperatingSystem.h"
13*349cc55cSDimitry Andric #include "lldb/Target/Process.h"
14*349cc55cSDimitry Andric #include "lldb/Target/RegisterContext.h"
15*349cc55cSDimitry Andric #include "lldb/Target/StopInfo.h"
16*349cc55cSDimitry Andric #include "lldb/Target/Unwind.h"
17*349cc55cSDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
18*349cc55cSDimitry Andric #include "lldb/Utility/Log.h"
19*349cc55cSDimitry Andric #include "lldb/Utility/Logging.h"
20*349cc55cSDimitry Andric 
21*349cc55cSDimitry Andric #include <memory>
22*349cc55cSDimitry Andric 
23*349cc55cSDimitry Andric using namespace lldb;
24*349cc55cSDimitry Andric using namespace lldb_private;
25*349cc55cSDimitry Andric 
26*349cc55cSDimitry Andric void ScriptedThread::CheckInterpreterAndScriptObject() const {
27*349cc55cSDimitry Andric   lldbassert(m_script_object_sp && "Invalid Script Object.");
28*349cc55cSDimitry Andric   lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");
29*349cc55cSDimitry Andric }
30*349cc55cSDimitry Andric 
31*349cc55cSDimitry Andric ScriptedThread::ScriptedThread(ScriptedProcess &process, Status &error)
32*349cc55cSDimitry Andric     : Thread(process, LLDB_INVALID_THREAD_ID), m_scripted_process(process) {
33*349cc55cSDimitry Andric   if (!process.IsValid()) {
34*349cc55cSDimitry Andric     error.SetErrorString("Invalid scripted process");
35*349cc55cSDimitry Andric     return;
36*349cc55cSDimitry Andric   }
37*349cc55cSDimitry Andric 
38*349cc55cSDimitry Andric   process.CheckInterpreterAndScriptObject();
39*349cc55cSDimitry Andric 
40*349cc55cSDimitry Andric   auto scripted_thread_interface = GetInterface();
41*349cc55cSDimitry Andric   if (!scripted_thread_interface) {
42*349cc55cSDimitry Andric     error.SetErrorString("Failed to get scripted thread interface.");
43*349cc55cSDimitry Andric     return;
44*349cc55cSDimitry Andric   }
45*349cc55cSDimitry Andric 
46*349cc55cSDimitry Andric   llvm::Optional<std::string> class_name =
47*349cc55cSDimitry Andric       process.GetInterface().GetScriptedThreadPluginName();
48*349cc55cSDimitry Andric   if (!class_name || class_name->empty()) {
49*349cc55cSDimitry Andric     error.SetErrorString("Failed to get scripted thread class name.");
50*349cc55cSDimitry Andric     return;
51*349cc55cSDimitry Andric   }
52*349cc55cSDimitry Andric 
53*349cc55cSDimitry Andric   ExecutionContext exe_ctx(process);
54*349cc55cSDimitry Andric 
55*349cc55cSDimitry Andric   StructuredData::GenericSP object_sp =
56*349cc55cSDimitry Andric       scripted_thread_interface->CreatePluginObject(
57*349cc55cSDimitry Andric           class_name->c_str(), exe_ctx,
58*349cc55cSDimitry Andric           process.m_scripted_process_info.GetArgsSP());
59*349cc55cSDimitry Andric   if (!object_sp || !object_sp->IsValid()) {
60*349cc55cSDimitry Andric     error.SetErrorString("Failed to create valid script object");
61*349cc55cSDimitry Andric     return;
62*349cc55cSDimitry Andric   }
63*349cc55cSDimitry Andric 
64*349cc55cSDimitry Andric   m_script_object_sp = object_sp;
65*349cc55cSDimitry Andric 
66*349cc55cSDimitry Andric   SetID(scripted_thread_interface->GetThreadID());
67*349cc55cSDimitry Andric }
68*349cc55cSDimitry Andric 
69*349cc55cSDimitry Andric ScriptedThread::~ScriptedThread() { DestroyThread(); }
70*349cc55cSDimitry Andric 
71*349cc55cSDimitry Andric const char *ScriptedThread::GetName() {
72*349cc55cSDimitry Andric   CheckInterpreterAndScriptObject();
73*349cc55cSDimitry Andric   llvm::Optional<std::string> thread_name = GetInterface()->GetName();
74*349cc55cSDimitry Andric   if (!thread_name)
75*349cc55cSDimitry Andric     return nullptr;
76*349cc55cSDimitry Andric   return ConstString(thread_name->c_str()).AsCString();
77*349cc55cSDimitry Andric }
78*349cc55cSDimitry Andric 
79*349cc55cSDimitry Andric const char *ScriptedThread::GetQueueName() {
80*349cc55cSDimitry Andric   CheckInterpreterAndScriptObject();
81*349cc55cSDimitry Andric   llvm::Optional<std::string> queue_name = GetInterface()->GetQueue();
82*349cc55cSDimitry Andric   if (!queue_name)
83*349cc55cSDimitry Andric     return nullptr;
84*349cc55cSDimitry Andric   return ConstString(queue_name->c_str()).AsCString();
85*349cc55cSDimitry Andric }
86*349cc55cSDimitry Andric 
87*349cc55cSDimitry Andric void ScriptedThread::WillResume(StateType resume_state) {}
88*349cc55cSDimitry Andric 
89*349cc55cSDimitry Andric void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); }
90*349cc55cSDimitry Andric 
91*349cc55cSDimitry Andric RegisterContextSP ScriptedThread::GetRegisterContext() {
92*349cc55cSDimitry Andric   if (!m_reg_context_sp)
93*349cc55cSDimitry Andric     m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
94*349cc55cSDimitry Andric   return m_reg_context_sp;
95*349cc55cSDimitry Andric }
96*349cc55cSDimitry Andric 
97*349cc55cSDimitry Andric RegisterContextSP
98*349cc55cSDimitry Andric ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) {
99*349cc55cSDimitry Andric   const uint32_t concrete_frame_idx =
100*349cc55cSDimitry Andric       frame ? frame->GetConcreteFrameIndex() : 0;
101*349cc55cSDimitry Andric 
102*349cc55cSDimitry Andric   if (concrete_frame_idx)
103*349cc55cSDimitry Andric     return GetUnwinder().CreateRegisterContextForFrame(frame);
104*349cc55cSDimitry Andric 
105*349cc55cSDimitry Andric   lldb::RegisterContextSP reg_ctx_sp;
106*349cc55cSDimitry Andric   Status error;
107*349cc55cSDimitry Andric 
108*349cc55cSDimitry Andric   llvm::Optional<std::string> reg_data = GetInterface()->GetRegisterContext();
109*349cc55cSDimitry Andric   if (!reg_data)
110*349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>(
111*349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.",
112*349cc55cSDimitry Andric         error, LIBLLDB_LOG_THREAD);
113*349cc55cSDimitry Andric 
114*349cc55cSDimitry Andric   DataBufferSP data_sp(
115*349cc55cSDimitry Andric       std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
116*349cc55cSDimitry Andric 
117*349cc55cSDimitry Andric   if (!data_sp->GetByteSize())
118*349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>(
119*349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error,
120*349cc55cSDimitry Andric         LIBLLDB_LOG_THREAD);
121*349cc55cSDimitry Andric 
122*349cc55cSDimitry Andric   std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
123*349cc55cSDimitry Andric       std::make_shared<RegisterContextMemory>(
124*349cc55cSDimitry Andric           *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);
125*349cc55cSDimitry Andric   if (!reg_ctx_memory)
126*349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>(
127*349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error,
128*349cc55cSDimitry Andric         LIBLLDB_LOG_THREAD);
129*349cc55cSDimitry Andric 
130*349cc55cSDimitry Andric   reg_ctx_memory->SetAllRegisterData(data_sp);
131*349cc55cSDimitry Andric   m_reg_context_sp = reg_ctx_memory;
132*349cc55cSDimitry Andric 
133*349cc55cSDimitry Andric   return m_reg_context_sp;
134*349cc55cSDimitry Andric }
135*349cc55cSDimitry Andric 
136*349cc55cSDimitry Andric bool ScriptedThread::CalculateStopInfo() {
137*349cc55cSDimitry Andric   StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();
138*349cc55cSDimitry Andric 
139*349cc55cSDimitry Andric   Status error;
140*349cc55cSDimitry Andric   lldb::StopInfoSP stop_info_sp;
141*349cc55cSDimitry Andric   lldb::StopReason stop_reason_type;
142*349cc55cSDimitry Andric 
143*349cc55cSDimitry Andric   if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type))
144*349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<bool>(
145*349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION,
146*349cc55cSDimitry Andric         "Couldn't find value for key 'type' in stop reason dictionary.", error,
147*349cc55cSDimitry Andric         LIBLLDB_LOG_THREAD);
148*349cc55cSDimitry Andric 
149*349cc55cSDimitry Andric   StructuredData::Dictionary *data_dict;
150*349cc55cSDimitry Andric   if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict))
151*349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<bool>(
152*349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION,
153*349cc55cSDimitry Andric         "Couldn't find value for key 'type' in stop reason dictionary.", error,
154*349cc55cSDimitry Andric         LIBLLDB_LOG_THREAD);
155*349cc55cSDimitry Andric 
156*349cc55cSDimitry Andric   switch (stop_reason_type) {
157*349cc55cSDimitry Andric   case lldb::eStopReasonNone:
158*349cc55cSDimitry Andric     break;
159*349cc55cSDimitry Andric   case lldb::eStopReasonBreakpoint: {
160*349cc55cSDimitry Andric     lldb::break_id_t break_id;
161*349cc55cSDimitry Andric     data_dict->GetValueForKeyAsInteger("break_id", break_id,
162*349cc55cSDimitry Andric                                        LLDB_INVALID_BREAK_ID);
163*349cc55cSDimitry Andric     stop_info_sp =
164*349cc55cSDimitry Andric         StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id);
165*349cc55cSDimitry Andric   } break;
166*349cc55cSDimitry Andric   case lldb::eStopReasonSignal: {
167*349cc55cSDimitry Andric     int signal;
168*349cc55cSDimitry Andric     llvm::StringRef description;
169*349cc55cSDimitry Andric     data_dict->GetValueForKeyAsInteger("signal", signal,
170*349cc55cSDimitry Andric                                        LLDB_INVALID_SIGNAL_NUMBER);
171*349cc55cSDimitry Andric     data_dict->GetValueForKeyAsString("desc", description);
172*349cc55cSDimitry Andric     stop_info_sp =
173*349cc55cSDimitry Andric         StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());
174*349cc55cSDimitry Andric   } break;
175*349cc55cSDimitry Andric   default:
176*349cc55cSDimitry Andric     return GetInterface()->ErrorWithMessage<bool>(
177*349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION,
178*349cc55cSDimitry Andric         llvm::Twine("Unsupported stop reason type (" +
179*349cc55cSDimitry Andric                     llvm::Twine(stop_reason_type) + llvm::Twine(")."))
180*349cc55cSDimitry Andric             .str(),
181*349cc55cSDimitry Andric         error, LIBLLDB_LOG_THREAD);
182*349cc55cSDimitry Andric   }
183*349cc55cSDimitry Andric 
184*349cc55cSDimitry Andric   SetStopInfo(stop_info_sp);
185*349cc55cSDimitry Andric   return true;
186*349cc55cSDimitry Andric }
187*349cc55cSDimitry Andric 
188*349cc55cSDimitry Andric void ScriptedThread::RefreshStateAfterStop() {
189*349cc55cSDimitry Andric   GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
190*349cc55cSDimitry Andric }
191*349cc55cSDimitry Andric 
192*349cc55cSDimitry Andric lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {
193*349cc55cSDimitry Andric   return m_scripted_process.GetInterface().GetScriptedThreadInterface();
194*349cc55cSDimitry Andric }
195*349cc55cSDimitry Andric 
196*349cc55cSDimitry Andric std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {
197*349cc55cSDimitry Andric   CheckInterpreterAndScriptObject();
198*349cc55cSDimitry Andric 
199*349cc55cSDimitry Andric   if (!m_register_info_sp) {
200*349cc55cSDimitry Andric     StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
201*349cc55cSDimitry Andric     if (!reg_info)
202*349cc55cSDimitry Andric       return nullptr;
203*349cc55cSDimitry Andric 
204*349cc55cSDimitry Andric     m_register_info_sp = std::make_shared<DynamicRegisterInfo>(
205*349cc55cSDimitry Andric         *reg_info, m_scripted_process.GetTarget().GetArchitecture());
206*349cc55cSDimitry Andric     assert(m_register_info_sp->GetNumRegisters() > 0);
207*349cc55cSDimitry Andric     assert(m_register_info_sp->GetNumRegisterSets() > 0);
208*349cc55cSDimitry Andric   }
209*349cc55cSDimitry Andric 
210*349cc55cSDimitry Andric   return m_register_info_sp;
211*349cc55cSDimitry Andric }
212