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 
3159d8dd79SMed Ismail Bennani ScriptedThread::ScriptedThread(ScriptedProcess &process, Status &error)
3259d8dd79SMed Ismail Bennani     : Thread(process, LLDB_INVALID_THREAD_ID), m_scripted_process(process) {
3359d8dd79SMed Ismail Bennani   if (!process.IsValid()) {
3459d8dd79SMed Ismail Bennani     error.SetErrorString("Invalid scripted process");
3559d8dd79SMed Ismail Bennani     return;
3659d8dd79SMed Ismail Bennani   }
3759d8dd79SMed Ismail Bennani 
3859d8dd79SMed Ismail Bennani   process.CheckInterpreterAndScriptObject();
3959d8dd79SMed Ismail Bennani 
4059d8dd79SMed Ismail Bennani   auto scripted_thread_interface = GetInterface();
4159d8dd79SMed Ismail Bennani   if (!scripted_thread_interface) {
4259d8dd79SMed Ismail Bennani     error.SetErrorString("Failed to get scripted thread interface.");
4359d8dd79SMed Ismail Bennani     return;
4459d8dd79SMed Ismail Bennani   }
4559d8dd79SMed Ismail Bennani 
4659d8dd79SMed Ismail Bennani   llvm::Optional<std::string> class_name =
4759d8dd79SMed Ismail Bennani       process.GetInterface().GetScriptedThreadPluginName();
4859d8dd79SMed Ismail Bennani   if (!class_name || class_name->empty()) {
4959d8dd79SMed Ismail Bennani     error.SetErrorString("Failed to get scripted thread class name.");
5059d8dd79SMed Ismail Bennani     return;
5159d8dd79SMed Ismail Bennani   }
5259d8dd79SMed Ismail Bennani 
5359d8dd79SMed Ismail Bennani   ExecutionContext exe_ctx(process);
5459d8dd79SMed Ismail Bennani 
5559d8dd79SMed Ismail Bennani   StructuredData::GenericSP object_sp =
5659d8dd79SMed Ismail Bennani       scripted_thread_interface->CreatePluginObject(
5759d8dd79SMed Ismail Bennani           class_name->c_str(), exe_ctx,
5859d8dd79SMed Ismail Bennani           process.m_scripted_process_info.GetDictionarySP());
5959d8dd79SMed Ismail Bennani   if (!object_sp || !object_sp->IsValid()) {
6059d8dd79SMed Ismail Bennani     error.SetErrorString("Failed to create valid script object");
6159d8dd79SMed Ismail Bennani     return;
6259d8dd79SMed Ismail Bennani   }
6359d8dd79SMed Ismail Bennani 
6459d8dd79SMed Ismail Bennani   m_script_object_sp = object_sp;
6559d8dd79SMed Ismail Bennani 
6659d8dd79SMed Ismail Bennani   SetID(scripted_thread_interface->GetThreadID());
6759d8dd79SMed Ismail Bennani 
6859d8dd79SMed Ismail Bennani   llvm::Optional<std::string> reg_data =
6959d8dd79SMed Ismail Bennani       scripted_thread_interface->GetRegisterContext();
7059d8dd79SMed Ismail Bennani   if (!reg_data) {
7159d8dd79SMed Ismail Bennani     error.SetErrorString("Failed to get scripted thread registers data.");
7259d8dd79SMed Ismail Bennani     return;
7359d8dd79SMed Ismail Bennani   }
7459d8dd79SMed Ismail Bennani 
7559d8dd79SMed Ismail Bennani   DataBufferSP data_sp(
7659d8dd79SMed Ismail Bennani       std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
7759d8dd79SMed Ismail Bennani 
7859d8dd79SMed Ismail Bennani   if (!data_sp->GetByteSize()) {
7959d8dd79SMed Ismail Bennani     error.SetErrorString("Failed to copy raw registers data.");
8059d8dd79SMed Ismail Bennani     return;
8159d8dd79SMed Ismail Bennani   }
8259d8dd79SMed Ismail Bennani 
8359d8dd79SMed Ismail Bennani   std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
8459d8dd79SMed Ismail Bennani       std::make_shared<RegisterContextMemory>(
8559d8dd79SMed Ismail Bennani           *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);
8659d8dd79SMed Ismail Bennani   if (!reg_ctx_memory) {
8759d8dd79SMed Ismail Bennani     error.SetErrorString("Failed to create a register context.");
8859d8dd79SMed Ismail Bennani     return;
8959d8dd79SMed Ismail Bennani   }
9059d8dd79SMed Ismail Bennani 
9159d8dd79SMed Ismail Bennani   reg_ctx_memory->SetAllRegisterData(data_sp);
9259d8dd79SMed Ismail Bennani   m_reg_context_sp = reg_ctx_memory;
9359d8dd79SMed Ismail Bennani }
9459d8dd79SMed Ismail Bennani 
9559d8dd79SMed Ismail Bennani ScriptedThread::~ScriptedThread() { DestroyThread(); }
9659d8dd79SMed Ismail Bennani 
9759d8dd79SMed Ismail Bennani const char *ScriptedThread::GetName() {
9859d8dd79SMed Ismail Bennani   CheckInterpreterAndScriptObject();
9959d8dd79SMed Ismail Bennani   llvm::Optional<std::string> thread_name = GetInterface()->GetName();
10059d8dd79SMed Ismail Bennani   if (!thread_name)
10159d8dd79SMed Ismail Bennani     return nullptr;
10259d8dd79SMed Ismail Bennani   return ConstString(thread_name->c_str()).AsCString();
10359d8dd79SMed Ismail Bennani }
10459d8dd79SMed Ismail Bennani 
10559d8dd79SMed Ismail Bennani const char *ScriptedThread::GetQueueName() {
10659d8dd79SMed Ismail Bennani   CheckInterpreterAndScriptObject();
10759d8dd79SMed Ismail Bennani   llvm::Optional<std::string> queue_name = GetInterface()->GetQueue();
10859d8dd79SMed Ismail Bennani   if (!queue_name)
10959d8dd79SMed Ismail Bennani     return nullptr;
11059d8dd79SMed Ismail Bennani   return ConstString(queue_name->c_str()).AsCString();
11159d8dd79SMed Ismail Bennani }
11259d8dd79SMed Ismail Bennani 
11359d8dd79SMed Ismail Bennani void ScriptedThread::WillResume(StateType resume_state) {}
11459d8dd79SMed Ismail Bennani 
11559d8dd79SMed Ismail Bennani void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); }
11659d8dd79SMed Ismail Bennani 
11759d8dd79SMed Ismail Bennani RegisterContextSP ScriptedThread::GetRegisterContext() {
11859d8dd79SMed Ismail Bennani   if (!m_reg_context_sp) {
11959d8dd79SMed Ismail Bennani     m_reg_context_sp = std::make_shared<RegisterContextThreadMemory>(
12059d8dd79SMed Ismail Bennani         *this, LLDB_INVALID_ADDRESS);
12159d8dd79SMed Ismail Bennani     GetInterface()->GetRegisterContext();
12259d8dd79SMed Ismail Bennani   }
12359d8dd79SMed Ismail Bennani   return m_reg_context_sp;
12459d8dd79SMed Ismail Bennani }
12559d8dd79SMed Ismail Bennani 
12659d8dd79SMed Ismail Bennani RegisterContextSP
12759d8dd79SMed Ismail Bennani ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) {
12859d8dd79SMed Ismail Bennani   uint32_t concrete_frame_idx = frame ? frame->GetConcreteFrameIndex() : 0;
12959d8dd79SMed Ismail Bennani 
13059d8dd79SMed Ismail Bennani   if (concrete_frame_idx == 0)
13159d8dd79SMed Ismail Bennani     return GetRegisterContext();
13259d8dd79SMed Ismail Bennani   return GetUnwinder().CreateRegisterContextForFrame(frame);
13359d8dd79SMed Ismail Bennani }
13459d8dd79SMed Ismail Bennani 
13559d8dd79SMed Ismail Bennani bool ScriptedThread::CalculateStopInfo() {
13659d8dd79SMed Ismail Bennani   StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();
13759d8dd79SMed Ismail Bennani 
13859d8dd79SMed Ismail Bennani   Status error;
13959d8dd79SMed Ismail Bennani   lldb::StopInfoSP stop_info_sp;
14059d8dd79SMed Ismail Bennani   lldb::StopReason stop_reason_type;
14159d8dd79SMed Ismail Bennani 
14259d8dd79SMed Ismail Bennani   if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type))
14359d8dd79SMed Ismail Bennani     return GetInterface()->ErrorWithMessage<bool>(
144*88a941baSMed Ismail Bennani         LLVM_PRETTY_FUNCTION,
14559d8dd79SMed Ismail Bennani         "Couldn't find value for key 'type' in stop reason dictionary.", error);
14659d8dd79SMed Ismail Bennani 
14759d8dd79SMed Ismail Bennani   StructuredData::Dictionary *data_dict;
14859d8dd79SMed Ismail Bennani   if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict))
14959d8dd79SMed Ismail Bennani     return GetInterface()->ErrorWithMessage<bool>(
150*88a941baSMed Ismail Bennani         LLVM_PRETTY_FUNCTION,
15159d8dd79SMed Ismail Bennani         "Couldn't find value for key 'type' in stop reason dictionary.", error);
15259d8dd79SMed Ismail Bennani 
15359d8dd79SMed Ismail Bennani   switch (stop_reason_type) {
15459d8dd79SMed Ismail Bennani   case lldb::eStopReasonNone:
15559d8dd79SMed Ismail Bennani     break;
15659d8dd79SMed Ismail Bennani   case lldb::eStopReasonBreakpoint: {
15759d8dd79SMed Ismail Bennani     lldb::break_id_t break_id;
15859d8dd79SMed Ismail Bennani     data_dict->GetValueForKeyAsInteger("break_id", break_id,
15959d8dd79SMed Ismail Bennani                                        LLDB_INVALID_BREAK_ID);
16059d8dd79SMed Ismail Bennani     stop_info_sp =
16159d8dd79SMed Ismail Bennani         StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id);
16259d8dd79SMed Ismail Bennani   } break;
16359d8dd79SMed Ismail Bennani   case lldb::eStopReasonSignal: {
16459d8dd79SMed Ismail Bennani     int signal;
16559d8dd79SMed Ismail Bennani     llvm::StringRef description;
16659d8dd79SMed Ismail Bennani     data_dict->GetValueForKeyAsInteger("signal", signal,
16759d8dd79SMed Ismail Bennani                                        LLDB_INVALID_SIGNAL_NUMBER);
16859d8dd79SMed Ismail Bennani     data_dict->GetValueForKeyAsString("desc", description);
16959d8dd79SMed Ismail Bennani     stop_info_sp =
17059d8dd79SMed Ismail Bennani         StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());
17159d8dd79SMed Ismail Bennani   } break;
17259d8dd79SMed Ismail Bennani   default:
17359d8dd79SMed Ismail Bennani     return GetInterface()->ErrorWithMessage<bool>(
174*88a941baSMed Ismail Bennani         LLVM_PRETTY_FUNCTION,
17559d8dd79SMed Ismail Bennani         llvm::Twine("Unsupported stop reason type (" +
17659d8dd79SMed Ismail Bennani                     llvm::Twine(stop_reason_type) + llvm::Twine(")."))
17759d8dd79SMed Ismail Bennani             .str(),
17859d8dd79SMed Ismail Bennani         error);
17959d8dd79SMed Ismail Bennani   }
18059d8dd79SMed Ismail Bennani 
18159d8dd79SMed Ismail Bennani   SetStopInfo(stop_info_sp);
18259d8dd79SMed Ismail Bennani   return true;
18359d8dd79SMed Ismail Bennani }
18459d8dd79SMed Ismail Bennani 
18559d8dd79SMed Ismail Bennani void ScriptedThread::RefreshStateAfterStop() {
18659d8dd79SMed Ismail Bennani   // TODO: Implement
18759d8dd79SMed Ismail Bennani   if (m_reg_context_sp)
18859d8dd79SMed Ismail Bennani     m_reg_context_sp->InvalidateAllRegisters();
18959d8dd79SMed Ismail Bennani }
19059d8dd79SMed Ismail Bennani 
19159d8dd79SMed Ismail Bennani lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {
19259d8dd79SMed Ismail Bennani   return m_scripted_process.GetInterface().GetScriptedThreadInterface();
19359d8dd79SMed Ismail Bennani }
19459d8dd79SMed Ismail Bennani 
19559d8dd79SMed Ismail Bennani std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {
19659d8dd79SMed Ismail Bennani   CheckInterpreterAndScriptObject();
19759d8dd79SMed Ismail Bennani 
19859d8dd79SMed Ismail Bennani   if (!m_register_info_sp) {
19959d8dd79SMed Ismail Bennani     StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
20059d8dd79SMed Ismail Bennani     if (!reg_info)
20159d8dd79SMed Ismail Bennani       return nullptr;
20259d8dd79SMed Ismail Bennani 
20359d8dd79SMed Ismail Bennani     m_register_info_sp = std::make_shared<DynamicRegisterInfo>(
20459d8dd79SMed Ismail Bennani         *reg_info, m_scripted_process.GetTarget().GetArchitecture());
20559d8dd79SMed Ismail Bennani     assert(m_register_info_sp->GetNumRegisters() > 0);
20659d8dd79SMed Ismail Bennani     assert(m_register_info_sp->GetNumRegisterSets() > 0);
20759d8dd79SMed Ismail Bennani   }
20859d8dd79SMed Ismail Bennani 
20959d8dd79SMed Ismail Bennani   return m_register_info_sp;
21059d8dd79SMed Ismail Bennani }
211