summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyan Brown <ribrdb@google.com>2015-09-16 21:20:44 +0000
committerRyan Brown <ribrdb@google.com>2015-09-16 21:20:44 +0000
commit65d4d5c3c6d742855f572d1306af93fabe015b0a (patch)
treef6a840baed06cdc87a15c0610b45fcad359fbe10
parent8be1847b09e358cacfb6219e8b0cdeaf77f1b9fe (diff)
downloadbcm5719-llvm-65d4d5c3c6d742855f572d1306af93fabe015b0a.tar.gz
bcm5719-llvm-65d4d5c3c6d742855f572d1306af93fabe015b0a.zip
Add an OperatingSystem plugin to support goroutines
The Go runtime schedules user level threads (goroutines) across real threads. This adds an OS plugin to create memory threads for goroutines. It supports the 1.4 and 1.5 go runtime. Differential Revision: http://reviews.llvm.org/D5871 llvm-svn: 247852
-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