Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,2 @@
add_subdirectory(Go)
add_subdirectory(Python)

View File

@@ -0,0 +1,10 @@
add_lldb_library(lldbPluginOSGo PLUGIN
OperatingSystemGo.cpp
LINK_LIBS
lldbCore
lldbInterpreter
lldbSymbol
lldbTarget
lldbPluginProcessUtility
)

View File

@@ -0,0 +1,499 @@
//===-- OperatingSystemGo.cpp -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
#include <unordered_map>
// Other libraries and framework includes
// Project includes
#include "OperatingSystemGo.h"
#include "Plugins/Process/Utility/DynamicRegisterInfo.h"
#include "Plugins/Process/Utility/RegisterContextMemory.h"
#include "Plugins/Process/Utility/ThreadMemory.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/OptionGroupBoolean.h"
#include "lldb/Interpreter/OptionGroupUInt64.h"
#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Interpreter/Options.h"
#include "lldb/Interpreter/Property.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadList.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
namespace {
static PropertyDefinition g_properties[] = {
{"enable", OptionValue::eTypeBoolean, true, true, nullptr, nullptr,
"Specify whether goroutines should be treated as threads."},
{NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}};
enum {
ePropertyEnableGoroutines,
};
class PluginProperties : public Properties {
public:
PluginProperties() : Properties() {
m_collection_sp.reset(new OptionValueProperties(GetSettingName()));
m_collection_sp->Initialize(g_properties);
}
~PluginProperties() override = default;
static ConstString GetSettingName() {
return OperatingSystemGo::GetPluginNameStatic();
}
bool GetEnableGoroutines() {
const uint32_t idx = ePropertyEnableGoroutines;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
NULL, idx, g_properties[idx].default_uint_value);
}
bool SetEnableGoroutines(bool enable) {
const uint32_t idx = ePropertyEnableGoroutines;
return m_collection_sp->SetPropertyAtIndexAsUInt64(NULL, idx, enable);
}
};
typedef std::shared_ptr<PluginProperties> OperatingSystemGoPropertiesSP;
static const OperatingSystemGoPropertiesSP &GetGlobalPluginProperties() {
static OperatingSystemGoPropertiesSP g_settings_sp;
if (!g_settings_sp)
g_settings_sp.reset(new PluginProperties());
return g_settings_sp;
}
class RegisterContextGo : public RegisterContextMemory {
public:
RegisterContextGo(lldb_private::Thread &thread, uint32_t concrete_frame_idx,
DynamicRegisterInfo &reg_info, lldb::addr_t reg_data_addr)
: RegisterContextMemory(thread, concrete_frame_idx, reg_info,
reg_data_addr) {
const RegisterInfo *sp = reg_info.GetRegisterInfoAtIndex(
reg_info.ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_SP));
const RegisterInfo *pc = reg_info.GetRegisterInfoAtIndex(
reg_info.ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_PC));
size_t byte_size = std::max(sp->byte_offset + sp->byte_size,
pc->byte_offset + pc->byte_size);
DataBufferSP reg_data_sp(new DataBufferHeap(byte_size, 0));
m_reg_data.SetData(reg_data_sp);
}
~RegisterContextGo() override = default;
bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
lldb_private::RegisterValue &reg_value) override {
switch (reg_info->kinds[eRegisterKindGeneric]) {
case LLDB_REGNUM_GENERIC_SP:
case LLDB_REGNUM_GENERIC_PC:
return RegisterContextMemory::ReadRegister(reg_info, reg_value);
default:
reg_value.SetValueToInvalid();
return true;
}
}
bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
const lldb_private::RegisterValue &reg_value) override {
switch (reg_info->kinds[eRegisterKindGeneric]) {
case LLDB_REGNUM_GENERIC_SP:
case LLDB_REGNUM_GENERIC_PC:
return RegisterContextMemory::WriteRegister(reg_info, reg_value);
default:
return false;
}
}
private:
DISALLOW_COPY_AND_ASSIGN(RegisterContextGo);
};
} // anonymous namespace
struct OperatingSystemGo::Goroutine {
uint64_t m_lostack;
uint64_t m_histack;
uint64_t m_goid;
addr_t m_gobuf;
uint32_t m_status;
};
void OperatingSystemGo::Initialize() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(), CreateInstance,
DebuggerInitialize);
}
void OperatingSystemGo::DebuggerInitialize(Debugger &debugger) {
if (!PluginManager::GetSettingForOperatingSystemPlugin(
debugger, PluginProperties::GetSettingName())) {
const bool is_global_setting = true;
PluginManager::CreateSettingForOperatingSystemPlugin(
debugger, GetGlobalPluginProperties()->GetValueProperties(),
ConstString("Properties for the goroutine thread plug-in."),
is_global_setting);
}
}
void OperatingSystemGo::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}
OperatingSystem *OperatingSystemGo::CreateInstance(Process *process,
bool force) {
if (!force) {
TargetSP target_sp = process->CalculateTarget();
if (!target_sp)
return nullptr;
ModuleList &module_list = target_sp->GetImages();
std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
const size_t num_modules = module_list.GetSize();
bool found_go_runtime = false;
for (size_t i = 0; i < num_modules; ++i) {
Module *module = module_list.GetModulePointerAtIndexUnlocked(i);
const SectionList *section_list = module->GetSectionList();
if (section_list) {
SectionSP section_sp(
section_list->FindSectionByType(eSectionTypeGoSymtab, true));
if (section_sp) {
found_go_runtime = true;
break;
}
}
}
if (!found_go_runtime)
return nullptr;
}
return new OperatingSystemGo(process);
}
OperatingSystemGo::OperatingSystemGo(lldb_private::Process *process)
: OperatingSystem(process), m_reginfo(new DynamicRegisterInfo) {}
OperatingSystemGo::~OperatingSystemGo() = default;
ConstString OperatingSystemGo::GetPluginNameStatic() {
static ConstString g_name("goroutines");
return g_name;
}
const char *OperatingSystemGo::GetPluginDescriptionStatic() {
return "Operating system plug-in that reads runtime data-structures for "
"goroutines.";
}
bool OperatingSystemGo::Init(ThreadList &threads) {
if (threads.GetSize(false) < 1)
return false;
TargetSP target_sp = m_process->CalculateTarget();
if (!target_sp)
return false;
// Go 1.6 stores goroutines in a slice called runtime.allgs
ValueObjectSP allgs_sp = FindGlobal(target_sp, "runtime.allgs");
if (allgs_sp) {
m_allg_sp = allgs_sp->GetChildMemberWithName(ConstString("array"), true);
m_allglen_sp = allgs_sp->GetChildMemberWithName(ConstString("len"), true);
} else {
// Go 1.4 stores goroutines in the variable runtime.allg.
m_allg_sp = FindGlobal(target_sp, "runtime.allg");
m_allglen_sp = FindGlobal(target_sp, "runtime.allglen");
}
if (m_allg_sp && !m_allglen_sp) {
StreamSP error_sp = target_sp->GetDebugger().GetAsyncErrorStream();
error_sp->Printf("Unsupported Go runtime version detected.");
return false;
}
if (!m_allg_sp)
return false;
RegisterContextSP real_registers_sp =
threads.GetThreadAtIndex(0, false)->GetRegisterContext();
std::unordered_map<size_t, ConstString> register_sets;
for (size_t set_idx = 0; set_idx < real_registers_sp->GetRegisterSetCount();
++set_idx) {
const RegisterSet *set = real_registers_sp->GetRegisterSet(set_idx);
ConstString name(set->name);
for (size_t reg_idx = 0; reg_idx < set->num_registers; ++reg_idx) {
register_sets[reg_idx] = name;
}
}
TypeSP gobuf_sp = FindType(target_sp, "runtime.gobuf");
if (!gobuf_sp) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS));
if (log)
log->Printf("OperatingSystemGo unable to find struct Gobuf");
return false;
}
CompilerType gobuf_type(gobuf_sp->GetLayoutCompilerType());
for (size_t idx = 0; idx < real_registers_sp->GetRegisterCount(); ++idx) {
RegisterInfo reg = *real_registers_sp->GetRegisterInfoAtIndex(idx);
int field_index = -1;
if (reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_SP) {
field_index = 0;
} else if (reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC) {
field_index = 1;
}
if (field_index == -1) {
reg.byte_offset = ~0;
} else {
std::string field_name;
uint64_t bit_offset = 0;
CompilerType field_type = gobuf_type.GetFieldAtIndex(
field_index, field_name, &bit_offset, nullptr, nullptr);
reg.byte_size = field_type.GetByteSize(nullptr);
reg.byte_offset = bit_offset / 8;
}
ConstString name(reg.name);
ConstString alt_name(reg.alt_name);
m_reginfo->AddRegister(reg, name, alt_name, register_sets[idx]);
}
return true;
}
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
ConstString OperatingSystemGo::GetPluginName() { return GetPluginNameStatic(); }
uint32_t OperatingSystemGo::GetPluginVersion() { return 1; }
bool OperatingSystemGo::UpdateThreadList(ThreadList &old_thread_list,
ThreadList &real_thread_list,
ThreadList &new_thread_list) {
new_thread_list = real_thread_list;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS));
if (!(m_allg_sp || Init(real_thread_list)) || (m_allg_sp && !m_allglen_sp) ||
!GetGlobalPluginProperties()->GetEnableGoroutines()) {
return new_thread_list.GetSize(false) > 0;
}
if (log)
log->Printf("OperatingSystemGo::UpdateThreadList(%d, %d, %d) fetching "
"thread data from Go for pid %" PRIu64,
old_thread_list.GetSize(false), real_thread_list.GetSize(false),
new_thread_list.GetSize(0), m_process->GetID());
uint64_t allglen = m_allglen_sp->GetValueAsUnsigned(0);
if (allglen == 0) {
return new_thread_list.GetSize(false) > 0;
}
std::vector<Goroutine> goroutines;
// The threads that are in "new_thread_list" upon entry are the threads from
// the
// lldb_private::Process subclass, no memory threads will be in this list.
Status err;
for (uint64_t i = 0; i < allglen; ++i) {
goroutines.push_back(CreateGoroutineAtIndex(i, err));
if (err.Fail()) {
LLDB_LOG(log, "error: {0}", err);
return new_thread_list.GetSize(false) > 0;
}
}
// Make a map so we can match goroutines with backing threads.
std::map<uint64_t, ThreadSP> stack_map;
for (uint32_t i = 0; i < real_thread_list.GetSize(false); ++i) {
ThreadSP thread = real_thread_list.GetThreadAtIndex(i, false);
stack_map[thread->GetRegisterContext()->GetSP()] = thread;
}
for (const Goroutine &goroutine : goroutines) {
if (0 /* Gidle */ == goroutine.m_status ||
6 /* Gdead */ == goroutine.m_status) {
continue;
}
ThreadSP memory_thread =
old_thread_list.FindThreadByID(goroutine.m_goid, false);
if (memory_thread && IsOperatingSystemPluginThread(memory_thread) &&
memory_thread->IsValid()) {
memory_thread->ClearBackingThread();
} else {
memory_thread.reset(new ThreadMemory(*m_process, goroutine.m_goid, "", "",
goroutine.m_gobuf));
}
// Search for the backing thread if the goroutine is running.
if (2 == (goroutine.m_status & 0xfff)) {
auto backing_it = stack_map.lower_bound(goroutine.m_lostack);
if (backing_it != stack_map.end()) {
if (goroutine.m_histack >= backing_it->first) {
if (log)
log->Printf(
"OperatingSystemGo::UpdateThreadList found backing thread "
"%" PRIx64 " (%" PRIx64 ") for thread %" PRIx64 "",
backing_it->second->GetID(),
backing_it->second->GetProtocolID(), memory_thread->GetID());
memory_thread->SetBackingThread(backing_it->second);
new_thread_list.RemoveThreadByID(backing_it->second->GetID(), false);
}
}
}
new_thread_list.AddThread(memory_thread);
}
return new_thread_list.GetSize(false) > 0;
}
void OperatingSystemGo::ThreadWasSelected(Thread *thread) {}
RegisterContextSP
OperatingSystemGo::CreateRegisterContextForThread(Thread *thread,
addr_t reg_data_addr) {
RegisterContextSP reg_ctx_sp;
if (!thread)
return reg_ctx_sp;
if (!IsOperatingSystemPluginThread(thread->shared_from_this()))
return reg_ctx_sp;
reg_ctx_sp.reset(
new RegisterContextGo(*thread, 0, *m_reginfo, reg_data_addr));
return reg_ctx_sp;
}
StopInfoSP
OperatingSystemGo::CreateThreadStopReason(lldb_private::Thread *thread) {
StopInfoSP stop_info_sp;
return stop_info_sp;
}
lldb::ThreadSP OperatingSystemGo::CreateThread(lldb::tid_t tid,
addr_t context) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS));
if (log)
log->Printf("OperatingSystemGo::CreateThread (tid = 0x%" PRIx64
", context = 0x%" PRIx64 ") not implemented",
tid, context);
return ThreadSP();
}
ValueObjectSP OperatingSystemGo::FindGlobal(TargetSP target, const char *name) {
VariableList variable_list;
const bool append = true;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS));
if (log) {
log->Printf(
"exe: %s",
target->GetExecutableModule()->GetSpecificationDescription().c_str());
log->Printf("modules: %zu", target->GetImages().GetSize());
}
uint32_t match_count = target->GetImages().FindGlobalVariables(
ConstString(name), append, 1, variable_list);
if (match_count > 0) {
ExecutionContextScope *exe_scope = target->GetProcessSP().get();
if (exe_scope == NULL)
exe_scope = target.get();
return ValueObjectVariable::Create(exe_scope,
variable_list.GetVariableAtIndex(0));
}
return ValueObjectSP();
}
TypeSP OperatingSystemGo::FindType(TargetSP target_sp, const char *name) {
ConstString const_typename(name);
SymbolContext sc;
const bool exact_match = false;
const ModuleList &module_list = target_sp->GetImages();
size_t count = module_list.GetSize();
for (size_t idx = 0; idx < count; idx++) {
ModuleSP module_sp(module_list.GetModuleAtIndex(idx));
if (module_sp) {
TypeSP type_sp(module_sp->FindFirstType(sc, const_typename, exact_match));
if (type_sp)
return type_sp;
}
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS));
if (log)
log->Printf("OperatingSystemGo::FindType(%s): not found", name);
return TypeSP();
}
OperatingSystemGo::Goroutine
OperatingSystemGo::CreateGoroutineAtIndex(uint64_t idx, Status &err) {
err.Clear();
Goroutine result = {};
ValueObjectSP g =
m_allg_sp->GetSyntheticArrayMember(idx, true)->Dereference(err);
if (err.Fail()) {
return result;
}
ConstString name("goid");
ValueObjectSP val = g->GetChildMemberWithName(name, true);
bool success = false;
result.m_goid = val->GetValueAsUnsigned(0, &success);
if (!success) {
err.SetErrorToGenericError();
err.SetErrorString("unable to read goid");
return result;
}
name.SetCString("atomicstatus");
val = g->GetChildMemberWithName(name, true);
result.m_status = (uint32_t)val->GetValueAsUnsigned(0, &success);
if (!success) {
err.SetErrorToGenericError();
err.SetErrorString("unable to read atomicstatus");
return result;
}
name.SetCString("sched");
val = g->GetChildMemberWithName(name, true);
result.m_gobuf = val->GetAddressOf(false);
name.SetCString("stack");
val = g->GetChildMemberWithName(name, true);
name.SetCString("lo");
ValueObjectSP child = val->GetChildMemberWithName(name, true);
result.m_lostack = child->GetValueAsUnsigned(0, &success);
if (!success) {
err.SetErrorToGenericError();
err.SetErrorString("unable to read stack.lo");
return result;
}
name.SetCString("hi");
child = val->GetChildMemberWithName(name, true);
result.m_histack = child->GetValueAsUnsigned(0, &success);
if (!success) {
err.SetErrorToGenericError();
err.SetErrorString("unable to read stack.hi");
return result;
}
return result;
}

