159d8dd79SMed Ismail Bennani //===-- ScriptedThread.cpp ------------------------------------------------===//
259d8dd79SMed Ismail Bennani //
359d8dd79SMed Ismail Bennani // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
459d8dd79SMed Ismail Bennani // See https://llvm.org/LICENSE.txt for license information.
559d8dd79SMed Ismail Bennani // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
659d8dd79SMed Ismail Bennani //
759d8dd79SMed Ismail Bennani //===----------------------------------------------------------------------===//
859d8dd79SMed Ismail Bennani 
959d8dd79SMed Ismail Bennani #include "ScriptedThread.h"
1059d8dd79SMed Ismail Bennani 
1159d8dd79SMed Ismail Bennani #include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
1259d8dd79SMed Ismail Bennani #include "lldb/Target/OperatingSystem.h"
1359d8dd79SMed Ismail Bennani #include "lldb/Target/Process.h"
1459d8dd79SMed Ismail Bennani #include "lldb/Target/RegisterContext.h"
1559d8dd79SMed Ismail Bennani #include "lldb/Target/StopInfo.h"
1659d8dd79SMed Ismail Bennani #include "lldb/Target/Unwind.h"
1759d8dd79SMed Ismail Bennani #include "lldb/Utility/DataBufferHeap.h"
1859d8dd79SMed Ismail Bennani #include "lldb/Utility/Log.h"
1959d8dd79SMed Ismail Bennani #include "lldb/Utility/Logging.h"
2059d8dd79SMed Ismail Bennani 
2159d8dd79SMed Ismail Bennani #include <memory>
2259d8dd79SMed Ismail Bennani 
2359d8dd79SMed Ismail Bennani using namespace lldb;
2459d8dd79SMed Ismail Bennani using namespace lldb_private;
2559d8dd79SMed Ismail Bennani 
2659d8dd79SMed Ismail Bennani void ScriptedThread::CheckInterpreterAndScriptObject() const {
2759d8dd79SMed Ismail Bennani   lldbassert(m_script_object_sp && "Invalid Script Object.");
2859d8dd79SMed Ismail Bennani   lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");
2959d8dd79SMed Ismail Bennani }
3059d8dd79SMed Ismail Bennani 
31*45148bfeSMed Ismail Bennani llvm::Expected<std::shared_ptr<ScriptedThread>>
32*45148bfeSMed Ismail Bennani ScriptedThread::Create(ScriptedProcess &process,
33*45148bfeSMed Ismail Bennani                        StructuredData::Generic *script_object) {
34*45148bfeSMed Ismail Bennani   if (!process.IsValid())
35*45148bfeSMed Ismail Bennani     return llvm::createStringError(llvm::inconvertibleErrorCode(),
36*45148bfeSMed Ismail Bennani                                    "Invalid scripted process.");
3759d8dd79SMed Ismail Bennani 
3859d8dd79SMed Ismail Bennani   process.CheckInterpreterAndScriptObject();
3959d8dd79SMed Ismail Bennani 
40*45148bfeSMed Ismail Bennani   auto scripted_thread_interface =
41*45148bfeSMed Ismail Bennani       process.GetInterface().CreateScriptedThreadInterface();
42*45148bfeSMed Ismail Bennani   if (!scripted_thread_interface)
43*45148bfeSMed Ismail Bennani     return llvm::createStringError(
44*45148bfeSMed Ismail Bennani         llvm::inconvertibleErrorCode(),
45*45148bfeSMed Ismail Bennani         "Failed to create scripted thread interface.");
4659d8dd79SMed Ismail Bennani 
47*45148bfeSMed Ismail Bennani   llvm::StringRef thread_class_name;
48*45148bfeSMed Ismail Bennani   if (!script_object) {
4959d8dd79SMed Ismail Bennani     llvm::Optional<std::string> class_name =
5059d8dd79SMed Ismail Bennani         process.GetInterface().GetScriptedThreadPluginName();
51*45148bfeSMed Ismail Bennani     if (!class_name || class_name->empty())
52*45148bfeSMed Ismail Bennani       return llvm::createStringError(
53*45148bfeSMed Ismail Bennani           llvm::inconvertibleErrorCode(),
54*45148bfeSMed Ismail Bennani           "Failed to get scripted thread class name.");
55*45148bfeSMed Ismail Bennani     thread_class_name = *class_name;
5659d8dd79SMed Ismail Bennani   }
5759d8dd79SMed Ismail Bennani 
5859d8dd79SMed Ismail Bennani   ExecutionContext exe_ctx(process);
59*45148bfeSMed Ismail Bennani   StructuredData::GenericSP owned_script_object_sp =
60*45148bfeSMed Ismail Bennani       scripted_thread_interface->CreatePluginObject(
61*45148bfeSMed Ismail Bennani           thread_class_name, exe_ctx,
62*45148bfeSMed Ismail Bennani           process.m_scripted_process_info.GetArgsSP(), script_object);
6359d8dd79SMed Ismail Bennani 
64*45148bfeSMed Ismail Bennani   if (!owned_script_object_sp)
65*45148bfeSMed Ismail Bennani     return llvm::createStringError(llvm::inconvertibleErrorCode(),
66*45148bfeSMed Ismail Bennani                                    "Failed to create script object.");
67*45148bfeSMed Ismail Bennani   if (!owned_script_object_sp->IsValid())
68*45148bfeSMed Ismail Bennani     return llvm::createStringError(llvm::inconvertibleErrorCode(),
69*45148bfeSMed Ismail Bennani                                    "Created script object is invalid.");
7059d8dd79SMed Ismail Bennani 
71d3e0f7e1SMed Ismail Bennani   lldb::tid_t tid = scripted_thread_interface->GetThreadID();
72*45148bfeSMed Ismail Bennani 
73*45148bfeSMed Ismail Bennani   return std::make_shared<ScriptedThread>(process, scripted_thread_interface,
74*45148bfeSMed Ismail Bennani                                           tid, owned_script_object_sp);
7559d8dd79SMed Ismail Bennani }
7659d8dd79SMed Ismail Bennani 
77*45148bfeSMed Ismail Bennani ScriptedThread::ScriptedThread(ScriptedProcess &process,
78*45148bfeSMed Ismail Bennani                                ScriptedThreadInterfaceSP interface_sp,
79*45148bfeSMed Ismail Bennani                                lldb::tid_t tid,
80*45148bfeSMed Ismail Bennani                                StructuredData::GenericSP script_object_sp)
81*45148bfeSMed Ismail Bennani     : Thread(process, tid), m_scripted_process(process),
82*45148bfeSMed Ismail Bennani       m_scripted_thread_interface_sp(interface_sp),
83*45148bfeSMed Ismail Bennani       m_script_object_sp(script_object_sp) {}
84*45148bfeSMed Ismail Bennani 
8559d8dd79SMed Ismail Bennani ScriptedThread::~ScriptedThread() { DestroyThread(); }
8659d8dd79SMed Ismail Bennani 
8759d8dd79SMed Ismail Bennani const char *ScriptedThread::GetName() {
8859d8dd79SMed Ismail Bennani   CheckInterpreterAndScriptObject();
8959d8dd79SMed Ismail Bennani   llvm::Optional<std::string> thread_name = GetInterface()->GetName();
9059d8dd79SMed Ismail Bennani   if (!thread_name)
9159d8dd79SMed Ismail Bennani     return nullptr;
9259d8dd79SMed Ismail Bennani   return ConstString(thread_name->c_str()).AsCString();
9359d8dd79SMed Ismail Bennani }
9459d8dd79SMed Ismail Bennani 
9559d8dd79SMed Ismail Bennani const char *ScriptedThread::GetQueueName() {
9659d8dd79SMed Ismail Bennani   CheckInterpreterAndScriptObject();
9759d8dd79SMed Ismail Bennani   llvm::Optional<std::string> queue_name = GetInterface()->GetQueue();
9859d8dd79SMed Ismail Bennani   if (!queue_name)
9959d8dd79SMed Ismail Bennani     return nullptr;
10059d8dd79SMed Ismail Bennani   return ConstString(queue_name->c_str()).AsCString();
10159d8dd79SMed Ismail Bennani }
10259d8dd79SMed Ismail Bennani 
10359d8dd79SMed Ismail Bennani void ScriptedThread::WillResume(StateType resume_state) {}
10459d8dd79SMed Ismail Bennani 
10559d8dd79SMed Ismail Bennani void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); }
10659d8dd79SMed Ismail Bennani 
10759d8dd79SMed Ismail Bennani RegisterContextSP ScriptedThread::GetRegisterContext() {
108676576b6SMed Ismail Bennani   if (!m_reg_context_sp)
109676576b6SMed Ismail Bennani     m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
11059d8dd79SMed Ismail Bennani   return m_reg_context_sp;
11159d8dd79SMed Ismail Bennani }
11259d8dd79SMed Ismail Bennani 
11359d8dd79SMed Ismail Bennani RegisterContextSP
11459d8dd79SMed Ismail Bennani ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) {
115676576b6SMed Ismail Bennani   const uint32_t concrete_frame_idx =
116676576b6SMed Ismail Bennani       frame ? frame->GetConcreteFrameIndex() : 0;
11759d8dd79SMed Ismail Bennani 
118676576b6SMed Ismail Bennani   if (concrete_frame_idx)
11959d8dd79SMed Ismail Bennani     return GetUnwinder().CreateRegisterContextForFrame(frame);
120676576b6SMed Ismail Bennani 
121676576b6SMed Ismail Bennani   lldb::RegisterContextSP reg_ctx_sp;
122676576b6SMed Ismail Bennani   Status error;
123676576b6SMed Ismail Bennani 
124676576b6SMed Ismail Bennani   llvm::Optional<std::string> reg_data = GetInterface()->GetRegisterContext();
125676576b6SMed Ismail Bennani   if (!reg_data)
126676576b6SMed Ismail Bennani     return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>(
127676576b6SMed Ismail Bennani         LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.",
128676576b6SMed Ismail Bennani         error, LIBLLDB_LOG_THREAD);
129676576b6SMed Ismail Bennani 
130676576b6SMed Ismail Bennani   DataBufferSP data_sp(
131676576b6SMed Ismail Bennani       std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
132676576b6SMed Ismail Bennani 
133676576b6SMed Ismail Bennani   if (!data_sp->GetByteSize())
134676576b6SMed Ismail Bennani     return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>(
135676576b6SMed Ismail Bennani         LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error,
136676576b6SMed Ismail Bennani         LIBLLDB_LOG_THREAD);
137676576b6SMed Ismail Bennani 
138676576b6SMed Ismail Bennani   std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
139676576b6SMed Ismail Bennani       std::make_shared<RegisterContextMemory>(
140676576b6SMed Ismail Bennani           *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);
141676576b6SMed Ismail Bennani   if (!reg_ctx_memory)
142676576b6SMed Ismail Bennani     return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>(
143676576b6SMed Ismail Bennani         LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error,
144676576b6SMed Ismail Bennani         LIBLLDB_LOG_THREAD);
145676576b6SMed Ismail Bennani 
146676576b6SMed Ismail Bennani   reg_ctx_memory->SetAllRegisterData(data_sp);
147676576b6SMed Ismail Bennani   m_reg_context_sp = reg_ctx_memory;
148676576b6SMed Ismail Bennani 
149676576b6SMed Ismail Bennani   return m_reg_context_sp;
15059d8dd79SMed Ismail Bennani }
15159d8dd79SMed Ismail Bennani 
15259d8dd79SMed Ismail Bennani bool ScriptedThread::CalculateStopInfo() {
15359d8dd79SMed Ismail Bennani   StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();
15459d8dd79SMed Ismail Bennani 
15559d8dd79SMed Ismail Bennani   Status error;
156cfa55bfeSMed Ismail Bennani   if (!dict_sp)
157cfa55bfeSMed Ismail Bennani     return GetInterface()->ErrorWithMessage<bool>(
158cfa55bfeSMed Ismail Bennani         LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error,
159cfa55bfeSMed Ismail Bennani         LIBLLDB_LOG_THREAD);
160cfa55bfeSMed Ismail Bennani 
16159d8dd79SMed Ismail Bennani   lldb::StopInfoSP stop_info_sp;
16259d8dd79SMed Ismail Bennani   lldb::StopReason stop_reason_type;
16359d8dd79SMed Ismail Bennani 
16459d8dd79SMed Ismail Bennani   if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type))
16559d8dd79SMed Ismail Bennani     return GetInterface()->ErrorWithMessage<bool>(
16688a941baSMed Ismail Bennani         LLVM_PRETTY_FUNCTION,
167676576b6SMed Ismail Bennani         "Couldn't find value for key 'type' in stop reason dictionary.", error,
168676576b6SMed Ismail Bennani         LIBLLDB_LOG_THREAD);
16959d8dd79SMed Ismail Bennani 
17059d8dd79SMed Ismail Bennani   StructuredData::Dictionary *data_dict;
17159d8dd79SMed Ismail Bennani   if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict))
17259d8dd79SMed Ismail Bennani     return GetInterface()->ErrorWithMessage<bool>(
17388a941baSMed Ismail Bennani         LLVM_PRETTY_FUNCTION,
174cfa55bfeSMed Ismail Bennani         "Couldn't find value for key 'data' in stop reason dictionary.", error,
175676576b6SMed Ismail Bennani         LIBLLDB_LOG_THREAD);
17659d8dd79SMed Ismail Bennani 
17759d8dd79SMed Ismail Bennani   switch (stop_reason_type) {
17859d8dd79SMed Ismail Bennani   case lldb::eStopReasonNone:
179cfa55bfeSMed Ismail Bennani     return true;
18059d8dd79SMed Ismail Bennani   case lldb::eStopReasonBreakpoint: {
18159d8dd79SMed Ismail Bennani     lldb::break_id_t break_id;
18259d8dd79SMed Ismail Bennani     data_dict->GetValueForKeyAsInteger("break_id", break_id,
18359d8dd79SMed Ismail Bennani                                        LLDB_INVALID_BREAK_ID);
18459d8dd79SMed Ismail Bennani     stop_info_sp =
18559d8dd79SMed Ismail Bennani         StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id);
18659d8dd79SMed Ismail Bennani   } break;
18759d8dd79SMed Ismail Bennani   case lldb::eStopReasonSignal: {
18859d8dd79SMed Ismail Bennani     int signal;
18959d8dd79SMed Ismail Bennani     llvm::StringRef description;
19059d8dd79SMed Ismail Bennani     data_dict->GetValueForKeyAsInteger("signal", signal,
19159d8dd79SMed Ismail Bennani                                        LLDB_INVALID_SIGNAL_NUMBER);
19259d8dd79SMed Ismail Bennani     data_dict->GetValueForKeyAsString("desc", description);
19359d8dd79SMed Ismail Bennani     stop_info_sp =
19459d8dd79SMed Ismail Bennani         StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());
19559d8dd79SMed Ismail Bennani   } break;
196cfa55bfeSMed Ismail Bennani   case lldb::eStopReasonException: {
197cfa55bfeSMed Ismail Bennani     llvm::StringRef description;
198cfa55bfeSMed Ismail Bennani     data_dict->GetValueForKeyAsString("desc", description);
199cfa55bfeSMed Ismail Bennani 
200cfa55bfeSMed Ismail Bennani     stop_info_sp =
201cfa55bfeSMed Ismail Bennani         StopInfo::CreateStopReasonWithException(*this, description.data());
202cfa55bfeSMed Ismail Bennani   } break;
20359d8dd79SMed Ismail Bennani   default:
20459d8dd79SMed Ismail Bennani     return GetInterface()->ErrorWithMessage<bool>(
20588a941baSMed Ismail Bennani         LLVM_PRETTY_FUNCTION,
20659d8dd79SMed Ismail Bennani         llvm::Twine("Unsupported stop reason type (" +
20759d8dd79SMed Ismail Bennani                     llvm::Twine(stop_reason_type) + llvm::Twine(")."))
20859d8dd79SMed Ismail Bennani             .str(),
209676576b6SMed Ismail Bennani         error, LIBLLDB_LOG_THREAD);
21059d8dd79SMed Ismail Bennani   }
21159d8dd79SMed Ismail Bennani 
212cfa55bfeSMed Ismail Bennani   if (!stop_info_sp)
213cfa55bfeSMed Ismail Bennani     return false;
214cfa55bfeSMed Ismail Bennani 
21559d8dd79SMed Ismail Bennani   SetStopInfo(stop_info_sp);
21659d8dd79SMed Ismail Bennani   return true;
21759d8dd79SMed Ismail Bennani }
21859d8dd79SMed Ismail Bennani 
21959d8dd79SMed Ismail Bennani void ScriptedThread::RefreshStateAfterStop() {
220676576b6SMed Ismail Bennani   GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
22159d8dd79SMed Ismail Bennani }
22259d8dd79SMed Ismail Bennani 
22359d8dd79SMed Ismail Bennani lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {
2241b86344fSMed Ismail Bennani   return m_scripted_thread_interface_sp;
22559d8dd79SMed Ismail Bennani }
22659d8dd79SMed Ismail Bennani 
22759d8dd79SMed Ismail Bennani std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {
22859d8dd79SMed Ismail Bennani   CheckInterpreterAndScriptObject();
22959d8dd79SMed Ismail Bennani 
23059d8dd79SMed Ismail Bennani   if (!m_register_info_sp) {
23159d8dd79SMed Ismail Bennani     StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
232caea440aSMed Ismail Bennani 
233caea440aSMed Ismail Bennani     Status error;
23459d8dd79SMed Ismail Bennani     if (!reg_info)
235caea440aSMed Ismail Bennani       return GetInterface()
236caea440aSMed Ismail Bennani           ->ErrorWithMessage<std::shared_ptr<DynamicRegisterInfo>>(
237caea440aSMed Ismail Bennani               LLVM_PRETTY_FUNCTION,
238caea440aSMed Ismail Bennani               "Failed to get scripted thread registers info.", error,
239caea440aSMed Ismail Bennani               LIBLLDB_LOG_THREAD);
24059d8dd79SMed Ismail Bennani 
24159d8dd79SMed Ismail Bennani     m_register_info_sp = std::make_shared<DynamicRegisterInfo>(
24259d8dd79SMed Ismail Bennani         *reg_info, m_scripted_process.GetTarget().GetArchitecture());
24359d8dd79SMed Ismail Bennani   }
24459d8dd79SMed Ismail Bennani 
24559d8dd79SMed Ismail Bennani   return m_register_info_sp;
24659d8dd79SMed Ismail Bennani }
247