[Lldb-commits] [lldb] r247852 - Add an OperatingSystem plugin to support goroutines

Ryan Brown via lldb-commits lldb-commits at lists.llvm.org
Wed Sep 16 14:20:45 PDT 2015


Author: ribrdb
Date: Wed Sep 16 16:20:44 2015
New Revision: 247852

URL: http://llvm.org/viewvc/llvm-project?rev=247852&view=rev
Log:
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

Added:
    lldb/trunk/source/Plugins/OperatingSystem/Go/
    lldb/trunk/source/Plugins/OperatingSystem/Go/CMakeLists.txt
    lldb/trunk/source/Plugins/OperatingSystem/Go/Makefile
    lldb/trunk/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp
    lldb/trunk/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h
    lldb/trunk/test/lang/go/goroutines/
    lldb/trunk/test/lang/go/goroutines/TestGoroutines.py
    lldb/trunk/test/lang/go/goroutines/main.go
Modified:
    lldb/trunk/cmake/LLDBDependencies.cmake
    lldb/trunk/include/lldb/Core/PluginManager.h
    lldb/trunk/include/lldb/lldb-enumerations.h
    lldb/trunk/lib/Makefile
    lldb/trunk/lldb.xcodeproj/project.pbxproj
    lldb/trunk/source/Core/PluginManager.cpp
    lldb/trunk/source/Initialization/SystemInitializerCommon.cpp
    lldb/trunk/source/Plugins/Makefile
    lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
    lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
    lldb/trunk/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
    lldb/trunk/source/Plugins/OperatingSystem/CMakeLists.txt
    lldb/trunk/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
    lldb/trunk/source/Symbol/ObjectFile.cpp
    lldb/trunk/source/Target/Process.cpp
    lldb/trunk/source/Target/StackFrameList.cpp
    lldb/trunk/source/Target/ThreadList.cpp
    lldb/trunk/source/Utility/ConvertEnum.cpp

Modified: lldb/trunk/cmake/LLDBDependencies.cmake
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/cmake/LLDBDependencies.cmake?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/cmake/LLDBDependencies.cmake (original)
+++ lldb/trunk/cmake/LLDBDependencies.cmake Wed Sep 16 16:20:44 2015
@@ -65,6 +65,7 @@ set( LLDB_USED_LIBS
   lldbPluginInstructionMIPS
   lldbPluginInstructionMIPS64
   lldbPluginObjectFilePECOFF
+  lldbPluginOSGo
   lldbPluginOSPython
   lldbPluginMemoryHistoryASan
   lldbPluginInstrumentationRuntimeAddressSanitizer

Modified: lldb/trunk/include/lldb/Core/PluginManager.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/PluginManager.h?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/PluginManager.h (original)
+++ lldb/trunk/include/lldb/Core/PluginManager.h Wed Sep 16 16:20:44 2015
@@ -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);
 };
 
 

Modified: lldb/trunk/include/lldb/lldb-enumerations.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-enumerations.h?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-enumerations.h (original)
+++ lldb/trunk/include/lldb/lldb-enumerations.h Wed Sep 16 16:20:44 2015
@@ -617,6 +617,7 @@ namespace lldb {
         eSectionTypeELFDynamicLinkInfo,   // Elf SHT_DYNAMIC section
         eSectionTypeEHFrame,
         eSectionTypeCompactUnwind,        // compact unwind section in Mach-O, __TEXT,__unwind_info
+        eSectionTypeGoSymtab,
         eSectionTypeOther
     };
 

Modified: lldb/trunk/lib/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lib/Makefile?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/lib/Makefile (original)
+++ lldb/trunk/lib/Makefile Wed Sep 16 16:20:44 2015
@@ -69,6 +69,7 @@ USEDLIBS = lldbAPI.a \
 	lldbPluginObjectFileJIT.a \
 	lldbPluginSymbolVendorELF.a \
 	lldbPluginObjectFilePECOFF.a \
