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