ribrdb updated this revision to Diff 34839.
ribrdb added a comment.

Fix cmake build.


Repository:
  rL LLVM

http://reviews.llvm.org/D5871

Files:
  cmake/LLDBDependencies.cmake
  include/lldb/Core/PluginManager.h
  lib/Makefile
  lldb.xcodeproj/project.pbxproj
  source/Core/PluginManager.cpp
  source/Initialization/SystemInitializerCommon.cpp
  source/Plugins/Makefile
  source/Plugins/OperatingSystem/CMakeLists.txt
  source/Plugins/OperatingSystem/Go/CMakeLists.txt
  source/Plugins/OperatingSystem/Go/Makefile
  source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp
  source/Plugins/OperatingSystem/Go/OperatingSystemGo.h
  source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
  source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
  source/Target/Process.cpp
  source/Target/StackFrameList.cpp
  source/Target/ThreadList.cpp
  test/lang/go/goroutines/TestGoroutines.py
  test/lang/go/goroutines/main.go

Index: test/lang/go/goroutines/main.go
===================================================================
--- /dev/null
+++ 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
+}
Index: test/lang/go/goroutines/TestGoroutines.py
===================================================================
--- /dev/null
+++ 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 suit 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()
Index: source/Target/ThreadList.cpp
===================================================================
--- source/Target/ThreadList.cpp
+++ source/Target/ThreadList.cpp
@@ -773,7 +773,8 @@
             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;
Index: source/Target/StackFrameList.cpp
===================================================================
--- source/Target/StackFrameList.cpp
+++ source/Target/StackFrameList.cpp
@@ -108,6 +108,8 @@
     if (m_show_inlined_frames)
     {        
         GetFramesUpTo(0);
+        if (m_frames.size() == 0)
+            return;
         if (!m_frames[0]->IsInlined())
         {
             m_current_inlined_depth = UINT32_MAX;
Index: source/Target/Process.cpp
===================================================================
--- source/Target/Process.cpp
+++ source/Target/Process.cpp
@@ -6550,6 +6550,8 @@
         if (language_runtime_sp)
             language_runtime_sp->ModulesDidLoad(module_list);
     }
+
+    LoadOperatingSystemPlugin(false);
 }
 
 void
Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -2044,6 +2044,10 @@
             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)
                 {
Index: source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
===================================================================
--- source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
+++ source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
@@ -42,9 +42,7 @@
 void
 OperatingSystemPython::Initialize()
 {
-    PluginManager::RegisterPlugin (GetPluginNameStatic(),
-                                   GetPluginDescriptionStatic(),
-                                   CreateInstance);
+    PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, nullptr);
 }
 
 void
Index: source/Plugins/OperatingSystem/Go/OperatingSystemGo.h
===================================================================
--- /dev/null
+++ 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_
Index: source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp
===================================================================
--- /dev/null
+++ source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp
@@ -0,0 +1,564 @@
+//===-- 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/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);
+};
+
+bool
+ModuleContainsGoRuntime(Module *module)
+{
+    const Symbol *symbol = module->FindFirstSymbolWithNameAndType(ConstString("runtime.allg"), lldb::eSymbolTypeAny);
+    if (symbol == nullptr)
+        return nullptr;
+    symbol = module->FindFirstSymbolWithNameAndType(ConstString("runtime.allglen"), lldb::eSymbolTypeAny);
+
+    return symbol != nullptr;
+}
+}
+
+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_pointer = module_list.GetModulePointerAtIndexUnlocked(i);
+            if (ModuleContainsGoRuntime(module_pointer))
+            {
+                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 (int 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 (int 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;
+}
Index: source/Plugins/OperatingSystem/Go/Makefile
===================================================================
--- /dev/null
+++ 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
Index: source/Plugins/OperatingSystem/Go/CMakeLists.txt
===================================================================
--- /dev/null
+++ source/Plugins/OperatingSystem/Go/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginOSGo
+  OperatingSystemGo.cpp
+  )
Index: source/Plugins/OperatingSystem/CMakeLists.txt
===================================================================
--- source/Plugins/OperatingSystem/CMakeLists.txt
+++ source/Plugins/OperatingSystem/CMakeLists.txt
@@ -1 +1,2 @@
+add_subdirectory(Go)
 add_subdirectory(Python)
Index: source/Plugins/Makefile
===================================================================
--- source/Plugins/Makefile
+++ source/Plugins/Makefile
@@ -33,6 +33,7 @@
 	DynamicLoader/Windows-DYLD \
 	JITLoader/GDB \
 	ExpressionParser/Clang \
+	OperatingSystem/Go \
 	OperatingSystem/Python \
 	SystemRuntime/MacOSX \
 	SymbolVendor/ELF \
Index: source/Initialization/SystemInitializerCommon.cpp
===================================================================
--- source/Initialization/SystemInitializerCommon.cpp
+++ 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 @@
 #ifndef LLDB_DISABLE_PYTHON
     OperatingSystemPython::Initialize();
 #endif
+    OperatingSystemGo::Initialize();
 }
 
 void
