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