brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.3 KiB · 491efac Raw
444 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "ScriptedThread.h"10#include "ScriptedFrame.h"11 12#include "Plugins/Process/Utility/RegisterContextThreadMemory.h"13#include "Plugins/Process/Utility/StopInfoMachException.h"14#include "lldb/Target/OperatingSystem.h"15#include "lldb/Target/Process.h"16#include "lldb/Target/RegisterContext.h"17#include "lldb/Target/StopInfo.h"18#include "lldb/Target/Unwind.h"19#include "lldb/Utility/DataBufferHeap.h"20#include "lldb/Utility/LLDBLog.h"21#include <memory>22#include <optional>23 24using namespace lldb;25using namespace lldb_private;26 27void ScriptedThread::CheckInterpreterAndScriptObject() const {28  lldbassert(m_script_object_sp && "Invalid Script Object.");29  lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");30}31 32llvm::Expected<std::shared_ptr<ScriptedThread>>33ScriptedThread::Create(ScriptedProcess &process,34                       StructuredData::Generic *script_object) {35  if (!process.IsValid())36    return llvm::createStringError(llvm::inconvertibleErrorCode(),37                                   "Invalid scripted process.");38 39  process.CheckScriptedInterface();40 41  auto scripted_thread_interface =42      process.GetInterface().CreateScriptedThreadInterface();43  if (!scripted_thread_interface)44    return llvm::createStringError(45        llvm::inconvertibleErrorCode(),46        "Failed to create scripted thread interface.");47 48  llvm::StringRef thread_class_name;49  if (!script_object) {50    std::optional<std::string> class_name =51        process.GetInterface().GetScriptedThreadPluginName();52    if (!class_name || class_name->empty())53      return llvm::createStringError(54          llvm::inconvertibleErrorCode(),55          "Failed to get scripted thread class name.");56    thread_class_name = *class_name;57  }58 59  ExecutionContext exe_ctx(process);60  auto obj_or_err = scripted_thread_interface->CreatePluginObject(61      thread_class_name, exe_ctx, process.m_scripted_metadata.GetArgsSP(),62      script_object);63 64  if (!obj_or_err) {65    llvm::consumeError(obj_or_err.takeError());66    return llvm::createStringError(llvm::inconvertibleErrorCode(),67                                   "Failed to create script object.");68  }69 70  StructuredData::GenericSP owned_script_object_sp = *obj_or_err;71 72  if (!owned_script_object_sp->IsValid())73    return llvm::createStringError(llvm::inconvertibleErrorCode(),74                                   "Created script object is invalid.");75 76  lldb::tid_t tid = scripted_thread_interface->GetThreadID();77 78  return std::make_shared<ScriptedThread>(process, scripted_thread_interface,79                                          tid, owned_script_object_sp);80}81 82ScriptedThread::ScriptedThread(ScriptedProcess &process,83                               ScriptedThreadInterfaceSP interface_sp,84                               lldb::tid_t tid,85                               StructuredData::GenericSP script_object_sp)86    : Thread(process, tid), m_scripted_process(process),87      m_scripted_thread_interface_sp(interface_sp),88      m_script_object_sp(script_object_sp) {}89 90ScriptedThread::~ScriptedThread() { DestroyThread(); }91 92const char *ScriptedThread::GetName() {93  CheckInterpreterAndScriptObject();94  std::optional<std::string> thread_name = GetInterface()->GetName();95  if (!thread_name)96    return nullptr;97  return ConstString(thread_name->c_str()).AsCString();98}99 100const char *ScriptedThread::GetQueueName() {101  CheckInterpreterAndScriptObject();102  std::optional<std::string> queue_name = GetInterface()->GetQueue();103  if (!queue_name)104    return nullptr;105  return ConstString(queue_name->c_str()).AsCString();106}107 108void ScriptedThread::WillResume(StateType resume_state) {}109 110void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); }111 112RegisterContextSP ScriptedThread::GetRegisterContext() {113  if (!m_reg_context_sp)114    m_reg_context_sp = CreateRegisterContextForFrame(nullptr);115  return m_reg_context_sp;116}117 118RegisterContextSP119ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) {120  const uint32_t concrete_frame_idx =121      frame ? frame->GetConcreteFrameIndex() : 0;122 123  if (concrete_frame_idx)124    return GetUnwinder().CreateRegisterContextForFrame(frame);125 126  lldb::RegisterContextSP reg_ctx_sp;127  Status error;128 129  std::optional<std::string> reg_data = GetInterface()->GetRegisterContext();130  if (!reg_data)131    return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(132        LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.",133        error, LLDBLog::Thread);134 135  DataBufferSP data_sp(136      std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));137 138  if (!data_sp->GetByteSize())139    return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(140        LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error,141        LLDBLog::Thread);142 143  std::shared_ptr<RegisterContextMemory> reg_ctx_memory =144      std::make_shared<RegisterContextMemory>(145          *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);146  if (!reg_ctx_memory)147    return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(148        LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error,149        LLDBLog::Thread);150 151  reg_ctx_memory->SetAllRegisterData(data_sp);152  m_reg_context_sp = reg_ctx_memory;153 154  return m_reg_context_sp;155}156 157bool ScriptedThread::LoadArtificialStackFrames() {158  StructuredData::ArraySP arr_sp = GetInterface()->GetStackFrames();159 160  Status error;161  if (!arr_sp)162    return ScriptedInterface::ErrorWithMessage<bool>(163        LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stackframes.",164        error, LLDBLog::Thread);165 166  size_t arr_size = arr_sp->GetSize();167  if (arr_size > std::numeric_limits<uint32_t>::max())168    return ScriptedInterface::ErrorWithMessage<bool>(169        LLVM_PRETTY_FUNCTION,170        llvm::Twine(171            "StackFrame array size (" + llvm::Twine(arr_size) +172            llvm::Twine(173                ") is greater than maximum authorized for a StackFrameList."))174            .str(),175        error, LLDBLog::Thread);176 177  auto create_frame_from_dict =178      [this, arr_sp](size_t idx) -> llvm::Expected<StackFrameSP> {179    Status error;180    std::optional<StructuredData::Dictionary *> maybe_dict =181        arr_sp->GetItemAtIndexAsDictionary(idx);182    if (!maybe_dict) {183      ScriptedInterface::ErrorWithMessage<bool>(184          LLVM_PRETTY_FUNCTION,185          llvm::Twine(186              "Couldn't get artificial stackframe dictionary at index (" +187              llvm::Twine(idx) + llvm::Twine(") from stackframe array."))188              .str(),189          error, LLDBLog::Thread);190      return error.ToError();191    }192    StructuredData::Dictionary *dict = *maybe_dict;193 194    lldb::addr_t pc;195    if (!dict->GetValueForKeyAsInteger("pc", pc)) {196      ScriptedInterface::ErrorWithMessage<bool>(197          LLVM_PRETTY_FUNCTION,198          "Couldn't find value for key 'pc' in stackframe dictionary.", error,199          LLDBLog::Thread);200      return error.ToError();201    }202 203    Address symbol_addr;204    symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget());205 206    lldb::addr_t cfa = LLDB_INVALID_ADDRESS;207    bool cfa_is_valid = false;208    const bool artificial = false;209    const bool behaves_like_zeroth_frame = false;210    SymbolContext sc;211    symbol_addr.CalculateSymbolContext(&sc);212 213    return std::make_shared<StackFrame>(this->shared_from_this(), idx, idx, cfa,214                                        cfa_is_valid, pc,215                                        StackFrame::Kind::Synthetic, artificial,216                                        behaves_like_zeroth_frame, &sc);217  };218 219  auto create_frame_from_script_object =220      [this, arr_sp](size_t idx) -> llvm::Expected<StackFrameSP> {221    Status error;222    StructuredData::ObjectSP object_sp = arr_sp->GetItemAtIndex(idx);223    if (!object_sp || !object_sp->GetAsGeneric()) {224      ScriptedInterface::ErrorWithMessage<bool>(225          LLVM_PRETTY_FUNCTION,226          llvm::Twine("Couldn't get artificial stackframe object at index (" +227                      llvm::Twine(idx) +228                      llvm::Twine(") from stackframe array."))229              .str(),230          error, LLDBLog::Thread);231      return error.ToError();232    }233 234    auto frame_or_error =235        ScriptedFrame::Create(*this, nullptr, object_sp->GetAsGeneric());236 237    if (!frame_or_error) {238      ScriptedInterface::ErrorWithMessage<bool>(239          LLVM_PRETTY_FUNCTION, toString(frame_or_error.takeError()), error);240      return error.ToError();241    }242 243    StackFrameSP frame_sp = frame_or_error.get();244    lldbassert(frame_sp && "Couldn't initialize scripted frame.");245 246    return frame_sp;247  };248 249  StackFrameListSP frames = GetStackFrameList();250 251  for (size_t idx = 0; idx < arr_size; idx++) {252    StackFrameSP synth_frame_sp = nullptr;253 254    auto frame_from_dict_or_err = create_frame_from_dict(idx);255    if (!frame_from_dict_or_err) {256      auto frame_from_script_obj_or_err = create_frame_from_script_object(idx);257 258      if (!frame_from_script_obj_or_err) {259        return ScriptedInterface::ErrorWithMessage<bool>(260            LLVM_PRETTY_FUNCTION,261            llvm::Twine("Couldn't add artificial frame (" + llvm::Twine(idx) +262                        llvm::Twine(") to ScriptedThread StackFrameList."))263                .str(),264            error, LLDBLog::Thread);265      } else {266        llvm::consumeError(frame_from_dict_or_err.takeError());267        synth_frame_sp = *frame_from_script_obj_or_err;268      }269    } else {270      synth_frame_sp = *frame_from_dict_or_err;271    }272 273    if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp))274      return ScriptedInterface::ErrorWithMessage<bool>(275          LLVM_PRETTY_FUNCTION,276          llvm::Twine("Couldn't add frame (" + llvm::Twine(idx) +277                      llvm::Twine(") to ScriptedThread StackFrameList."))278              .str(),279          error, LLDBLog::Thread);280  }281 282  return true;283}284 285bool ScriptedThread::CalculateStopInfo() {286  StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();287 288  Status error;289  if (!dict_sp)290    return ScriptedInterface::ErrorWithMessage<bool>(291        LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error,292        LLDBLog::Thread);293 294  // If we're at a BreakpointSite, mark that we stopped there and295  // need to hit the breakpoint when we resume.  This will be cleared296  // if we CreateStopReasonWithBreakpointSiteID.297  if (RegisterContextSP reg_ctx_sp = GetRegisterContext()) {298    addr_t pc = reg_ctx_sp->GetPC();299    if (BreakpointSiteSP bp_site_sp =300            GetProcess()->GetBreakpointSiteList().FindByAddress(pc))301      if (bp_site_sp->IsEnabled())302        SetThreadStoppedAtUnexecutedBP(pc);303  }304 305  lldb::StopInfoSP stop_info_sp;306  lldb::StopReason stop_reason_type;307 308  if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type))309    return ScriptedInterface::ErrorWithMessage<bool>(310        LLVM_PRETTY_FUNCTION,311        "Couldn't find value for key 'type' in stop reason dictionary.", error,312        LLDBLog::Thread);313 314  StructuredData::Dictionary *data_dict;315  if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict))316    return ScriptedInterface::ErrorWithMessage<bool>(317        LLVM_PRETTY_FUNCTION,318        "Couldn't find value for key 'data' in stop reason dictionary.", error,319        LLDBLog::Thread);320 321  switch (stop_reason_type) {322  case lldb::eStopReasonNone:323    return true;324  case lldb::eStopReasonBreakpoint: {325    lldb::break_id_t break_id;326    data_dict->GetValueForKeyAsInteger("break_id", break_id,327                                       LLDB_INVALID_BREAK_ID);328    stop_info_sp =329        StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id);330  } break;331  case lldb::eStopReasonSignal: {332    uint32_t signal;333    llvm::StringRef description;334    if (!data_dict->GetValueForKeyAsInteger("signal", signal)) {335        signal = LLDB_INVALID_SIGNAL_NUMBER;336        return false;337    }338    data_dict->GetValueForKeyAsString("desc", description);339    stop_info_sp =340        StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());341  } break;342  case lldb::eStopReasonTrace: {343    stop_info_sp = StopInfo::CreateStopReasonToTrace(*this);344  } break;345  case lldb::eStopReasonException: {346#if defined(__APPLE__)347    StructuredData::Dictionary *mach_exception;348    if (data_dict->GetValueForKeyAsDictionary("mach_exception",349                                              mach_exception)) {350      llvm::StringRef value;351      mach_exception->GetValueForKeyAsString("type", value);352      auto exc_type =353          StopInfoMachException::MachException::ExceptionCode(value.data());354 355      if (!exc_type)356        return false;357 358      uint32_t exc_data_size = 0;359      llvm::SmallVector<uint64_t, 3> raw_codes;360 361      StructuredData::Array *exc_rawcodes;362      mach_exception->GetValueForKeyAsArray("rawCodes", exc_rawcodes);363      if (exc_rawcodes) {364        auto fetch_data = [&raw_codes](StructuredData::Object *obj) {365          if (!obj)366            return false;367          raw_codes.push_back(obj->GetUnsignedIntegerValue());368          return true;369        };370 371        exc_rawcodes->ForEach(fetch_data);372        exc_data_size = raw_codes.size();373      }374 375      stop_info_sp = StopInfoMachException::CreateStopReasonWithMachException(376          *this, *exc_type, exc_data_size,377          exc_data_size >= 1 ? raw_codes[0] : 0,378          exc_data_size >= 2 ? raw_codes[1] : 0,379          exc_data_size >= 3 ? raw_codes[2] : 0);380 381      break;382    }383#endif384    stop_info_sp =385        StopInfo::CreateStopReasonWithException(*this, "EXC_BAD_ACCESS");386  } break;387  default:388    return ScriptedInterface::ErrorWithMessage<bool>(389        LLVM_PRETTY_FUNCTION,390        llvm::Twine("Unsupported stop reason type (" +391                    llvm::Twine(stop_reason_type) + llvm::Twine(")."))392            .str(),393        error, LLDBLog::Thread);394  }395 396  if (!stop_info_sp)397    return false;398 399  SetStopInfo(stop_info_sp);400  return true;401}402 403void ScriptedThread::RefreshStateAfterStop() {404  GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);405  LoadArtificialStackFrames();406}407 408lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {409  return m_scripted_thread_interface_sp;410}411 412std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {413  CheckInterpreterAndScriptObject();414 415  if (!m_register_info_sp) {416    StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();417 418    Status error;419    if (!reg_info)420      return ScriptedInterface::ErrorWithMessage<421          std::shared_ptr<DynamicRegisterInfo>>(422          LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers info.",423          error, LLDBLog::Thread);424 425    m_register_info_sp = DynamicRegisterInfo::Create(426        *reg_info, m_scripted_process.GetTarget().GetArchitecture());427  }428 429  return m_register_info_sp;430}431 432StructuredData::ObjectSP ScriptedThread::FetchThreadExtendedInfo() {433  CheckInterpreterAndScriptObject();434 435  Status error;436  StructuredData::ArraySP extended_info_sp = GetInterface()->GetExtendedInfo();437 438  if (!extended_info_sp || !extended_info_sp->GetSize())439    return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(440        LLVM_PRETTY_FUNCTION, "No extended information found", error);441 442  return extended_info_sp;443}444