@@ -181,6 +183,7 @@
 #ifndef LLDB_DISABLE_PYTHON
     OperatingSystemPython::Terminate();
 #endif
+    OperatingSystemGo::Terminate();
 
     Log::Terminate();
 }
Index: source/Core/PluginManager.cpp
===================================================================
--- source/Core/PluginManager.cpp
+++ source/Core/PluginManager.cpp
@@ -771,16 +771,18 @@
 
 struct OperatingSystemInstance
 {
-    OperatingSystemInstance() :
-        name(),
-        description(),
-        create_callback(NULL)
+    OperatingSystemInstance()
+        : name()
+        , description()
+        , create_callback(NULL)
+        , debugger_init_callback(NULL)
     {
     }
     
     ConstString name;
     std::string description;
     OperatingSystemCreateInstance create_callback;
+    DebuggerInitializeCallback debugger_init_callback;
 };
 
 typedef std::vector<OperatingSystemInstance> OperatingSystemInstances;
@@ -800,9 +802,9 @@
 }
 
 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 @@
         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 @@
                 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.
@@ -2815,3 +2828,38 @@
     }
     return false;
 }
+
+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;
+}
Index: lldb.xcodeproj/project.pbxproj
===================================================================
--- lldb.xcodeproj/project.pbxproj
+++ lldb.xcodeproj/project.pbxproj
@@ -814,6 +814,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 */; };
@@ -2613,6 +2615,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>"; };
@@ -3575,6 +3579,7 @@
 		266DFE9013FD64D200D0C574 /* OperatingSystem */ = {
 			isa = PBXGroup;
 			children = (
+				AE8F624519EF3DFC00326B21 /* Go */,
 				2698699715E6CBD0002415FF /* Python */,
 			);
 			path = OperatingSystem;
@@ -5403,6 +5408,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 = (
@@ -6345,6 +6359,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 */,
Index: lib/Makefile
===================================================================
--- lib/Makefile
+++ lib/Makefile
@@ -69,6 +69,7 @@
 	lldbPluginObjectFileJIT.a \
 	lldbPluginSymbolVendorELF.a \
 	lldbPluginObjectFilePECOFF.a \
+	lldbPluginOSGo.a \
 	lldbPluginOSPython.a \
 	lldbPluginPlatformGDB.a \
 	lldbPluginProcessElfCore.a \
Index: include/lldb/Core/PluginManager.h
===================================================================
--- include/lldb/Core/PluginManager.h
+++ include/lldb/Core/PluginManager.h
@@ -117,11 +117,10 @@
     //------------------------------------------------------------------
     // 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);
     
@@ -470,6 +469,13 @@
                                       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);
 };
 
 
Index: cmake/LLDBDependencies.cmake
===================================================================
--- cmake/LLDBDependencies.cmake
+++ cmake/LLDBDependencies.cmake
@@ -65,6 +65,7 @@
   lldbPluginInstructionMIPS
   lldbPluginInstructionMIPS64
   lldbPluginObjectFilePECOFF
+  lldbPluginOSGo
   lldbPluginOSPython
   lldbPluginMemoryHistoryASan
   lldbPluginInstrumentationRuntimeAddressSanitizer
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to