View File

@@ -0,0 +1,90 @@
//===-- OperatingSystemGo.h -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef _liblldb_OperatingSystemGo_h_
#define _liblldb_OperatingSystemGo_h_
// C Includes
// C++ Includes
#include <memory>
// Other libraries and framework includes
// Project includes
#include "lldb/Target/OperatingSystem.h"
class DynamicRegisterInfo;
class OperatingSystemGo : public lldb_private::OperatingSystem {
public:
OperatingSystemGo(lldb_private::Process *process);
~OperatingSystemGo() override;
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
static lldb_private::OperatingSystem *
CreateInstance(lldb_private::Process *process, bool force);
static void Initialize();
static void DebuggerInitialize(lldb_private::Debugger &debugger);
static void Terminate();
static lldb_private::ConstString GetPluginNameStatic();
static const char *GetPluginDescriptionStatic();
//------------------------------------------------------------------
// lldb_private::PluginInterface Methods
//------------------------------------------------------------------
lldb_private::ConstString GetPluginName() override;
uint32_t GetPluginVersion() override;
//------------------------------------------------------------------
// lldb_private::OperatingSystem Methods
//------------------------------------------------------------------
bool UpdateThreadList(lldb_private::ThreadList &old_thread_list,
lldb_private::ThreadList &real_thread_list,
lldb_private::ThreadList &new_thread_list) override;
void ThreadWasSelected(lldb_private::Thread *thread) override;
lldb::RegisterContextSP
CreateRegisterContextForThread(lldb_private::Thread *thread,
lldb::addr_t reg_data_addr) override;
lldb::StopInfoSP
CreateThreadStopReason(lldb_private::Thread *thread) override;
//------------------------------------------------------------------
// Method for lazy creation of threads on demand
//------------------------------------------------------------------
lldb::ThreadSP CreateThread(lldb::tid_t tid, lldb::addr_t context) override;
private:
struct Goroutine;
static lldb::ValueObjectSP FindGlobal(lldb::TargetSP target,
const char *name);
static lldb::TypeSP FindType(lldb::TargetSP target_sp, const char *name);
bool Init(lldb_private::ThreadList &threads);
Goroutine CreateGoroutineAtIndex(uint64_t idx, lldb_private::Status &err);
std::unique_ptr<DynamicRegisterInfo> m_reginfo;
lldb::ValueObjectSP m_allg_sp;
lldb::ValueObjectSP m_allglen_sp;
};
#endif // liblldb_OperatingSystemGo_h_