+	lldbPluginOSGo.a \
 	lldbPluginOSPython.a \
 	lldbPluginPlatformGDB.a \
 	lldbPluginProcessElfCore.a \

Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Wed Sep 16 16:20:44 2015
@@ -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 */,

Modified: lldb/trunk/source/Core/PluginManager.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/PluginManager.cpp?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Core/PluginManager.cpp (original)
+++ lldb/trunk/source/Core/PluginManager.cpp Wed Sep 16 16:20:44 2015
@@ -771,16 +771,18 @@ PluginManager::GetEmulateInstructionCrea
 
 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 Con
         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 (Debug
                 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::CreateSettingForJITLoader
                                   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;
+}

Modified: lldb/trunk/source/Initialization/SystemInitializerCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Initialization/SystemInitializerCommon.cpp?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Initialization/SystemInitializerCommon.cpp (original)
+++ lldb/trunk/source/Initialization/SystemInitializerCommon.cpp Wed Sep 16 16:20:44 2015
@@ -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();
 }

Modified: lldb/trunk/source/Plugins/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Makefile?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Makefile (original)
+++ lldb/trunk/source/Plugins/Makefile Wed Sep 16 16:20:44 2015
@@ -33,6 +33,7 @@ PARALLEL_DIRS := ABI/MacOSX-arm ABI/MacO
 	DynamicLoader/Windows-DYLD \
 	JITLoader/GDB \
 	ExpressionParser/Clang \
