Path: blob/main/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
39638 views
//===-- OperatingSystemPython.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 "lldb/Host/Config.h"910#if LLDB_ENABLE_PYTHON1112#include "OperatingSystemPython.h"1314#include "Plugins/Process/Utility/RegisterContextDummy.h"15#include "Plugins/Process/Utility/RegisterContextMemory.h"16#include "Plugins/Process/Utility/ThreadMemory.h"17#include "lldb/Core/Debugger.h"18#include "lldb/Core/Module.h"19#include "lldb/Core/PluginManager.h"20#include "lldb/Core/ValueObjectVariable.h"21#include "lldb/Interpreter/CommandInterpreter.h"22#include "lldb/Interpreter/ScriptInterpreter.h"23#include "lldb/Symbol/ObjectFile.h"24#include "lldb/Symbol/VariableList.h"25#include "lldb/Target/Process.h"26#include "lldb/Target/StopInfo.h"27#include "lldb/Target/Target.h"28#include "lldb/Target/Thread.h"29#include "lldb/Target/ThreadList.h"30#include "lldb/Utility/DataBufferHeap.h"31#include "lldb/Utility/LLDBLog.h"32#include "lldb/Utility/RegisterValue.h"33#include "lldb/Utility/StreamString.h"34#include "lldb/Utility/StructuredData.h"3536#include <memory>3738using namespace lldb;39using namespace lldb_private;4041LLDB_PLUGIN_DEFINE(OperatingSystemPython)4243void OperatingSystemPython::Initialize() {44PluginManager::RegisterPlugin(GetPluginNameStatic(),45GetPluginDescriptionStatic(), CreateInstance,46nullptr);47}4849void OperatingSystemPython::Terminate() {50PluginManager::UnregisterPlugin(CreateInstance);51}5253OperatingSystem *OperatingSystemPython::CreateInstance(Process *process,54bool force) {55// Python OperatingSystem plug-ins must be requested by name, so force must56// be true57FileSpec python_os_plugin_spec(process->GetPythonOSPluginPath());58if (python_os_plugin_spec &&59FileSystem::Instance().Exists(python_os_plugin_spec)) {60std::unique_ptr<OperatingSystemPython> os_up(61new OperatingSystemPython(process, python_os_plugin_spec));62if (os_up.get() && os_up->IsValid())63return os_up.release();64}65return nullptr;66}6768llvm::StringRef OperatingSystemPython::GetPluginDescriptionStatic() {69return "Operating system plug-in that gathers OS information from a python "70"class that implements the necessary OperatingSystem functionality.";71}7273OperatingSystemPython::OperatingSystemPython(lldb_private::Process *process,74const FileSpec &python_module_path)75: OperatingSystem(process), m_thread_list_valobj_sp(), m_register_info_up(),76m_interpreter(nullptr), m_script_object_sp() {77if (!process)78return;79TargetSP target_sp = process->CalculateTarget();80if (!target_sp)81return;82m_interpreter = target_sp->GetDebugger().GetScriptInterpreter();83if (!m_interpreter)84return;8586std::string os_plugin_class_name(87python_module_path.GetFilename().AsCString(""));88if (os_plugin_class_name.empty())89return;9091LoadScriptOptions options;92char python_module_path_cstr[PATH_MAX];93python_module_path.GetPath(python_module_path_cstr,94sizeof(python_module_path_cstr));95Status error;96if (!m_interpreter->LoadScriptingModule(python_module_path_cstr, options,97error))98return;99100// Strip the ".py" extension if there is one101size_t py_extension_pos = os_plugin_class_name.rfind(".py");102if (py_extension_pos != std::string::npos)103os_plugin_class_name.erase(py_extension_pos);104// Add ".OperatingSystemPlugIn" to the module name to get a string like105// "modulename.OperatingSystemPlugIn"106os_plugin_class_name += ".OperatingSystemPlugIn";107108auto operating_system_interface =109m_interpreter->CreateOperatingSystemInterface();110if (!operating_system_interface)111// FIXME: We should pass an Status& to raise the error to the user.112// return llvm::createStringError(113// llvm::inconvertibleErrorCode(),114// "Failed to create scripted thread interface.");115return;116117ExecutionContext exe_ctx(process);118auto obj_or_err = operating_system_interface->CreatePluginObject(119os_plugin_class_name, exe_ctx, nullptr);120121if (!obj_or_err) {122llvm::consumeError(obj_or_err.takeError());123return;124}125126StructuredData::GenericSP owned_script_object_sp = *obj_or_err;127if (!owned_script_object_sp->IsValid())128// return llvm::createStringError(llvm::inconvertibleErrorCode(),129// "Created script object is invalid.");130return;131132m_script_object_sp = owned_script_object_sp;133m_operating_system_interface_sp = operating_system_interface;134}135136OperatingSystemPython::~OperatingSystemPython() = default;137138DynamicRegisterInfo *OperatingSystemPython::GetDynamicRegisterInfo() {139if (m_register_info_up == nullptr) {140if (!m_interpreter || !m_operating_system_interface_sp)141return nullptr;142Log *log = GetLog(LLDBLog::OS);143144LLDB_LOGF(log,145"OperatingSystemPython::GetDynamicRegisterInfo() fetching "146"thread register definitions from python for pid %" PRIu64,147m_process->GetID());148149StructuredData::DictionarySP dictionary =150m_operating_system_interface_sp->GetRegisterInfo();151if (!dictionary)152return nullptr;153154m_register_info_up = DynamicRegisterInfo::Create(155*dictionary, m_process->GetTarget().GetArchitecture());156assert(m_register_info_up);157assert(m_register_info_up->GetNumRegisters() > 0);158assert(m_register_info_up->GetNumRegisterSets() > 0);159}160return m_register_info_up.get();161}162163bool OperatingSystemPython::UpdateThreadList(ThreadList &old_thread_list,164ThreadList &core_thread_list,165ThreadList &new_thread_list) {166if (!m_interpreter || !m_operating_system_interface_sp)167return false;168169Log *log = GetLog(LLDBLog::OS);170171LLDB_LOGF(log,172"OperatingSystemPython::UpdateThreadList() fetching thread "173"data from python for pid %" PRIu64,174m_process->GetID());175176// The threads that are in "core_thread_list" upon entry are the threads from177// the lldb_private::Process subclass, no memory threads will be in this178// list.179StructuredData::ArraySP threads_list =180m_operating_system_interface_sp->GetThreadInfo();181182const uint32_t num_cores = core_thread_list.GetSize(false);183184// Make a map so we can keep track of which cores were used from the185// core_thread list. Any real threads/cores that weren't used should later be186// put back into the "new_thread_list".187std::vector<bool> core_used_map(num_cores, false);188if (threads_list) {189if (log) {190StreamString strm;191threads_list->Dump(strm);192LLDB_LOGF(log, "threads_list = %s", strm.GetData());193}194195const uint32_t num_threads = threads_list->GetSize();196for (uint32_t i = 0; i < num_threads; ++i) {197StructuredData::ObjectSP thread_dict_obj =198threads_list->GetItemAtIndex(i);199if (auto thread_dict = thread_dict_obj->GetAsDictionary()) {200ThreadSP thread_sp(CreateThreadFromThreadInfo(201*thread_dict, core_thread_list, old_thread_list, core_used_map,202nullptr));203if (thread_sp)204new_thread_list.AddThread(thread_sp);205}206}207}208209// Any real core threads that didn't end up backing a memory thread should210// still be in the main thread list, and they should be inserted at the211// beginning of the list212uint32_t insert_idx = 0;213for (uint32_t core_idx = 0; core_idx < num_cores; ++core_idx) {214if (!core_used_map[core_idx]) {215new_thread_list.InsertThread(216core_thread_list.GetThreadAtIndex(core_idx, false), insert_idx);217++insert_idx;218}219}220221return new_thread_list.GetSize(false) > 0;222}223224ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo(225StructuredData::Dictionary &thread_dict, ThreadList &core_thread_list,226ThreadList &old_thread_list, std::vector<bool> &core_used_map,227bool *did_create_ptr) {228ThreadSP thread_sp;229tid_t tid = LLDB_INVALID_THREAD_ID;230if (!thread_dict.GetValueForKeyAsInteger("tid", tid))231return ThreadSP();232233uint32_t core_number;234addr_t reg_data_addr;235llvm::StringRef name;236llvm::StringRef queue;237238thread_dict.GetValueForKeyAsInteger("core", core_number, UINT32_MAX);239thread_dict.GetValueForKeyAsInteger("register_data_addr", reg_data_addr,240LLDB_INVALID_ADDRESS);241thread_dict.GetValueForKeyAsString("name", name);242thread_dict.GetValueForKeyAsString("queue", queue);243244// See if a thread already exists for "tid"245thread_sp = old_thread_list.FindThreadByID(tid, false);246if (thread_sp) {247// A thread already does exist for "tid", make sure it was an operating248// system249// plug-in generated thread.250if (!IsOperatingSystemPluginThread(thread_sp)) {251// We have thread ID overlap between the protocol threads and the252// operating system threads, clear the thread so we create an operating253// system thread for this.254thread_sp.reset();255}256}257258if (!thread_sp) {259if (did_create_ptr)260*did_create_ptr = true;261thread_sp = std::make_shared<ThreadMemory>(*m_process, tid, name, queue,262reg_data_addr);263}264265if (core_number < core_thread_list.GetSize(false)) {266ThreadSP core_thread_sp(267core_thread_list.GetThreadAtIndex(core_number, false));268if (core_thread_sp) {269// Keep track of which cores were set as the backing thread for memory270// threads...271if (core_number < core_used_map.size())272core_used_map[core_number] = true;273274ThreadSP backing_core_thread_sp(core_thread_sp->GetBackingThread());275if (backing_core_thread_sp) {276thread_sp->SetBackingThread(backing_core_thread_sp);277} else {278thread_sp->SetBackingThread(core_thread_sp);279}280}281}282return thread_sp;283}284285void OperatingSystemPython::ThreadWasSelected(Thread *thread) {}286287RegisterContextSP288OperatingSystemPython::CreateRegisterContextForThread(Thread *thread,289addr_t reg_data_addr) {290RegisterContextSP reg_ctx_sp;291if (!m_interpreter || !m_script_object_sp || !thread)292return reg_ctx_sp;293294if (!IsOperatingSystemPluginThread(thread->shared_from_this()))295return reg_ctx_sp;296297Log *log = GetLog(LLDBLog::Thread);298299if (reg_data_addr != LLDB_INVALID_ADDRESS) {300// The registers data is in contiguous memory, just create the register301// context using the address provided302LLDB_LOGF(log,303"OperatingSystemPython::CreateRegisterContextForThread (tid "304"= 0x%" PRIx64 ", 0x%" PRIx64 ", reg_data_addr = 0x%" PRIx64305") creating memory register context",306thread->GetID(), thread->GetProtocolID(), reg_data_addr);307reg_ctx_sp = std::make_shared<RegisterContextMemory>(308*thread, 0, *GetDynamicRegisterInfo(), reg_data_addr);309} else {310// No register data address is provided, query the python plug-in to let it311// make up the data as it sees fit312LLDB_LOGF(log,313"OperatingSystemPython::CreateRegisterContextForThread (tid "314"= 0x%" PRIx64 ", 0x%" PRIx64315") fetching register data from python",316thread->GetID(), thread->GetProtocolID());317318std::optional<std::string> reg_context_data =319m_operating_system_interface_sp->GetRegisterContextForTID(320thread->GetID());321if (reg_context_data) {322std::string value = *reg_context_data;323DataBufferSP data_sp(new DataBufferHeap(value.c_str(), value.length()));324if (data_sp->GetByteSize()) {325RegisterContextMemory *reg_ctx_memory = new RegisterContextMemory(326*thread, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);327if (reg_ctx_memory) {328reg_ctx_sp.reset(reg_ctx_memory);329reg_ctx_memory->SetAllRegisterData(data_sp);330}331}332}333}334// if we still have no register data, fallback on a dummy context to avoid335// crashing336if (!reg_ctx_sp) {337LLDB_LOGF(log,338"OperatingSystemPython::CreateRegisterContextForThread (tid "339"= 0x%" PRIx64 ") forcing a dummy register context",340thread->GetID());341Target &target = m_process->GetTarget();342reg_ctx_sp = std::make_shared<RegisterContextDummy>(343*thread, 0, target.GetArchitecture().GetAddressByteSize());344}345return reg_ctx_sp;346}347348StopInfoSP349OperatingSystemPython::CreateThreadStopReason(lldb_private::Thread *thread) {350// We should have gotten the thread stop info from the dictionary of data for351// the thread in the initial call to get_thread_info(), this should have been352// cached so we can return it here353StopInfoSP354stop_info_sp; //(StopInfo::CreateStopReasonWithSignal (*thread, SIGSTOP));355return stop_info_sp;356}357358lldb::ThreadSP OperatingSystemPython::CreateThread(lldb::tid_t tid,359addr_t context) {360Log *log = GetLog(LLDBLog::Thread);361362LLDB_LOGF(log,363"OperatingSystemPython::CreateThread (tid = 0x%" PRIx64364", context = 0x%" PRIx64 ") fetching register data from python",365tid, context);366367if (m_interpreter && m_script_object_sp) {368369StructuredData::DictionarySP thread_info_dict =370m_operating_system_interface_sp->CreateThread(tid, context);371372std::vector<bool> core_used_map;373if (thread_info_dict) {374ThreadList core_threads(*m_process);375ThreadList &thread_list = m_process->GetThreadList();376bool did_create = false;377ThreadSP thread_sp(378CreateThreadFromThreadInfo(*thread_info_dict, core_threads,379thread_list, core_used_map, &did_create));380if (did_create)381thread_list.AddThread(thread_sp);382return thread_sp;383}384}385return ThreadSP();386}387388#endif // #if LLDB_ENABLE_PYTHON389390391