View File

@@ -0,0 +1,10 @@
add_lldb_library(lldbPluginOSPython PLUGIN
OperatingSystemPython.cpp
LINK_LIBS
lldbCore
lldbInterpreter
lldbSymbol
lldbTarget
lldbPluginProcessUtility
)

View File

@@ -0,0 +1,416 @@
//===-- OperatingSystemPython.cpp --------------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_DISABLE_PYTHON
#include "OperatingSystemPython.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
#include "Plugins/Process/Utility/DynamicRegisterInfo.h"
#include "Plugins/Process/Utility/RegisterContextDummy.h"
#include "Plugins/Process/Utility/RegisterContextMemory.h"
#include "Plugins/Process/Utility/ThreadMemory.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadList.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StructuredData.h"
using namespace lldb;
using namespace lldb_private;
void OperatingSystemPython::Initialize() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(), CreateInstance,
nullptr);
}
void OperatingSystemPython::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}
OperatingSystem *OperatingSystemPython::CreateInstance(Process *process,
bool force) {
// Python OperatingSystem plug-ins must be requested by name, so force must be
// true
FileSpec python_os_plugin_spec(process->GetPythonOSPluginPath());
if (python_os_plugin_spec && python_os_plugin_spec.Exists()) {
std::unique_ptr<OperatingSystemPython> os_ap(
new OperatingSystemPython(process, python_os_plugin_spec));
if (os_ap.get() && os_ap->IsValid())
return os_ap.release();
}
return NULL;
}
ConstString OperatingSystemPython::GetPluginNameStatic() {
static ConstString g_name("python");
return g_name;
}
const char *OperatingSystemPython::GetPluginDescriptionStatic() {
return "Operating system plug-in that gathers OS information from a python "
"class that implements the necessary OperatingSystem functionality.";
}
OperatingSystemPython::OperatingSystemPython(lldb_private::Process *process,
const FileSpec &python_module_path)
: OperatingSystem(process), m_thread_list_valobj_sp(), m_register_info_ap(),
m_interpreter(NULL), m_python_object_sp() {
if (!process)
return;
TargetSP target_sp = process->CalculateTarget();
if (!target_sp)
return;
m_interpreter =
target_sp->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
if (m_interpreter) {
std::string os_plugin_class_name(
python_module_path.GetFilename().AsCString(""));
if (!os_plugin_class_name.empty()) {
const bool init_session = false;
const bool allow_reload = true;
char python_module_path_cstr[PATH_MAX];
python_module_path.GetPath(python_module_path_cstr,
sizeof(python_module_path_cstr));
Status error;
if (m_interpreter->LoadScriptingModule(
python_module_path_cstr, allow_reload, init_session, error)) {
// Strip the ".py" extension if there is one
size_t py_extension_pos = os_plugin_class_name.rfind(".py");
if (py_extension_pos != std::string::npos)
os_plugin_class_name.erase(py_extension_pos);
// Add ".OperatingSystemPlugIn" to the module name to get a string like
// "modulename.OperatingSystemPlugIn"
os_plugin_class_name += ".OperatingSystemPlugIn";
StructuredData::ObjectSP object_sp =
m_interpreter->OSPlugin_CreatePluginObject(
os_plugin_class_name.c_str(), process->CalculateProcess());
if (object_sp && object_sp->IsValid())
m_python_object_sp = object_sp;
}
}
}
}
OperatingSystemPython::~OperatingSystemPython() {}
DynamicRegisterInfo *OperatingSystemPython::GetDynamicRegisterInfo() {
if (m_register_info_ap.get() == NULL) {
if (!m_interpreter || !m_python_object_sp)
return NULL;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS));
if (log)
log->Printf("OperatingSystemPython::GetDynamicRegisterInfo() fetching "
"thread register definitions from python for pid %" PRIu64,
m_process->GetID());
StructuredData::DictionarySP dictionary =
m_interpreter->OSPlugin_RegisterInfo(m_python_object_sp);
if (!dictionary)
return NULL;
m_register_info_ap.reset(new DynamicRegisterInfo(
*dictionary, m_process->GetTarget().GetArchitecture()));
assert(m_register_info_ap->GetNumRegisters() > 0);
assert(m_register_info_ap->GetNumRegisterSets() > 0);
}
return m_register_info_ap.get();
}
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
ConstString OperatingSystemPython::GetPluginName() {
return GetPluginNameStatic();
}
uint32_t OperatingSystemPython::GetPluginVersion() { return 1; }
bool OperatingSystemPython::UpdateThreadList(ThreadList &old_thread_list,
ThreadList &core_thread_list,
ThreadList &new_thread_list) {
if (!m_interpreter || !m_python_object_sp)
return false;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS));
// First thing we have to do is to try to get the API lock, and the run lock.
// We're going to change the thread content of the process, and we're going
// to use python, which requires the API lock to do it.
//
// If someone already has the API lock, that is ok, we just want to avoid
// external code from making new API calls while this call is happening.
//
// This is a recursive lock so we can grant it to any Python code called on
// the stack below us.
Target &target = m_process->GetTarget();
std::unique_lock<std::recursive_mutex> lock(target.GetAPIMutex(),
std::defer_lock);
lock.try_lock();
if (log)
log->Printf("OperatingSystemPython::UpdateThreadList() fetching thread "
"data from python for pid %" PRIu64,
m_process->GetID());
// The threads that are in "new_thread_list" upon entry are the threads from
// the
// lldb_private::Process subclass, no memory threads will be in this list.
auto interpreter_lock =
m_interpreter
->AcquireInterpreterLock(); // to make sure threads_list stays alive
StructuredData::ArraySP threads_list =
m_interpreter->OSPlugin_ThreadsInfo(m_python_object_sp);
const uint32_t num_cores = core_thread_list.GetSize(false);
// Make a map so we can keep track of which cores were used from the
// core_thread list. Any real threads/cores that weren't used should
// later be put back into the "new_thread_list".
std::vector<bool> core_used_map(num_cores, false);
if (threads_list) {
if (log) {
StreamString strm;
threads_list->Dump(strm);
log->Printf("threads_list = %s", strm.GetData());
}
const uint32_t num_threads = threads_list->GetSize();
for (uint32_t i = 0; i < num_threads; ++i) {
StructuredData::ObjectSP thread_dict_obj =
threads_list->GetItemAtIndex(i);
if (auto thread_dict = thread_dict_obj->GetAsDictionary()) {
ThreadSP thread_sp(
CreateThreadFromThreadInfo(*thread_dict, core_thread_list,
old_thread_list, core_used_map, NULL));
if (thread_sp)
new_thread_list.AddThread(thread_sp);
}
}
}
// Any real core threads that didn't end up backing a memory thread should
// still be in the main thread list, and they should be inserted at the
// beginning
// of the list
uint32_t insert_idx = 0;
for (uint32_t core_idx = 0; core_idx < num_cores; ++core_idx) {
if (core_used_map[core_idx] == false) {
new_thread_list.InsertThread(
core_thread_list.GetThreadAtIndex(core_idx, false), insert_idx);
++insert_idx;
}
}
return new_thread_list.GetSize(false) > 0;
}
ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo(
StructuredData::Dictionary &thread_dict, ThreadList &core_thread_list,
ThreadList &old_thread_list, std::vector<bool> &core_used_map,
bool *did_create_ptr) {
ThreadSP thread_sp;
tid_t tid = LLDB_INVALID_THREAD_ID;
if (!thread_dict.GetValueForKeyAsInteger("tid", tid))
return ThreadSP();
uint32_t core_number;
addr_t reg_data_addr;
llvm::StringRef name;
llvm::StringRef queue;
thread_dict.GetValueForKeyAsInteger("core", core_number, UINT32_MAX);
thread_dict.GetValueForKeyAsInteger("register_data_addr", reg_data_addr,
LLDB_INVALID_ADDRESS);
thread_dict.GetValueForKeyAsString("name", name);
thread_dict.GetValueForKeyAsString("queue", queue);
// See if a thread already exists for "tid"
thread_sp = old_thread_list.FindThreadByID(tid, false);
if (thread_sp) {
// A thread already does exist for "tid", make sure it was an operating
// system
// plug-in generated thread.
if (!IsOperatingSystemPluginThread(thread_sp)) {
// We have thread ID overlap between the protocol threads and the
// operating system threads, clear the thread so we create an
// operating system thread for this.
thread_sp.reset();
}
}
if (!thread_sp) {
if (did_create_ptr)
*did_create_ptr = true;
thread_sp.reset(
new ThreadMemory(*m_process, tid, name, queue, reg_data_addr));
}
if (core_number < core_thread_list.GetSize(false)) {
ThreadSP core_thread_sp(
core_thread_list.GetThreadAtIndex(core_number, false));
if (core_thread_sp) {
// Keep track of which cores were set as the backing thread for memory
// threads...
if (core_number < core_used_map.size())
core_used_map[core_number] = true;
ThreadSP backing_core_thread_sp(core_thread_sp->GetBackingThread());
if (backing_core_thread_sp) {
thread_sp->SetBackingThread(backing_core_thread_sp);
} else {
thread_sp->SetBackingThread(core_thread_sp);
}
}
}
return thread_sp;
}
void OperatingSystemPython::ThreadWasSelected(Thread *thread) {}
RegisterContextSP
OperatingSystemPython::CreateRegisterContextForThread(Thread *thread,
addr_t reg_data_addr) {
RegisterContextSP reg_ctx_sp;
if (!m_interpreter || !m_python_object_sp || !thread)
return reg_ctx_sp;
if (!IsOperatingSystemPluginThread(thread->shared_from_this()))
return reg_ctx_sp;
// First thing we have to do is get the API lock, and the run lock. We're
// going to change the thread
// content of the process, and we're going to use python, which requires the
// API lock to do it.
// So get & hold that. This is a recursive lock so we can grant it to any
// Python code called on the stack below us.
Target &target = m_process->GetTarget();
std::lock_guard<std::recursive_mutex> guard(target.GetAPIMutex());
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
auto lock =
m_interpreter
->AcquireInterpreterLock(); // to make sure python objects stays alive
if (reg_data_addr != LLDB_INVALID_ADDRESS) {
// The registers data is in contiguous memory, just create the register
// context using the address provided
if (log)
log->Printf("OperatingSystemPython::CreateRegisterContextForThread (tid "
"= 0x%" PRIx64 ", 0x%" PRIx64 ", reg_data_addr = 0x%" PRIx64
") creating memory register context",
thread->GetID(), thread->GetProtocolID(), reg_data_addr);
reg_ctx_sp.reset(new RegisterContextMemory(
*thread, 0, *GetDynamicRegisterInfo(), reg_data_addr));
} else {
// No register data address is provided, query the python plug-in to let
// it make up the data as it sees fit
if (log)
log->Printf("OperatingSystemPython::CreateRegisterContextForThread (tid "
"= 0x%" PRIx64 ", 0x%" PRIx64
") fetching register data from python",
thread->GetID(), thread->GetProtocolID());
StructuredData::StringSP reg_context_data =
m_interpreter->OSPlugin_RegisterContextData(m_python_object_sp,
thread->GetID());
if (reg_context_data) {
std::string value = reg_context_data->GetValue();
DataBufferSP data_sp(new DataBufferHeap(value.c_str(), value.length()));
if (data_sp->GetByteSize()) {
RegisterContextMemory *reg_ctx_memory = new RegisterContextMemory(
*thread, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);
if (reg_ctx_memory) {
reg_ctx_sp.reset(reg_ctx_memory);
reg_ctx_memory->SetAllRegisterData(data_sp);
}
}
}
}
// if we still have no register data, fallback on a dummy context to avoid
// crashing
if (!reg_ctx_sp) {
if (log)
log->Printf("OperatingSystemPython::CreateRegisterContextForThread (tid "
"= 0x%" PRIx64 ") forcing a dummy register context",
thread->GetID());
reg_ctx_sp.reset(new RegisterContextDummy(
*thread, 0, target.GetArchitecture().GetAddressByteSize()));
}
return reg_ctx_sp;
}
StopInfoSP
OperatingSystemPython::CreateThreadStopReason(lldb_private::Thread *thread) {
// We should have gotten the thread stop info from the dictionary of data for
// the thread in the initial call to get_thread_info(), this should have been
// cached so we can return it here
StopInfoSP
stop_info_sp; //(StopInfo::CreateStopReasonWithSignal (*thread, SIGSTOP));
return stop_info_sp;
}
lldb::ThreadSP OperatingSystemPython::CreateThread(lldb::tid_t tid,
addr_t context) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
if (log)
log->Printf("OperatingSystemPython::CreateThread (tid = 0x%" PRIx64
", context = 0x%" PRIx64 ") fetching register data from python",
tid, context);
if (m_interpreter && m_python_object_sp) {
// First thing we have to do is get the API lock, and the run lock. We're
// going to change the thread
// content of the process, and we're going to use python, which requires the
// API lock to do it.
// So get & hold that. This is a recursive lock so we can grant it to any
// Python code called on the stack below us.
Target &target = m_process->GetTarget();
std::lock_guard<std::recursive_mutex> guard(target.GetAPIMutex());
auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure
// thread_info_dict
// stays alive
StructuredData::DictionarySP thread_info_dict =
m_interpreter->OSPlugin_CreateThread(m_python_object_sp, tid, context);
std::vector<bool> core_used_map;
if (thread_info_dict) {
ThreadList core_threads(m_process);
ThreadList &thread_list = m_process->GetThreadList();
bool did_create = false;
ThreadSP thread_sp(
CreateThreadFromThreadInfo(*thread_info_dict, core_threads,
thread_list, core_used_map, &did_create));
if (did_create)
thread_list.AddThread(thread_sp);
return thread_sp;
}
}
return ThreadSP();
}
#endif // #ifndef LLDB_DISABLE_PYTHON