+	OperatingSystem/Go \
 	OperatingSystem/Python \
 	SystemRuntime/MacOSX \
 	SymbolVendor/ELF \

Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp (original)
+++ lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp Wed Sep 16 16:20:44 2015
@@ -1720,6 +1720,7 @@ ObjectFileELF::CreateSections(SectionLis
             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(SectionLis
             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)
             {

Modified: lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp (original)
+++ lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp Wed Sep 16 16:20:44 2015
@@ -1318,6 +1318,7 @@ ObjectFileMachO::GetAddressClass (lldb::
                     case eSectionTypeZeroFill:
                     case eSectionTypeDataObjCMessageRefs:
                     case eSectionTypeDataObjCCFStrings:
+                    case eSectionTypeGoSymtab:
                         return eAddressClassData;
 
                     case eSectionTypeDebug:
@@ -1777,6 +1778,7 @@ ObjectFileMachO::CreateSections (Section
                                     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 (Section
                                         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 ||

Modified: lldb/trunk/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp (original)
+++ lldb/trunk/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp Wed Sep 16 16:20:44 2015
@@ -693,6 +693,7 @@ ObjectFilePECOFF::CreateSections (Sectio
                 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 (Sectio
                 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;

Modified: lldb/trunk/source/Plugins/OperatingSystem/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/OperatingSystem/CMakeLists.txt?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/OperatingSystem/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/OperatingSystem/CMakeLists.txt Wed Sep 16 16:20:44 2015
@@ -1 +1,2 @@
+add_subdirectory(Go)
 add_subdirectory(Python)

Added: lldb/trunk/source/Plugins/OperatingSystem/Go/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/OperatingSystem/Go/CMakeLists.txt?rev=247852&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/OperatingSystem/Go/CMakeLists.txt (added)
+++ lldb/trunk/source/Plugins/OperatingSystem/Go/CMakeLists.txt Wed Sep 16 16:20:44 2015
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginOSGo
+  OperatingSystemGo.cpp
+  )

Added: lldb/trunk/source/Plugins/OperatingSystem/Go/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/OperatingSystem/Go/Makefile?rev=247852&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/OperatingSystem/Go/Makefile (added)
+++ lldb/trunk/source/Plugins/OperatingSystem/Go/Makefile Wed Sep 16 16:20:44 2015
@@ -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

Added: lldb/trunk/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp?rev=247852&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp (added)
+++ lldb/trunk/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp Wed Sep 16 16:20:44 2015
@@ -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;
+}

Added: lldb/trunk/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h?rev=247852&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h (added)
+++ lldb/trunk/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h Wed Sep 16 16:20:44 2015
@@ -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_

Modified: lldb/trunk/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp (original)
+++ lldb/trunk/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp Wed Sep 16 16:20:44 2015
@@ -42,9 +42,7 @@ using namespace lldb_private;
 void
 OperatingSystemPython::Initialize()
 {
-    PluginManager::RegisterPlugin (GetPluginNameStatic(),
-                                   GetPluginDescriptionStatic(),
-                                   CreateInstance);
+    PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, nullptr);
 }
 
 void

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Wed Sep 16 16:20:44 2015
@@ -2044,6 +2044,10 @@ ProcessGDBRemote::SetThreadStopInfo (lld
             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)
                 {

Modified: lldb/trunk/source/Symbol/ObjectFile.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ObjectFile.cpp?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/ObjectFile.cpp (original)
+++ lldb/trunk/source/Symbol/ObjectFile.cpp Wed Sep 16 16:20:44 2015
@@ -351,6 +351,7 @@ ObjectFile::GetAddressClass (addr_t file
                     case eSectionTypeZeroFill:
                     case eSectionTypeDataObjCMessageRefs:
                     case eSectionTypeDataObjCCFStrings:
+                    case eSectionTypeGoSymtab:
                         return eAddressClassData;
                     case eSectionTypeDebug:
                     case eSectionTypeDWARFDebugAbbrev:

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Wed Sep 16 16:20:44 2015
@@ -6553,6 +6553,8 @@ Process::ModulesDidLoad (ModuleList &mod
         if (language_runtime_sp)
             language_runtime_sp->ModulesDidLoad(module_list);
     }
+
+    LoadOperatingSystemPlugin(false);
 }
 
 void

Modified: lldb/trunk/source/Target/StackFrameList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StackFrameList.cpp?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Target/StackFrameList.cpp (original)
+++ lldb/trunk/source/Target/StackFrameList.cpp Wed Sep 16 16:20:44 2015
@@ -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;

Modified: lldb/trunk/source/Target/ThreadList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadList.cpp?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadList.cpp (original)
+++ lldb/trunk/source/Target/ThreadList.cpp Wed Sep 16 16:20:44 2015
@@ -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;

Modified: lldb/trunk/source/Utility/ConvertEnum.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/ConvertEnum.cpp?rev=247852&r1=247851&r2=247852&view=diff
==============================================================================
--- lldb/trunk/source/Utility/ConvertEnum.cpp (original)
+++ lldb/trunk/source/Utility/ConvertEnum.cpp Wed Sep 16 16:20:44 2015
@@ -107,6 +107,8 @@ lldb_private::GetSectionTypeAsCString(ll
             return "eh-frame";
         case eSectionTypeCompactUnwind:
             return "compact-unwind";
+        case eSectionTypeGoSymtab:
+            return "go-symtab";
         case eSectionTypeOther:
             return "regular";
     }

Added: lldb/trunk/test/lang/go/goroutines/TestGoroutines.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/go/goroutines/TestGoroutines.py?rev=247852&view=auto
==============================================================================
--- lldb/trunk/test/lang/go/goroutines/TestGoroutines.py (added)
+++ lldb/trunk/test/lang/go/goroutines/TestGoroutines.py Wed Sep 16 16:20:44 2015
@@ -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()

Added: lldb/trunk/test/lang/go/goroutines/main.go
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/go/goroutines/main.go?rev=247852&view=auto
==============================================================================
--- lldb/trunk/test/lang/go/goroutines/main.go (added)
+++ lldb/trunk/test/lang/go/goroutines/main.go Wed Sep 16 16:20:44 2015
@@ -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
+}




More information about the lldb-commits mailing list