Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
39642 views
//===-- ScriptedThread.cpp ------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "ScriptedThread.h"910#include "Plugins/Process/Utility/RegisterContextThreadMemory.h"11#include "Plugins/Process/Utility/StopInfoMachException.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/LLDBLog.h"19#include <memory>20#include <optional>2122using namespace lldb;23using namespace lldb_private;2425void ScriptedThread::CheckInterpreterAndScriptObject() const {26lldbassert(m_script_object_sp && "Invalid Script Object.");27lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");28}2930llvm::Expected<std::shared_ptr<ScriptedThread>>31ScriptedThread::Create(ScriptedProcess &process,32StructuredData::Generic *script_object) {33if (!process.IsValid())34return llvm::createStringError(llvm::inconvertibleErrorCode(),35"Invalid scripted process.");3637process.CheckScriptedInterface();3839auto scripted_thread_interface =40process.GetInterface().CreateScriptedThreadInterface();41if (!scripted_thread_interface)42return llvm::createStringError(43llvm::inconvertibleErrorCode(),44"Failed to create scripted thread interface.");4546llvm::StringRef thread_class_name;47if (!script_object) {48std::optional<std::string> class_name =49process.GetInterface().GetScriptedThreadPluginName();50if (!class_name || class_name->empty())51return llvm::createStringError(52llvm::inconvertibleErrorCode(),53"Failed to get scripted thread class name.");54thread_class_name = *class_name;55}5657ExecutionContext exe_ctx(process);58auto obj_or_err = scripted_thread_interface->CreatePluginObject(59thread_class_name, exe_ctx, process.m_scripted_metadata.GetArgsSP(),60script_object);6162if (!obj_or_err) {63llvm::consumeError(obj_or_err.takeError());64return llvm::createStringError(llvm::inconvertibleErrorCode(),65"Failed to create script object.");66}6768StructuredData::GenericSP owned_script_object_sp = *obj_or_err;6970if (!owned_script_object_sp->IsValid())71return llvm::createStringError(llvm::inconvertibleErrorCode(),72"Created script object is invalid.");7374lldb::tid_t tid = scripted_thread_interface->GetThreadID();7576return std::make_shared<ScriptedThread>(process, scripted_thread_interface,77tid, owned_script_object_sp);78}7980ScriptedThread::ScriptedThread(ScriptedProcess &process,81ScriptedThreadInterfaceSP interface_sp,82lldb::tid_t tid,83StructuredData::GenericSP script_object_sp)84: Thread(process, tid), m_scripted_process(process),85m_scripted_thread_interface_sp(interface_sp),86m_script_object_sp(script_object_sp) {}8788ScriptedThread::~ScriptedThread() { DestroyThread(); }8990const char *ScriptedThread::GetName() {91CheckInterpreterAndScriptObject();92std::optional<std::string> thread_name = GetInterface()->GetName();93if (!thread_name)94return nullptr;95return ConstString(thread_name->c_str()).AsCString();96}9798const char *ScriptedThread::GetQueueName() {99CheckInterpreterAndScriptObject();100std::optional<std::string> queue_name = GetInterface()->GetQueue();101if (!queue_name)102return nullptr;103return ConstString(queue_name->c_str()).AsCString();104}105106void ScriptedThread::WillResume(StateType resume_state) {}107108void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); }109110RegisterContextSP ScriptedThread::GetRegisterContext() {111if (!m_reg_context_sp)112m_reg_context_sp = CreateRegisterContextForFrame(nullptr);113return m_reg_context_sp;114}115116RegisterContextSP117ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) {118const uint32_t concrete_frame_idx =119frame ? frame->GetConcreteFrameIndex() : 0;120121if (concrete_frame_idx)122return GetUnwinder().CreateRegisterContextForFrame(frame);123124lldb::RegisterContextSP reg_ctx_sp;125Status error;126127std::optional<std::string> reg_data = GetInterface()->GetRegisterContext();128if (!reg_data)129return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(130LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.",131error, LLDBLog::Thread);132133DataBufferSP data_sp(134std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));135136if (!data_sp->GetByteSize())137return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(138LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error,139LLDBLog::Thread);140141std::shared_ptr<RegisterContextMemory> reg_ctx_memory =142std::make_shared<RegisterContextMemory>(143*this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);144if (!reg_ctx_memory)145return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(146LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error,147LLDBLog::Thread);148149reg_ctx_memory->SetAllRegisterData(data_sp);150m_reg_context_sp = reg_ctx_memory;151152return m_reg_context_sp;153}154155bool ScriptedThread::LoadArtificialStackFrames() {156StructuredData::ArraySP arr_sp = GetInterface()->GetStackFrames();157158Status error;159if (!arr_sp)160return ScriptedInterface::ErrorWithMessage<bool>(161LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stackframes.",162error, LLDBLog::Thread);163164size_t arr_size = arr_sp->GetSize();165if (arr_size > std::numeric_limits<uint32_t>::max())166return ScriptedInterface::ErrorWithMessage<bool>(167LLVM_PRETTY_FUNCTION,168llvm::Twine(169"StackFrame array size (" + llvm::Twine(arr_size) +170llvm::Twine(171") is greater than maximum authorized for a StackFrameList."))172.str(),173error, LLDBLog::Thread);174175StackFrameListSP frames = GetStackFrameList();176177for (size_t idx = 0; idx < arr_size; idx++) {178std::optional<StructuredData::Dictionary *> maybe_dict =179arr_sp->GetItemAtIndexAsDictionary(idx);180if (!maybe_dict)181return ScriptedInterface::ErrorWithMessage<bool>(182LLVM_PRETTY_FUNCTION,183llvm::Twine(184"Couldn't get artificial stackframe dictionary at index (" +185llvm::Twine(idx) + llvm::Twine(") from stackframe array."))186.str(),187error, LLDBLog::Thread);188StructuredData::Dictionary *dict = *maybe_dict;189190lldb::addr_t pc;191if (!dict->GetValueForKeyAsInteger("pc", pc))192return ScriptedInterface::ErrorWithMessage<bool>(193LLVM_PRETTY_FUNCTION,194"Couldn't find value for key 'pc' in stackframe dictionary.", error,195LLDBLog::Thread);196197Address symbol_addr;198symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget());199200lldb::addr_t cfa = LLDB_INVALID_ADDRESS;201bool cfa_is_valid = false;202const bool behaves_like_zeroth_frame = false;203SymbolContext sc;204symbol_addr.CalculateSymbolContext(&sc);205206StackFrameSP synth_frame_sp = std::make_shared<StackFrame>(207this->shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,208StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc);209210if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp))211return ScriptedInterface::ErrorWithMessage<bool>(212LLVM_PRETTY_FUNCTION,213llvm::Twine("Couldn't add frame (" + llvm::Twine(idx) +214llvm::Twine(") to ScriptedThread StackFrameList."))215.str(),216error, LLDBLog::Thread);217}218219return true;220}221222bool ScriptedThread::CalculateStopInfo() {223StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();224225Status error;226if (!dict_sp)227return ScriptedInterface::ErrorWithMessage<bool>(228LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error,229LLDBLog::Thread);230231lldb::StopInfoSP stop_info_sp;232lldb::StopReason stop_reason_type;233234if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type))235return ScriptedInterface::ErrorWithMessage<bool>(236LLVM_PRETTY_FUNCTION,237"Couldn't find value for key 'type' in stop reason dictionary.", error,238LLDBLog::Thread);239240StructuredData::Dictionary *data_dict;241if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict))242return ScriptedInterface::ErrorWithMessage<bool>(243LLVM_PRETTY_FUNCTION,244"Couldn't find value for key 'data' in stop reason dictionary.", error,245LLDBLog::Thread);246247switch (stop_reason_type) {248case lldb::eStopReasonNone:249return true;250case lldb::eStopReasonBreakpoint: {251lldb::break_id_t break_id;252data_dict->GetValueForKeyAsInteger("break_id", break_id,253LLDB_INVALID_BREAK_ID);254stop_info_sp =255StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id);256} break;257case lldb::eStopReasonSignal: {258uint32_t signal;259llvm::StringRef description;260if (!data_dict->GetValueForKeyAsInteger("signal", signal)) {261signal = LLDB_INVALID_SIGNAL_NUMBER;262return false;263}264data_dict->GetValueForKeyAsString("desc", description);265stop_info_sp =266StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());267} break;268case lldb::eStopReasonTrace: {269stop_info_sp = StopInfo::CreateStopReasonToTrace(*this);270} break;271case lldb::eStopReasonException: {272#if defined(__APPLE__)273StructuredData::Dictionary *mach_exception;274if (data_dict->GetValueForKeyAsDictionary("mach_exception",275mach_exception)) {276llvm::StringRef value;277mach_exception->GetValueForKeyAsString("type", value);278auto exc_type =279StopInfoMachException::MachException::ExceptionCode(value.data());280281if (!exc_type)282return false;283284uint32_t exc_data_size = 0;285llvm::SmallVector<uint64_t, 3> raw_codes;286287StructuredData::Array *exc_rawcodes;288mach_exception->GetValueForKeyAsArray("rawCodes", exc_rawcodes);289if (exc_rawcodes) {290auto fetch_data = [&raw_codes](StructuredData::Object *obj) {291if (!obj)292return false;293raw_codes.push_back(obj->GetUnsignedIntegerValue());294return true;295};296297exc_rawcodes->ForEach(fetch_data);298exc_data_size = raw_codes.size();299}300301stop_info_sp = StopInfoMachException::CreateStopReasonWithMachException(302*this, *exc_type, exc_data_size,303exc_data_size >= 1 ? raw_codes[0] : 0,304exc_data_size >= 2 ? raw_codes[1] : 0,305exc_data_size >= 3 ? raw_codes[2] : 0);306307break;308}309#endif310stop_info_sp =311StopInfo::CreateStopReasonWithException(*this, "EXC_BAD_ACCESS");312} break;313default:314return ScriptedInterface::ErrorWithMessage<bool>(315LLVM_PRETTY_FUNCTION,316llvm::Twine("Unsupported stop reason type (" +317llvm::Twine(stop_reason_type) + llvm::Twine(")."))318.str(),319error, LLDBLog::Thread);320}321322if (!stop_info_sp)323return false;324325SetStopInfo(stop_info_sp);326return true;327}328329void ScriptedThread::RefreshStateAfterStop() {330GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);331LoadArtificialStackFrames();332}333334lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {335return m_scripted_thread_interface_sp;336}337338std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {339CheckInterpreterAndScriptObject();340341if (!m_register_info_sp) {342StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();343344Status error;345if (!reg_info)346return ScriptedInterface::ErrorWithMessage<347std::shared_ptr<DynamicRegisterInfo>>(348LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers info.",349error, LLDBLog::Thread);350351m_register_info_sp = DynamicRegisterInfo::Create(352*reg_info, m_scripted_process.GetTarget().GetArchitecture());353}354355return m_register_info_sp;356}357358StructuredData::ObjectSP ScriptedThread::FetchThreadExtendedInfo() {359CheckInterpreterAndScriptObject();360361Status error;362StructuredData::ArraySP extended_info_sp = GetInterface()->GetExtendedInfo();363364if (!extended_info_sp || !extended_info_sp->GetSize())365return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(366LLVM_PRETTY_FUNCTION, "No extended information found", error);367368return extended_info_sp;369}370371372