View File

@@ -0,0 +1,98 @@
//===-- OperatingSystemPython.h ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_OperatingSystemPython_h_
#define liblldb_OperatingSystemPython_h_
#ifndef LLDB_DISABLE_PYTHON
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Target/OperatingSystem.h"
#include "lldb/Utility/StructuredData.h"
class DynamicRegisterInfo;
namespace lldb_private {
class ScriptInterpreter;
}
class OperatingSystemPython : public lldb_private::OperatingSystem {
public:
OperatingSystemPython(lldb_private::Process *process,
const lldb_private::FileSpec &python_module_path);
~OperatingSystemPython() override;
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
static lldb_private::OperatingSystem *
CreateInstance(lldb_private::Process *process, bool force);
static void Initialize();
static void Terminate();
static lldb_private::ConstString GetPluginNameStatic();
static const char *GetPluginDescriptionStatic();
//------------------------------------------------------------------
// lldb_private::PluginInterface Methods
//------------------------------------------------------------------
lldb_private::ConstString GetPluginName() override;
uint32_t GetPluginVersion() override;
//------------------------------------------------------------------
// lldb_private::OperatingSystem Methods
//------------------------------------------------------------------
bool UpdateThreadList(lldb_private::ThreadList &old_thread_list,
lldb_private::ThreadList &real_thread_list,
lldb_private::ThreadList &new_thread_list) override;
void ThreadWasSelected(lldb_private::Thread *thread) override;
lldb::RegisterContextSP
CreateRegisterContextForThread(lldb_private::Thread *thread,
lldb::addr_t reg_data_addr) override;
lldb::StopInfoSP
CreateThreadStopReason(lldb_private::Thread *thread) override;
//------------------------------------------------------------------
// Method for lazy creation of threads on demand
//------------------------------------------------------------------
lldb::ThreadSP CreateThread(lldb::tid_t tid, lldb::addr_t context) override;
protected:
bool IsValid() const {
return m_python_object_sp && m_python_object_sp->IsValid();
}
lldb::ThreadSP CreateThreadFromThreadInfo(
lldb_private::StructuredData::Dictionary &thread_dict,
lldb_private::ThreadList &core_thread_list,
lldb_private::ThreadList &old_thread_list,
std::vector<bool> &core_used_map, bool *did_create_ptr);
DynamicRegisterInfo *GetDynamicRegisterInfo();
lldb::ValueObjectSP m_thread_list_valobj_sp;
std::unique_ptr<DynamicRegisterInfo> m_register_info_ap;
lldb_private::ScriptInterpreter *m_interpreter;
lldb_private::StructuredData::ObjectSP m_python_object_sp;
};
#endif // LLDB_DISABLE_PYTHON
#endif // liblldb_OperatingSystemPython_h_