diff options
Diffstat (limited to 'lldb/source')
18 files changed, 744 insertions, 11 deletions
diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp index 2770bbb258a..4c0d2e772f0 100644 --- a/lldb/source/Core/PluginManager.cpp +++ b/lldb/source/Core/PluginManager.cpp @@ -771,16 +771,18 @@ PluginManager::GetEmulateInstructionCreateCallbackForPluginName (const ConstStri struct OperatingSystemInstance { - OperatingSystemInstance() : - name(), - description(), - create_callback(NULL) + OperatingSystemInstance () : + name (), + description (), + create_callback (nullptr), + debugger_init_callback (nullptr) { } ConstString name; std::string description; OperatingSystemCreateInstance create_callback; + DebuggerInitializeCallback debugger_init_callback; }; typedef std::vector<OperatingSystemInstance> OperatingSystemInstances; @@ -800,9 +802,9 @@ GetOperatingSystemInstances () } bool -PluginManager::RegisterPlugin (const ConstString &name, - const char *description, - OperatingSystemCreateInstance create_callback) +PluginManager::RegisterPlugin(const ConstString &name, const char *description, + OperatingSystemCreateInstance create_callback, + DebuggerInitializeCallback debugger_init_callback) { if (create_callback) { @@ -812,6 +814,7 @@ PluginManager::RegisterPlugin (const ConstString &name, if (description && description[0]) instance.description = description; instance.create_callback = create_callback; + instance.debugger_init_callback = debugger_init_callback; Mutex::Locker locker (GetOperatingSystemMutex ()); GetOperatingSystemInstances ().push_back (instance); } @@ -2579,6 +2582,16 @@ PluginManager::DebuggerInitialize (Debugger &debugger) sym_file.debugger_init_callback (debugger); } } + + // Initialize the OperatingSystem plugins + { + Mutex::Locker locker(GetOperatingSystemMutex()); + for (auto &os : GetOperatingSystemInstances()) + { + if (os.debugger_init_callback) + os.debugger_init_callback(debugger); + } + } } // This is the preferred new way to register plugin specific settings. e.g. @@ -2823,3 +2836,38 @@ PluginManager::CreateSettingForJITLoaderPlugin (Debugger &debugger, description, is_global_property); } + +static const char *kOperatingSystemPluginName("os"); + +lldb::OptionValuePropertiesSP +PluginManager::GetSettingForOperatingSystemPlugin(Debugger &debugger, const ConstString &setting_name) +{ + lldb::OptionValuePropertiesSP properties_sp; + lldb::OptionValuePropertiesSP plugin_type_properties_sp( + GetDebuggerPropertyForPlugins(debugger, ConstString(kOperatingSystemPluginName), + ConstString(), // not creating to so we don't need the description + false)); + if (plugin_type_properties_sp) + properties_sp = plugin_type_properties_sp->GetSubProperty(nullptr, setting_name); + return properties_sp; +} + +bool +PluginManager::CreateSettingForOperatingSystemPlugin(Debugger &debugger, + const lldb::OptionValuePropertiesSP &properties_sp, + const ConstString &description, bool is_global_property) +{ + if (properties_sp) + { + lldb::OptionValuePropertiesSP plugin_type_properties_sp( + GetDebuggerPropertyForPlugins(debugger, ConstString(kOperatingSystemPluginName), + ConstString("Settings for operating system plug-ins"), true)); + if (plugin_type_properties_sp) + { + plugin_type_properties_sp->AppendProperty(properties_sp->GetName(), description, is_global_property, + properties_sp); + return true; + } + } + return false; +} diff --git a/lldb/source/Initialization/SystemInitializerCommon.cpp b/lldb/source/Initialization/SystemInitializerCommon.cpp index c17b979c9cb..89a3afe0947 100644 --- a/lldb/source/Initialization/SystemInitializerCommon.cpp +++ b/lldb/source/Initialization/SystemInitializerCommon.cpp @@ -25,6 +25,7 @@ #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" #include "Plugins/OperatingSystem/Python/OperatingSystemPython.h" +#include "Plugins/OperatingSystem/Go/OperatingSystemGo.h" #include "Plugins/Platform/Android/PlatformAndroid.h" #include "Plugins/Platform/FreeBSD/PlatformFreeBSD.h" #include "Plugins/Platform/Kalimba/PlatformKalimba.h" @@ -142,6 +143,7 @@ SystemInitializerCommon::Initialize() #ifndef LLDB_DISABLE_PYTHON OperatingSystemPython::Initialize(); #endif + OperatingSystemGo::Initialize(); } void @@ -181,6 +183,7 @@ SystemInitializerCommon::Terminate() #ifndef LLDB_DISABLE_PYTHON OperatingSystemPython::Terminate(); #endif + OperatingSystemGo::Terminate(); Log::Terminate(); } diff --git a/lldb/source/Plugins/Makefile b/lldb/source/Plugins/Makefile index fe0826f7293..776b6e64b62 100644 --- a/lldb/source/Plugins/Makefile +++ b/lldb/source/Plugins/Makefile @@ -33,6 +33,7 @@ PARALLEL_DIRS := ABI/MacOSX-arm ABI/MacOSX-arm64 ABI/MacOSX-i386 ABI/SysV-i386 A DynamicLoader/Windows-DYLD \ JITLoader/GDB \ ExpressionParser/Clang \ + OperatingSystem/Go \ OperatingSystem/Python \ SystemRuntime/MacOSX \ SymbolVendor/ELF \ diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index a846beee05d..4c6782d59c8 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1720,6 +1720,7 @@ ObjectFileELF::CreateSections(SectionList &unified_section_list) static ConstString g_sect_name_dwarf_debug_str_dwo (".debug_str.dwo"); static ConstString g_sect_name_dwarf_debug_str_offsets_dwo (".debug_str_offsets.dwo"); static ConstString g_sect_name_eh_frame (".eh_frame"); + static ConstString g_sect_name_go_symtab (".gosymtab"); SectionType sect_type = eSectionTypeOther; @@ -1772,6 +1773,7 @@ ObjectFileELF::CreateSections(SectionList &unified_section_list) else if (name == g_sect_name_dwarf_debug_str_dwo) sect_type = eSectionTypeDWARFDebugStr; else if (name == g_sect_name_dwarf_debug_str_offsets_dwo) sect_type = eSectionTypeDWARFDebugStrOffsets; else if (name == g_sect_name_eh_frame) sect_type = eSectionTypeEHFrame; + else if (name == g_sect_name_go_symtab) sect_type = eSectionTypeGoSymtab; switch (header.sh_type) { diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index 4decef69113..855a6dbeea4 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -1318,6 +1318,7 @@ ObjectFileMachO::GetAddressClass (lldb::addr_t file_addr) case eSectionTypeZeroFill: case eSectionTypeDataObjCMessageRefs: case eSectionTypeDataObjCCFStrings: + case eSectionTypeGoSymtab: return eAddressClassData; case eSectionTypeDebug: @@ -1777,6 +1778,7 @@ ObjectFileMachO::CreateSections (SectionList &unified_section_list) static ConstString g_sect_name_compact_unwind ("__unwind_info"); static ConstString g_sect_name_text ("__text"); static ConstString g_sect_name_data ("__data"); + static ConstString g_sect_name_go_symtab ("__gosymtab"); if (section_name == g_sect_name_dwarf_debug_abbrev) @@ -1819,6 +1821,8 @@ ObjectFileMachO::CreateSections (SectionList &unified_section_list) sect_type = eSectionTypeCompactUnwind; else if (section_name == g_sect_name_cfstring) sect_type = eSectionTypeDataObjCCFStrings; + else if (section_name == g_sect_name_go_symtab) + sect_type = eSectionTypeGoSymtab; else if (section_name == g_sect_name_objc_data || section_name == g_sect_name_objc_classrefs || section_name == g_sect_name_objc_superrefs || diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index 8189f10bd30..8b994590504 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -693,6 +693,7 @@ ObjectFilePECOFF::CreateSections (SectionList &unified_section_list) static ConstString g_sect_name_dwarf_debug_ranges (".debug_ranges"); static ConstString g_sect_name_dwarf_debug_str (".debug_str"); static ConstString g_sect_name_eh_frame (".eh_frame"); + static ConstString g_sect_name_go_symtab (".gosymtab"); SectionType section_type = eSectionTypeOther; if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE && ((const_sect_name == g_code_sect_name) || (const_sect_name == g_CODE_sect_name))) @@ -736,6 +737,7 @@ ObjectFilePECOFF::CreateSections (SectionList &unified_section_list) else if (const_sect_name == g_sect_name_dwarf_debug_ranges) section_type = eSectionTypeDWARFDebugRanges; else if (const_sect_name == g_sect_name_dwarf_debug_str) section_type = eSectionTypeDWARFDebugStr; else if (const_sect_name == g_sect_name_eh_frame) section_type = eSectionTypeEHFrame; + else if (const_sect_name == g_sect_name_go_symtab) section_type = eSectionTypeGoSymtab; else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE) { section_type = eSectionTypeCode; diff --git a/lldb/source/Plugins/OperatingSystem/CMakeLists.txt b/lldb/source/Plugins/OperatingSystem/CMakeLists.txt index 655007a0aab..1f017adcd02 100644 --- a/lldb/source/Plugins/OperatingSystem/CMakeLists.txt +++ b/lldb/source/Plugins/OperatingSystem/CMakeLists.txt @@ -1 +1,2 @@ +add_subdirectory(Go) add_subdirectory(Python) diff --git a/lldb/source/Plugins/OperatingSystem/Go/CMakeLists.txt b/lldb/source/Plugins/OperatingSystem/Go/CMakeLists.txt new file mode 100644 index 00000000000..1ca82c46206 --- /dev/null +++ b/lldb/source/Plugins/OperatingSystem/Go/CMakeLists.txt @@ -0,0 +1,3 @@ +add_lldb_library(lldbPluginOSGo + OperatingSystemGo.cpp + ) diff --git a/lldb/source/Plugins/OperatingSystem/Go/Makefile b/lldb/source/Plugins/OperatingSystem/Go/Makefile new file mode 100644 index 00000000000..7d06d483d3a --- /dev/null +++ b/lldb/source/Plugins/OperatingSystem/Go/Makefile @@ -0,0 +1,14 @@ +##==- source/Plugins/OperatingSystem/Go/Makefile --------*- Makefile -*-==## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginOSGo +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile diff --git a/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp b/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp new file mode 100644 index 00000000000..2709afc2743 --- /dev/null +++ b/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp @@ -0,0 +1,560 @@ +//===-- OperatingSystemGo.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "OperatingSystemGo.h" + +// C Includes +// C++ Includes +#include <unordered_map> + +// Other libraries and framework includes +#include "lldb/Core/DataBufferHeap.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/StreamString.h" +#include "lldb/Core/ValueObjectVariable.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Interpreter/Options.h" +#include "lldb/Interpreter/OptionGroupBoolean.h" +#include "lldb/Interpreter/OptionGroupUInt64.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/ThreadList.h" +#include "lldb/Target/Thread.h" +#include "Plugins/Process/Utility/DynamicRegisterInfo.h" +#include "Plugins/Process/Utility/RegisterContextMemory.h" +#include "Plugins/Process/Utility/ThreadMemory.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: + static ConstString + GetSettingName() + { + return OperatingSystemGo::GetPluginNameStatic(); + } + + PluginProperties() + : Properties() + { + m_collection_sp.reset(new OptionValueProperties(GetSettingName())); + m_collection_sp->Initialize(g_properties); + } + + virtual ~PluginProperties() {} + + 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: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + RegisterContextGo(lldb_private::Thread &thread, uint32_t concrete_frame_idx, DynamicRegisterInfo ®_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); + } + + virtual ~RegisterContextGo() {} + + virtual bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue ®_value) + { + 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; + } + } + + virtual bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue ®_value) + { + 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); +}; + +} // 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(); + Mutex::Locker modules_locker(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); +} + +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."; +} + +OperatingSystemGo::OperatingSystemGo(lldb_private::Process *process) + : OperatingSystem(process) + , m_reginfo(new DynamicRegisterInfo) +{ +} + +OperatingSystemGo::~OperatingSystemGo() +{ +} + +bool +OperatingSystemGo::Init(ThreadList &threads) +{ + if (threads.GetSize(false) < 1) + return false; + TargetSP target_sp = m_process->CalculateTarget(); + if (!target_sp) + return false; + 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. + + Error err; + for (uint64_t i = 0; i < allglen; ++i) + { + goroutines.push_back(CreateGoroutineAtIndex(i, err)); + if (err.Fail()) + { + err.PutToLog(log, "OperatingSystemGo::UpdateThreadList"); + 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, nullptr, nullptr, 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, Error &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; +} diff --git a/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h b/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h new file mode 100644 index 00000000000..b543f61be6a --- /dev/null +++ b/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h @@ -0,0 +1,85 @@ +//===-- 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_ + +#include <iostream> + +#include "lldb/Target/OperatingSystem.h" + +class DynamicRegisterInfo; + +class OperatingSystemGo : public lldb_private::OperatingSystem +{ + public: + //------------------------------------------------------------------ + // 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(); + + //------------------------------------------------------------------ + // Class Methods + //------------------------------------------------------------------ + OperatingSystemGo(lldb_private::Process *process); + + virtual ~OperatingSystemGo(); + + //------------------------------------------------------------------ + // lldb_private::PluginInterface Methods + //------------------------------------------------------------------ + virtual lldb_private::ConstString GetPluginName(); + + virtual uint32_t GetPluginVersion(); + + //------------------------------------------------------------------ + // lldb_private::OperatingSystem Methods + //------------------------------------------------------------------ + virtual bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &real_thread_list, + lldb_private::ThreadList &new_thread_list); + + virtual void ThreadWasSelected(lldb_private::Thread *thread); + + virtual lldb::RegisterContextSP CreateRegisterContextForThread(lldb_private::Thread *thread, + lldb::addr_t reg_data_addr); + + virtual lldb::StopInfoSP CreateThreadStopReason(lldb_private::Thread *thread); + + //------------------------------------------------------------------ + // Method for lazy creation of threads on demand + //------------------------------------------------------------------ + virtual lldb::ThreadSP CreateThread(lldb::tid_t tid, lldb::addr_t context); + + 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::Error &err); + + std::unique_ptr<DynamicRegisterInfo> m_reginfo; + lldb::ValueObjectSP m_allg_sp; + lldb::ValueObjectSP m_allglen_sp; +}; + +#endif // #ifndef liblldb_OperatingSystemGo_h_ diff --git a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index 93a52d1206e..a556b0e84e8 100644 --- a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -42,9 +42,7 @@ using namespace lldb_private; void OperatingSystemPython::Initialize() { - PluginManager::RegisterPlugin (GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance); + PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, nullptr); } void diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 2d5b76c3a9d..09947738321 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -2044,6 +2044,10 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid, if (!thread_sp->StopInfoIsUpToDate()) { thread_sp->SetStopInfo (StopInfoSP()); + // If there's a memory thread backed by this thread, we need to use it to calcualte StopInfo. + ThreadSP memory_thread_sp = m_thread_list.FindThreadByProtocolID(thread_sp->GetProtocolID()); + if (memory_thread_sp) + thread_sp = memory_thread_sp; if (exc_type != 0) { diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp index b61d499d2eb..e8a963e5767 100644 --- a/lldb/source/Symbol/ObjectFile.cpp +++ b/lldb/source/Symbol/ObjectFile.cpp @@ -351,6 +351,7 @@ ObjectFile::GetAddressClass (addr_t file_addr) case eSectionTypeZeroFill: case eSectionTypeDataObjCMessageRefs: case eSectionTypeDataObjCCFStrings: + case eSectionTypeGoSymtab: return eAddressClassData; case eSectionTypeDebug: case eSectionTypeDWARFDebugAbbrev: diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index e2bb2e48c41..a8f43c36a04 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -6553,6 +6553,8 @@ Process::ModulesDidLoad (ModuleList &module_list) if (language_runtime_sp) language_runtime_sp->ModulesDidLoad(module_list); } + + LoadOperatingSystemPlugin(false); } void diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index b93e80806de..a7ee6df06f5 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -108,6 +108,8 @@ StackFrameList::ResetCurrentInlinedDepth () if (m_show_inlined_frames) { GetFramesUpTo(0); + if (m_frames.size() == 0) + return; if (!m_frames[0]->IsInlined()) { m_current_inlined_depth = UINT32_MAX; diff --git a/lldb/source/Target/ThreadList.cpp b/lldb/source/Target/ThreadList.cpp index 3ccadfd81b8..a342b8ae5f9 100644 --- a/lldb/source/Target/ThreadList.cpp +++ b/lldb/source/Target/ThreadList.cpp @@ -773,7 +773,8 @@ ThreadList::Update (ThreadList &rhs) const uint32_t num_threads = m_threads.size(); for (uint32_t idx = 0; idx < num_threads; ++idx) { - if (m_threads[idx]->GetID() == tid) + ThreadSP backing_thread = m_threads[idx]->GetBackingThread(); + if (m_threads[idx]->GetID() == tid || (backing_thread && backing_thread->GetID() == tid)) { thread_is_alive = true; break; diff --git a/lldb/source/Utility/ConvertEnum.cpp b/lldb/source/Utility/ConvertEnum.cpp index 8c18d6d4af5..f7dab08498c 100644 --- a/lldb/source/Utility/ConvertEnum.cpp +++ b/lldb/source/Utility/ConvertEnum.cpp @@ -107,6 +107,8 @@ lldb_private::GetSectionTypeAsCString(lldb::SectionType sect_type) return "eh-frame"; case eSectionTypeCompactUnwind: return "compact-unwind"; + case eSectionTypeGoSymtab: + return "go-symtab"; case eSectionTypeOther: return "regular"; } |