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