summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/cmake/LLDBDependencies.cmake1
-rw-r--r--lldb/include/lldb/Core/PluginManager.h16
-rw-r--r--lldb/include/lldb/lldb-enumerations.h1
-rw-r--r--lldb/lib/Makefile1
-rw-r--r--lldb/lldb.xcodeproj/project.pbxproj15
-rw-r--r--lldb/source/Core/PluginManager.cpp62
-rw-r--r--lldb/source/Initialization/SystemInitializerCommon.cpp3
-rw-r--r--lldb/source/Plugins/Makefile1
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp2
-rw-r--r--lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp4
-rw-r--r--lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp2
-rw-r--r--lldb/source/Plugins/OperatingSystem/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/OperatingSystem/Go/CMakeLists.txt3
-rw-r--r--lldb/source/Plugins/OperatingSystem/Go/Makefile14
-rw-r--r--lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp560
-rw-r--r--lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h85
-rw-r--r--lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp4
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp4
-rw-r--r--lldb/source/Symbol/ObjectFile.cpp1
-rw-r--r--lldb/source/Target/Process.cpp2
-rw-r--r--lldb/source/Target/StackFrameList.cpp2
-rw-r--r--lldb/source/Target/ThreadList.cpp3
-rw-r--r--lldb/source/Utility/ConvertEnum.cpp2
-rw-r--r--lldb/test/lang/go/goroutines/TestGoroutines.py87
-rw-r--r--lldb/test/lang/go/goroutines/main.go89
25 files changed, 949 insertions, 16 deletions
diff --git a/lldb/cmake/LLDBDependencies.cmake b/lldb/cmake/LLDBDependencies.cmake
index 1108a7fa5ac..6ce14b7d666 100644
--- a/lldb/cmake/LLDBDependencies.cmake
+++ b/lldb/cmake/LLDBDependencies.cmake
@@ -65,6 +65,7 @@ set( LLDB_USED_LIBS
lldbPluginInstructionMIPS
lldbPluginInstructionMIPS64
lldbPluginObjectFilePECOFF
+ lldbPluginOSGo
lldbPluginOSPython
lldbPluginMemoryHistoryASan
lldbPluginInstrumentationRuntimeAddressSanitizer
diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h
index 6d9f4c914cc..4157353be54 100644
--- a/lldb/include/lldb/Core/PluginManager.h
+++ b/lldb/include/lldb/Core/PluginManager.h
@@ -117,11 +117,10 @@ public:
//------------------------------------------------------------------
// OperatingSystem
//------------------------------------------------------------------
- static bool
- RegisterPlugin (const ConstString &name,
- const char *description,
- OperatingSystemCreateInstance create_callback);
-
+ static bool RegisterPlugin(const ConstString &name, const char *description,
+ OperatingSystemCreateInstance create_callback,
+ DebuggerInitializeCallback debugger_init_callback);
+
static bool
UnregisterPlugin (OperatingSystemCreateInstance create_callback);
@@ -480,6 +479,13 @@ public:
const lldb::OptionValuePropertiesSP &properties_sp,
const ConstString &description,
bool is_global_property);
+
+ static lldb::OptionValuePropertiesSP GetSettingForOperatingSystemPlugin(Debugger &debugger,
+ const ConstString &setting_name);
+
+ static bool CreateSettingForOperatingSystemPlugin(Debugger &debugger,
+ const lldb::OptionValuePropertiesSP &properties_sp,
+ const ConstString &description, bool is_global_property);
};
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 768b43a25dc..20d9651a312 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -617,6 +617,7 @@ namespace lldb {
eSectionTypeELFDynamicLinkInfo, // Elf SHT_DYNAMIC section
eSectionTypeEHFrame,
eSectionTypeCompactUnwind, // compact unwind section in Mach-O, __TEXT,__unwind_info
+ eSectionTypeGoSymtab,
eSectionTypeOther
};
diff --git a/lldb/lib/Makefile b/lldb/lib/Makefile
index 96db9a51e91..b55bed72825 100644
--- a/lldb/lib/Makefile
+++ b/lldb/lib/Makefile
@@ -69,6 +69,7 @@ USEDLIBS = lldbAPI.a \
lldbPluginObjectFileJIT.a \
lldbPluginSymbolVendorELF.a \
lldbPluginObjectFilePECOFF.a \
+ lldbPluginOSGo.a \
lldbPluginOSPython.a \
lldbPluginPlatformGDB.a \
lldbPluginProcessElfCore.a \
diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj
index 1a8ae34d2be..1716d4b686d 100644
--- a/lldb/lldb.xcodeproj/project.pbxproj
+++ b/lldb/lldb.xcodeproj/project.pbxproj
@@ -817,6 +817,8 @@
9AC703AF117675410086C050 /* SBInstruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC703AE117675410086C050 /* SBInstruction.cpp */; };
9AC703B1117675490086C050 /* SBInstructionList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC703B0117675490086C050 /* SBInstructionList.cpp */; };
A36FF33C17D8E94600244D40 /* OptionParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A36FF33B17D8E94600244D40 /* OptionParser.cpp */; };
+ AE8F624919EF3E1E00326B21 /* OperatingSystemGo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE8F624719EF3E1E00326B21 /* OperatingSystemGo.cpp */; };
+ AEB74D931A8C1BE300FE1A4A /* OperatingSystemGo.h in Headers */ = {isa = PBXBuildFile; fileRef = AE8F624819EF3E1E00326B21 /* OperatingSystemGo.h */; };
AE6897281B94F6DE0018845D /* DWARFASTParserGo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE6897261B94F6DE0018845D /* DWARFASTParserGo.cpp */; };
AE7F56291B8FE418001377A8 /* GoASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEFFBA7C1AC4835D0087B932 /* GoASTContext.cpp */; };
AEEA34051AC88A7400AB639D /* TypeSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEEA34041AC88A7400AB639D /* TypeSystem.cpp */; };
@@ -2624,6 +2626,8 @@
9AF16CC7114086A1007A7B3F /* SBBreakpointLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBBreakpointLocation.cpp; path = source/API/SBBreakpointLocation.cpp; sourceTree = "<group>"; };
A36FF33B17D8E94600244D40 /* OptionParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OptionParser.cpp; sourceTree = "<group>"; };
A36FF33D17D8E98800244D40 /* OptionParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OptionParser.h; path = include/lldb/Host/OptionParser.h; sourceTree = "<group>"; };
+ AE8F624719EF3E1E00326B21 /* OperatingSystemGo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OperatingSystemGo.cpp; path = Go/OperatingSystemGo.cpp; sourceTree = "<group>"; };
+ AE8F624819EF3E1E00326B21 /* OperatingSystemGo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OperatingSystemGo.h; path = Go/OperatingSystemGo.h; sourceTree = "<group>"; };
AE6897261B94F6DE0018845D /* DWARFASTParserGo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFASTParserGo.cpp; sourceTree = "<group>"; };
AE6897271B94F6DE0018845D /* DWARFASTParserGo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFASTParserGo.h; sourceTree = "<group>"; };
AEEA33F61AC74FE700AB639D /* TypeSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeSystem.h; path = include/lldb/Symbol/TypeSystem.h; sourceTree = "<group>"; };
@@ -3582,6 +3586,7 @@
266DFE9013FD64D200D0C574 /* OperatingSystem */ = {
isa = PBXGroup;
children = (
+ AE8F624519EF3DFC00326B21 /* Go */,
2698699715E6CBD0002415FF /* Python */,
);
path = OperatingSystem;
@@ -5422,6 +5427,15 @@
name = DataFormatters;
sourceTree = "<group>";
};
+ AE8F624519EF3DFC00326B21 /* Go */ = {
+ isa = PBXGroup;
+ children = (
+ AE8F624719EF3E1E00326B21 /* OperatingSystemGo.cpp */,
+ AE8F624819EF3E1E00326B21 /* OperatingSystemGo.h */,
+ );
+ name = Go;
+ sourceTree = "<group>";
+ };
9694FA6E1B32AA35005EBB16 /* SysV-mips */ = {
isa = PBXGroup;
children = (
@@ -6366,6 +6380,7 @@
2689008D13353E4200698AC0 /* DynamicLoaderMacOSXDYLD.cpp in Sources */,
2689008E13353E4200698AC0 /* DynamicLoaderStatic.cpp in Sources */,
2689009613353E4200698AC0 /* ObjectContainerBSDArchive.cpp in Sources */,
+ AE8F624919EF3E1E00326B21 /* OperatingSystemGo.cpp in Sources */,
26BC179A18C7F2B300D2196D /* JITLoaderList.cpp in Sources */,
2689009713353E4200698AC0 /* ObjectContainerUniversalMachO.cpp in Sources */,
2689009813353E4200698AC0 /* ELFHeader.cpp in Sources */,
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 &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);
+ }
+
+ virtual ~RegisterContextGo() {}
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &reg_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 &reg_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";
}
diff --git a/lldb/test/lang/go/goroutines/TestGoroutines.py b/lldb/test/lang/go/goroutines/TestGoroutines.py
new file mode 100644
index 00000000000..79f5123df42
--- /dev/null
+++ b/lldb/test/lang/go/goroutines/TestGoroutines.py
@@ -0,0 +1,87 @@
+"""Test the Go OS Plugin."""
+
+import os, time
+import unittest2
+import lldb
+import lldbutil
+from lldbtest import *
+
+class TestGoASTContext(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @python_api_test
+ @skipIfRemote # Not remote test suite ready
+ @skipUnlessGoInstalled
+ def test_goroutine_plugin(self):
+ """Test goroutine as threads support."""
+ self.buildGo()
+ self.launchProcess()
+ self.check_goroutines()
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ # Find the line numbers to break inside main().
+ self.main_source = "main.go"
+ self.break_line1 = line_number(self.main_source, '// stop1')
+ self.break_line2 = line_number(self.main_source, '// stop2')
+ self.break_line3 = line_number(self.main_source, '// stop3')
+
+ def launchProcess(self):
+ exe = os.path.join(os.getcwd(), "a.out")
+
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, VALID_TARGET)
+
+ self.bpt1 = target.BreakpointCreateByLocation(self.main_source, self.break_line1)
+ self.assertTrue(self.bpt1, VALID_BREAKPOINT)
+ self.bpt2 = target.BreakpointCreateByLocation(self.main_source, self.break_line2)
+ self.assertTrue(self.bpt2, VALID_BREAKPOINT)
+ self.bpt3 = target.BreakpointCreateByLocation(self.main_source, self.break_line3)
+ self.assertTrue(self.bpt3, VALID_BREAKPOINT)
+
+ # Now launch the process, and do not stop at entry point.
+ process = target.LaunchSimple (None, None, self.get_process_working_directory())
+
+ self.assertTrue(process, PROCESS_IS_VALID)
+
+ # The stop reason of the thread should be breakpoint.
+ thread_list = lldbutil.get_threads_stopped_at_breakpoint (process, self.bpt1)
+
+ # Make sure we stopped at the first breakpoint.
+ self.assertTrue (len(thread_list) != 0, "No thread stopped at our breakpoint.")
+ self.assertTrue (len(thread_list) == 1, "More than one thread stopped at our breakpoint.")
+
+ frame = thread_list[0].GetFrameAtIndex(0)
+ self.assertTrue (frame, "Got a valid frame 0 frame.")
+
+ def check_goroutines(self):
+ self.assertLess(len(self.process().threads), 20)
+ self.process().Continue()
+
+ # Make sure we stopped at the 2nd breakpoint
+ thread_list = lldbutil.get_threads_stopped_at_breakpoint (self.process(), self.bpt2)
+ self.assertTrue (len(thread_list) != 0, "No thread stopped at our breakpoint.")
+ self.assertTrue (len(thread_list) == 1, "More than one thread stopped at our breakpoint.")
+
+ # There's (at least) 21 goroutines.
+ self.assertGreater(len(self.process().threads), 20)
+ # self.dbg.HandleCommand("log enable lldb os")
+
+ # Now test that stepping works if the memory thread moves to a different backing thread.
+ for i in xrange(11):
+ self.thread().StepOver()
+ self.assertEqual(lldb.eStopReasonPlanComplete, self.thread().GetStopReason(), self.thread().GetStopDescription(100))
+
+ # Disable the plugin and make sure the goroutines disappear
+ self.dbg.HandleCommand("settings set plugin.os.goroutines.enable false")
+ self.thread().StepInstruction(False)
+ self.assertLess(len(self.process().threads), 20)
+
+
+if __name__ == '__main__':
+ import atexit
+ lldb.SBDebugger.Initialize()
+ atexit.register(lambda: lldb.SBDebugger.Terminate())
+ unittest2.main()
diff --git a/lldb/test/lang/go/goroutines/main.go b/lldb/test/lang/go/goroutines/main.go
new file mode 100644
index 00000000000..bb44f7b8b71
--- /dev/null
+++ b/lldb/test/lang/go/goroutines/main.go
@@ -0,0 +1,89 @@
+package main
+
+import (
+ "fmt"
+ "runtime"
+)
+
+type philosopher struct {
+ i int
+ forks [2]chan bool
+ eating chan int
+ done chan struct{}
+}
+
+func (p philosopher) run() {
+ for {
+ select {
+ case <-p.done:
+ return
+ case <-p.forks[0]:
+ p.eat()
+ }
+ }
+}
+
+func (p philosopher) eat() {
+ select {
+ case <-p.done:
+ return
+ case <-p.forks[1]:
+ p.eating <- p.i
+ p.forks[0] <- true
+ p.forks[1] <- true
+ runtime.Gosched()
+ }
+}
+
+func startPhilosophers(n int) (chan struct{}, chan int) {
+ philosophers := make([]*philosopher, n)
+ chans := make([]chan bool, n)
+ for i := range chans {
+ chans[i] = make(chan bool, 1)
+ chans[i] <- true
+ }
+ eating := make(chan int, n)
+ done := make(chan struct{})
+ for i := range philosophers {
+ var min, max int
+ if i == n - 1 {
+ min = 0
+ max = i
+ } else {
+ min = i
+ max = i + 1
+ }
+ philosophers[i] = &philosopher{i: i, forks: [2]chan bool{chans[min], chans[max]}, eating: eating, done: done}
+ go philosophers[i].run()
+ }
+ return done, eating
+}
+
+func wait(c chan int) {
+ fmt.Println(<- c)
+ runtime.Gosched()
+}
+
+func main() {
+ // Restrict go to 1 real thread so we can be sure we're seeing goroutines
+ // and not threads.
+ runtime.GOMAXPROCS(1)
+ // Create a bunch of goroutines
+ done, eating := startPhilosophers(20) // stop1
+ // Now turn up the number of threads so this goroutine is likely to get
+ // scheduled on a different thread.
+ runtime.GOMAXPROCS(runtime.NumCPU()) // stop2
+ // Now let things run. Hopefully we'll bounce around
+ wait(eating)
+ wait(eating)
+ wait(eating)
+ wait(eating)
+ wait(eating)
+ wait(eating)
+ wait(eating)
+ wait(eating)
+ wait(eating)
+ wait(eating)
+ close(done)
+ fmt.Println("done") // stop3
+}
OpenPOWER on IntegriCloud