brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.1 KiB · 30fc195 Raw
574 lines · cpp
1//===-- ScriptedProcess.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 "ScriptedProcess.h"10 11#include "lldb/Core/Debugger.h"12#include "lldb/Core/Module.h"13#include "lldb/Core/PluginManager.h"14 15#include "lldb/Host/OptionParser.h"16#include "lldb/Host/ThreadLauncher.h"17#include "lldb/Interpreter/CommandInterpreter.h"18#include "lldb/Interpreter/OptionArgParser.h"19#include "lldb/Interpreter/OptionGroupBoolean.h"20#include "lldb/Interpreter/ScriptInterpreter.h"21#include "lldb/Target/MemoryRegionInfo.h"22#include "lldb/Target/Queue.h"23#include "lldb/Target/RegisterContext.h"24#include "lldb/Utility/LLDBLog.h"25#include "lldb/Utility/ScriptedMetadata.h"26#include "lldb/Utility/State.h"27 28#include "Plugins/ObjectFile/Placeholder/ObjectFilePlaceholder.h"29 30#include <mutex>31 32LLDB_PLUGIN_DEFINE(ScriptedProcess)33 34using namespace lldb;35using namespace lldb_private;36 37llvm::StringRef ScriptedProcess::GetPluginDescriptionStatic() {38  return "Scripted Process plug-in.";39}40 41static constexpr lldb::ScriptLanguage g_supported_script_languages[] = {42    ScriptLanguage::eScriptLanguagePython,43};44 45bool ScriptedProcess::IsScriptLanguageSupported(lldb::ScriptLanguage language) {46  llvm::ArrayRef<lldb::ScriptLanguage> supported_languages =47      llvm::ArrayRef(g_supported_script_languages);48 49  return llvm::is_contained(supported_languages, language);50}51 52lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp,53                                                lldb::ListenerSP listener_sp,54                                                const FileSpec *file,55                                                bool can_connect) {56  if (!target_sp ||57      !IsScriptLanguageSupported(target_sp->GetDebugger().GetScriptLanguage()))58    return nullptr;59 60  ScriptedMetadata scripted_metadata(target_sp->GetProcessLaunchInfo());61 62  Status error;63  auto process_sp = std::shared_ptr<ScriptedProcess>(64      new ScriptedProcess(target_sp, listener_sp, scripted_metadata, error));65 66  if (error.Fail() || !process_sp || !process_sp->m_interface_up) {67    LLDB_LOGF(GetLog(LLDBLog::Process), "%s", error.AsCString());68    return nullptr;69  }70 71  return process_sp;72}73 74bool ScriptedProcess::CanDebug(lldb::TargetSP target_sp,75                               bool plugin_specified_by_name) {76  return true;77}78 79ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp,80                                 lldb::ListenerSP listener_sp,81                                 const ScriptedMetadata &scripted_metadata,82                                 Status &error)83    : Process(target_sp, listener_sp), m_scripted_metadata(scripted_metadata) {84 85  if (!target_sp) {86    error = Status::FromErrorStringWithFormat(87        "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__, "Invalid target");88    return;89  }90 91  ScriptInterpreter *interpreter =92      target_sp->GetDebugger().GetScriptInterpreter();93 94  if (!interpreter) {95    error = Status::FromErrorStringWithFormat(96        "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__,97        "Debugger has no Script Interpreter");98    return;99  }100 101  // Create process instance interface102  m_interface_up = interpreter->CreateScriptedProcessInterface();103  if (!m_interface_up) {104    error = Status::FromErrorStringWithFormat(105        "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__,106        "Script interpreter couldn't create Scripted Process Interface");107    return;108  }109 110  ExecutionContext exe_ctx(target_sp, /*get_process=*/false);111 112  // Create process script object113  auto obj_or_err = GetInterface().CreatePluginObject(114      m_scripted_metadata.GetClassName(), exe_ctx,115      m_scripted_metadata.GetArgsSP());116 117  if (!obj_or_err) {118    llvm::consumeError(obj_or_err.takeError());119    error = Status::FromErrorString("Failed to create script object.");120    return;121  }122 123  StructuredData::GenericSP object_sp = *obj_or_err;124 125  if (!object_sp || !object_sp->IsValid()) {126    error = Status::FromErrorStringWithFormat(127        "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__,128        "Failed to create valid script object");129    return;130  }131}132 133ScriptedProcess::~ScriptedProcess() {134  Clear();135  // If the interface is not valid, we can't call Finalize(). When that happens136  // it means that the Scripted Process instanciation failed and the137  // CreateProcess function returns a nullptr, so no one besides this class138  // should have access to that bogus process object.139  if (!m_interface_up)140    return;141  // We need to call finalize on the process before destroying ourselves to142  // make sure all of the broadcaster cleanup goes as planned. If we destruct143  // this class, then Process::~Process() might have problems trying to fully144  // destroy the broadcaster.145  Finalize(true /* destructing */);146}147 148void ScriptedProcess::Initialize() {149  static llvm::once_flag g_once_flag;150 151  llvm::call_once(g_once_flag, []() {152    PluginManager::RegisterPlugin(GetPluginNameStatic(),153                                  GetPluginDescriptionStatic(), CreateInstance);154  });155}156 157void ScriptedProcess::Terminate() {158  PluginManager::UnregisterPlugin(ScriptedProcess::CreateInstance);159}160 161Status ScriptedProcess::DoLoadCore() {162  ProcessLaunchInfo launch_info = GetTarget().GetProcessLaunchInfo();163 164  return DoLaunch(nullptr, launch_info);165}166 167Status ScriptedProcess::DoLaunch(Module *exe_module,168                                 ProcessLaunchInfo &launch_info) {169  LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s launching process", __FUNCTION__);170 171  /* MARK: This doesn't reflect how lldb actually launches a process.172           In reality, it attaches to debugserver, then resume the process.173           That's not true in all cases.  If debugserver is remote, lldb174           asks debugserver to launch the process for it. */175  Status error = GetInterface().Launch();176  SetPrivateState(eStateStopped);177  return error;178}179 180void ScriptedProcess::DidLaunch() { m_pid = GetInterface().GetProcessID(); }181 182void ScriptedProcess::DidResume() {183  // Update the PID again, in case the user provided a placeholder pid at launch184  m_pid = GetInterface().GetProcessID();185}186 187Status ScriptedProcess::DoResume(RunDirection direction) {188  LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s resuming process", __FUNCTION__);189 190  if (direction == RunDirection::eRunForward)191    return GetInterface().Resume();192  // FIXME: Pipe reverse continue through Scripted Processes193  return Status::FromErrorStringWithFormatv(194      "{0} does not support reverse execution of processes", GetPluginName());195}196 197Status ScriptedProcess::DoAttach(const ProcessAttachInfo &attach_info) {198  Status error = GetInterface().Attach(attach_info);199  SetPrivateState(eStateRunning);200  SetPrivateState(eStateStopped);201  if (error.Fail())202    return error;203  // NOTE: We need to set the PID before finishing to attach otherwise we will204  // hit an assert when calling the attach completion handler.205  DidLaunch();206 207  return {};208}209 210Status211ScriptedProcess::DoAttachToProcessWithID(lldb::pid_t pid,212                                         const ProcessAttachInfo &attach_info) {213  return DoAttach(attach_info);214}215 216Status ScriptedProcess::DoAttachToProcessWithName(217    const char *process_name, const ProcessAttachInfo &attach_info) {218  return DoAttach(attach_info);219}220 221void ScriptedProcess::DidAttach(ArchSpec &process_arch) {222  process_arch = GetArchitecture();223}224 225Status ScriptedProcess::DoDestroy() { return Status(); }226 227bool ScriptedProcess::IsAlive() { return GetInterface().IsAlive(); }228 229size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,230                                     Status &error) {231  lldb::DataExtractorSP data_extractor_sp =232      GetInterface().ReadMemoryAtAddress(addr, size, error);233 234  if (!data_extractor_sp || !data_extractor_sp->GetByteSize() || error.Fail())235    return 0;236 237  offset_t bytes_copied = data_extractor_sp->CopyByteOrderedData(238      0, data_extractor_sp->GetByteSize(), buf, size, GetByteOrder());239 240  if (!bytes_copied || bytes_copied == LLDB_INVALID_OFFSET)241    return ScriptedInterface::ErrorWithMessage<size_t>(242        LLVM_PRETTY_FUNCTION, "Failed to copy read memory to buffer.", error);243 244  // FIXME: We should use the diagnostic system to report a warning if the245  // `bytes_copied` is different from `size`.246 247  return bytes_copied;248}249 250size_t ScriptedProcess::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,251                                      size_t size, Status &error) {252  lldb::DataExtractorSP data_extractor_sp = std::make_shared<DataExtractor>(253      buf, size, GetByteOrder(), GetAddressByteSize());254 255  if (!data_extractor_sp || !data_extractor_sp->GetByteSize())256    return 0;257 258  lldb::offset_t bytes_written =259      GetInterface().WriteMemoryAtAddress(vm_addr, data_extractor_sp, error);260 261  if (!bytes_written || bytes_written == LLDB_INVALID_OFFSET)262    return ScriptedInterface::ErrorWithMessage<size_t>(263        LLVM_PRETTY_FUNCTION, "Failed to copy write buffer to memory.", error);264 265  // FIXME: We should use the diagnostic system to report a warning if the266  // `bytes_written` is different from `size`.267 268  return bytes_written;269}270 271Status ScriptedProcess::EnableBreakpointSite(BreakpointSite *bp_site) {272  assert(bp_site != nullptr);273 274  if (bp_site->IsEnabled()) {275    return {};276  }277 278  if (bp_site->HardwareRequired()) {279    return Status::FromErrorString(280        "Scripted Processes don't support hardware breakpoints");281  }282 283  Status error;284  GetInterface().CreateBreakpoint(bp_site->GetLoadAddress(), error);285 286  return error;287}288 289ArchSpec ScriptedProcess::GetArchitecture() {290  return GetTarget().GetArchitecture();291}292 293Status ScriptedProcess::DoGetMemoryRegionInfo(lldb::addr_t load_addr,294                                              MemoryRegionInfo &region) {295  Status error;296  if (auto region_or_err =297          GetInterface().GetMemoryRegionContainingAddress(load_addr, error))298    region = *region_or_err;299 300  return error;301}302 303Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos &region_list) {304  Status error;305  lldb::addr_t address = 0;306 307  while (auto region_or_err =308             GetInterface().GetMemoryRegionContainingAddress(address, error)) {309    if (error.Fail())310      break;311 312    MemoryRegionInfo &mem_region = *region_or_err;313    auto range = mem_region.GetRange();314    address += range.GetRangeBase() + range.GetByteSize();315    region_list.push_back(mem_region);316  }317 318  return error;319}320 321void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); }322 323bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,324                                         ThreadList &new_thread_list) {325  // TODO: Implement326  // This is supposed to get the current set of threads, if any of them are in327  // old_thread_list then they get copied to new_thread_list, and then any328  // actually new threads will get added to new_thread_list.329  m_thread_plans.ClearThreadCache();330 331  Status error;332  StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo();333 334  if (!thread_info_sp)335    return ScriptedInterface::ErrorWithMessage<bool>(336        LLVM_PRETTY_FUNCTION,337        "Couldn't fetch thread list from Scripted Process.", error);338 339  // Because `StructuredData::Dictionary` uses a `std::map<ConstString,340  // ObjectSP>` for storage, each item is sorted based on the key alphabetical341  // order. Since `GetThreadsInfo` provides thread indices as the key element,342  // thread info comes ordered alphabetically, instead of numerically, so we343  // need to sort the thread indices before creating thread.344 345  StructuredData::ArraySP keys = thread_info_sp->GetKeys();346 347  std::map<size_t, StructuredData::ObjectSP> sorted_threads;348  auto sort_keys = [&sorted_threads,349                    &thread_info_sp](StructuredData::Object *item) -> bool {350    if (!item)351      return false;352 353    llvm::StringRef key = item->GetStringValue();354    size_t idx = 0;355 356    // Make sure the provided index is actually an integer357    if (!llvm::to_integer(key, idx))358      return false;359 360    sorted_threads[idx] = thread_info_sp->GetValueForKey(key);361    return true;362  };363 364  size_t thread_count = thread_info_sp->GetSize();365 366  if (!keys->ForEach(sort_keys) || sorted_threads.size() != thread_count)367    // Might be worth showing the unsorted thread list instead of return early.368    return ScriptedInterface::ErrorWithMessage<bool>(369        LLVM_PRETTY_FUNCTION, "Couldn't sort thread list.", error);370 371  auto create_scripted_thread =372      [this, &error, &new_thread_list](373          const std::pair<size_t, StructuredData::ObjectSP> pair) -> bool {374    size_t idx = pair.first;375    StructuredData::ObjectSP object_sp = pair.second;376 377    if (!object_sp)378      return ScriptedInterface::ErrorWithMessage<bool>(379          LLVM_PRETTY_FUNCTION, "Invalid thread info object", error);380 381    auto thread_or_error =382        ScriptedThread::Create(*this, object_sp->GetAsGeneric());383 384    if (!thread_or_error)385      return ScriptedInterface::ErrorWithMessage<bool>(386          LLVM_PRETTY_FUNCTION, toString(thread_or_error.takeError()), error);387 388    ThreadSP thread_sp = thread_or_error.get();389    lldbassert(thread_sp && "Couldn't initialize scripted thread.");390 391    RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext();392    if (!reg_ctx_sp)393      return ScriptedInterface::ErrorWithMessage<bool>(394          LLVM_PRETTY_FUNCTION,395          llvm::Twine("Invalid Register Context for thread " + llvm::Twine(idx))396              .str(),397          error);398 399    new_thread_list.AddThread(thread_sp);400 401    return true;402  };403 404  llvm::for_each(sorted_threads, create_scripted_thread);405 406  return new_thread_list.GetSize(false) > 0;407}408 409void ScriptedProcess::RefreshStateAfterStop() {410  // Let all threads recover from stopping and do any clean up based on the411  // previous thread state (if any).412  m_thread_list.RefreshStateAfterStop();413}414 415bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) {416  info.Clear();417  info.SetProcessID(GetID());418  info.SetArchitecture(GetArchitecture());419  lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();420  if (module_sp) {421    const bool add_exe_file_as_first_arg = false;422    info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),423                           add_exe_file_as_first_arg);424  }425  return true;426}427 428lldb_private::StructuredData::ObjectSP429ScriptedProcess::GetLoadedDynamicLibrariesInfos() {430  Status error;431  auto error_with_message = [&error](llvm::StringRef message) {432    return ScriptedInterface::ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,433                                                     message.data(), error);434  };435 436  StructuredData::ArraySP loaded_images_sp = GetInterface().GetLoadedImages();437 438  if (!loaded_images_sp || !loaded_images_sp->GetSize())439    return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(440        LLVM_PRETTY_FUNCTION, "No loaded images.", error);441 442  ModuleList module_list;443  Target &target = GetTarget();444 445  auto reload_image = [&target, &module_list, &error_with_message](446                          StructuredData::Object *obj) -> bool {447    StructuredData::Dictionary *dict = obj->GetAsDictionary();448 449    if (!dict)450      return error_with_message("Couldn't cast image object into dictionary.");451 452    ModuleSpec module_spec;453 454    bool has_path = dict->HasKey("path");455    bool has_uuid = dict->HasKey("uuid");456    if (!has_path && !has_uuid)457      return error_with_message("Dictionary should have key 'path' or 'uuid'");458    if (!dict->HasKey("load_addr"))459      return error_with_message("Dictionary is missing key 'load_addr'");460 461    llvm::StringRef path = "";462    if (has_path) {463      dict->GetValueForKeyAsString("path", path);464      module_spec.GetFileSpec().SetPath(path);465    }466 467    llvm::StringRef uuid = "";468    if (has_uuid) {469      dict->GetValueForKeyAsString("uuid", uuid);470      module_spec.GetUUID().SetFromStringRef(uuid);471    }472 473    lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;474    lldb::offset_t slide = LLDB_INVALID_OFFSET;475    dict->GetValueForKeyAsInteger("load_addr", load_addr);476    dict->GetValueForKeyAsInteger("slide", slide);477    if (load_addr == LLDB_INVALID_ADDRESS)478      return error_with_message(479          "Couldn't get valid load address or slide offset.");480 481    if (slide != LLDB_INVALID_OFFSET)482      load_addr += slide;483 484    module_spec.GetArchitecture() = target.GetArchitecture();485 486    ModuleSP module_sp =487        target.GetOrCreateModule(module_spec, true /* notify */);488 489    bool is_placeholder_module = false;490 491    if (!module_sp) {492      // Create a placeholder module493      LLDB_LOGF(494          GetLog(LLDBLog::Process),495          "ScriptedProcess::%s unable to locate the matching "496          "object file path %s, creating a placeholder module at 0x%" PRIx64,497          __FUNCTION__, path.str().c_str(), load_addr);498 499      module_sp = Module::CreateModuleFromObjectFile<ObjectFilePlaceholder>(500          module_spec, load_addr, module_spec.GetFileSpec().MemorySize());501 502      is_placeholder_module = true;503    }504 505    bool changed = false;506    module_sp->SetLoadAddress(target, load_addr, false /*=value_is_offset*/,507                              changed);508 509    if (!changed && !module_sp->GetObjectFile())510      return error_with_message("Couldn't set the load address for module.");511 512    FileSpec objfile(path);513    module_sp->SetFileSpecAndObjectName(objfile, objfile.GetFilename());514 515    if (is_placeholder_module) {516      target.GetImages().AppendIfNeeded(module_sp, true /*notify=*/);517      return true;518    }519 520    return module_list.AppendIfNeeded(module_sp);521  };522 523  size_t loaded_images_size = loaded_images_sp->GetSize();524  bool print_error = true;525  for (size_t idx = 0; idx < loaded_images_size; idx++) {526    const auto &loaded_image = loaded_images_sp->GetItemAtIndex(idx);527    if (!reload_image(loaded_image.get()) && print_error) {528      print_error = false;529      ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(530          LLVM_PRETTY_FUNCTION, "Couldn't reload all images.", error);531    }532  }533 534  target.ModulesDidLoad(module_list);535 536  return loaded_images_sp;537}538 539lldb_private::StructuredData::DictionarySP ScriptedProcess::GetMetadata() {540  StructuredData::DictionarySP metadata_sp = GetInterface().GetMetadata();541 542  Status error;543  if (!metadata_sp || !metadata_sp->GetSize())544    return ScriptedInterface::ErrorWithMessage<StructuredData::DictionarySP>(545        LLVM_PRETTY_FUNCTION, "No metadata.", error);546 547  return metadata_sp;548}549 550void ScriptedProcess::UpdateQueueListIfNeeded() {551  CheckScriptedInterface();552  for (ThreadSP thread_sp : Threads()) {553    if (const char *queue_name = thread_sp->GetQueueName()) {554      QueueSP queue_sp = std::make_shared<Queue>(555          m_process->shared_from_this(), thread_sp->GetQueueID(), queue_name);556      m_queue_list.AddQueue(queue_sp);557    }558  }559}560 561ScriptedProcessInterface &ScriptedProcess::GetInterface() const {562  CheckScriptedInterface();563  return *m_interface_up;564}565 566void *ScriptedProcess::GetImplementation() {567  StructuredData::GenericSP object_instance_sp =568      GetInterface().GetScriptObjectInstance();569  if (object_instance_sp &&570      object_instance_sp->GetType() == eStructuredDataTypeGeneric)571    return object_instance_sp->GetAsGeneric()->GetValue();572  return nullptr;573}574