Index: cmake/LLDBDependencies.cmake =================================================================== --- cmake/LLDBDependencies.cmake +++ cmake/LLDBDependencies.cmake @@ -22,6 +22,7 @@ lldbPluginDynamicLoaderWindowsDYLD lldbPluginCPlusPlusLanguage + lldbPluginGoLanguage lldbPluginObjCLanguage lldbPluginObjCPlusPlusLanguage Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -825,6 +825,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 */; }; + AE44FB471BB4BB090033EB62 /* GoLanguage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE44FB451BB4BB090033EB62 /* GoLanguage.cpp */; }; + AE44FB4C1BB4BB540033EB62 /* GoFormatterFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE44FB4A1BB4BB540033EB62 /* GoFormatterFunctions.cpp */; }; AE44FB3E1BB485960033EB62 /* GoLanguageRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE44FB3D1BB485960033EB62 /* GoLanguageRuntime.cpp */; }; AE6897281B94F6DE0018845D /* DWARFASTParserGo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE6897261B94F6DE0018845D /* DWARFASTParserGo.cpp */; }; AE7F56291B8FE418001377A8 /* GoASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEFFBA7C1AC4835D0087B932 /* GoASTContext.cpp */; }; @@ -2648,6 +2650,10 @@ 9AF16CC7114086A1007A7B3F /* SBBreakpointLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBBreakpointLocation.cpp; path = source/API/SBBreakpointLocation.cpp; sourceTree = ""; }; A36FF33B17D8E94600244D40 /* OptionParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OptionParser.cpp; sourceTree = ""; }; A36FF33D17D8E98800244D40 /* OptionParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OptionParser.h; path = include/lldb/Host/OptionParser.h; sourceTree = ""; }; + AE44FB451BB4BB090033EB62 /* GoLanguage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GoLanguage.cpp; path = Language/Go/GoLanguage.cpp; sourceTree = ""; }; + AE44FB461BB4BB090033EB62 /* GoLanguage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GoLanguage.h; path = Language/Go/GoLanguage.h; sourceTree = ""; }; + AE44FB4A1BB4BB540033EB62 /* GoFormatterFunctions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GoFormatterFunctions.cpp; path = Language/Go/GoFormatterFunctions.cpp; sourceTree = ""; }; + AE44FB4B1BB4BB540033EB62 /* GoFormatterFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GoFormatterFunctions.h; path = Language/Go/GoFormatterFunctions.h; sourceTree = ""; }; AE44FB3C1BB4858A0033EB62 /* GoLanguageRuntime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GoLanguageRuntime.h; path = Go/GoLanguageRuntime.h; sourceTree = ""; }; AE44FB3D1BB485960033EB62 /* GoLanguageRuntime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GoLanguageRuntime.cpp; path = Go/GoLanguageRuntime.cpp; sourceTree = ""; }; AE6897261B94F6DE0018845D /* DWARFASTParserGo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFASTParserGo.cpp; sourceTree = ""; }; @@ -5389,6 +5395,7 @@ isa = PBXGroup; children = ( 94B6385A1B8FB109004FE1E4 /* CPlusPlus */, + AE44FB431BB4BAC20033EB62 /* Go */, 94B638551B8FAC87004FE1E4 /* ObjC */, 94B638601B8FB7BE004FE1E4 /* ObjCPlusPlus */, ); @@ -5474,6 +5481,25 @@ name = "SysV-mips"; sourceTree = ""; }; + AE44FB431BB4BAC20033EB62 /* Go */ = { + isa = PBXGroup; + children = ( + AE44FB491BB4BB1B0033EB62 /* Formatters */, + AE44FB461BB4BB090033EB62 /* GoLanguage.h */, + AE44FB451BB4BB090033EB62 /* GoLanguage.cpp */, + ); + name = Go; + sourceTree = ""; + }; + AE44FB491BB4BB1B0033EB62 /* Formatters */ = { + isa = PBXGroup; + children = ( + AE44FB4B1BB4BB540033EB62 /* GoFormatterFunctions.h */, + AE44FB4A1BB4BB540033EB62 /* GoFormatterFunctions.cpp */, + ); + name = Formatters; + sourceTree = ""; + }; AE44FB3B1BB485730033EB62 /* Go */ = { isa = PBXGroup; children = ( @@ -6241,6 +6267,7 @@ 2689001113353DB600698AC0 /* Watchpoint.cpp in Sources */, 2689001213353DDE00698AC0 /* CommandObjectApropos.cpp in Sources */, 4C88BC2A1BA3722B00AA0964 /* Expression.cpp in Sources */, + AE44FB4C1BB4BB540033EB62 /* GoFormatterFunctions.cpp in Sources */, 23042D121976CA1D00621B2C /* PlatformKalimba.cpp in Sources */, 2689001313353DDE00698AC0 /* CommandObjectArgs.cpp in Sources */, 2689001413353DDE00698AC0 /* CommandObjectBreakpoint.cpp in Sources */, @@ -6757,6 +6784,7 @@ 2698699B15E6CBD0002415FF /* OperatingSystemPython.cpp in Sources */, 947A1D641616476B0017C8D1 /* CommandObjectPlugin.cpp in Sources */, 2666ADC81B3CB675001FAFD3 /* HexagonDYLDRendezvous.cpp in Sources */, + AE44FB471BB4BB090033EB62 /* GoLanguage.cpp in Sources */, 262ED0081631FA3A00879631 /* OptionGroupString.cpp in Sources */, 94F48F251A01C687005C0EC6 /* StringPrinter.cpp in Sources */, 94094C6B163B6F840083A547 /* ValueObjectCast.cpp in Sources */, Index: source/API/SystemInitializerFull.cpp =================================================================== --- source/API/SystemInitializerFull.cpp +++ source/API/SystemInitializerFull.cpp @@ -44,6 +44,7 @@ #include "Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h" #include "Plugins/JITLoader/GDB/JITLoaderGDB.h" #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" +#include "Plugins/Language/Go/GoLanguage.h" #include "Plugins/Language/ObjC/ObjCLanguage.h" #include "Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h" #include "Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h" @@ -303,6 +304,7 @@ GoLanguageRuntime::Initialize(); CPlusPlusLanguage::Initialize(); + GoLanguage::Initialize(); ObjCLanguage::Initialize(); ObjCPlusPlusLanguage::Initialize(); @@ -414,6 +416,7 @@ RenderScriptRuntime::Terminate(); CPlusPlusLanguage::Terminate(); + GoLanguage::Terminate(); ObjCLanguage::Terminate(); ObjCPlusPlusLanguage::Terminate(); Index: source/Plugins/Language/CMakeLists.txt =================================================================== --- source/Plugins/Language/CMakeLists.txt +++ source/Plugins/Language/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(CPlusPlus) +add_subdirectory(Go) add_subdirectory(ObjC) add_subdirectory(ObjCPlusPlus) Index: source/Plugins/Language/Go/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/Language/Go/CMakeLists.txt @@ -0,0 +1,4 @@ +add_lldb_library(lldbPluginGoLanguage + GoLanguage.cpp + GoFormatterFunctions.cpp +) Index: source/Plugins/Language/Go/GoFormatterFunctions.h =================================================================== --- /dev/null +++ source/Plugins/Language/Go/GoFormatterFunctions.h @@ -0,0 +1,43 @@ +//===-- GoFormatterFunctions.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_GoFormatterFunctions_h_ +#define liblldb_GoFormatterFunctions_h_ + +// C Includes +#include +#include + +// C++ Includes +// Other libraries and framework includes +#include "clang/AST/ASTContext.h" + +// Project includes +#include "lldb/lldb-forward.h" + +#include "lldb/Core/ConstString.h" +#include "lldb/DataFormatters/FormatClasses.h" +#include "lldb/DataFormatters/TypeSynthetic.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/Target/Target.h" + +namespace lldb_private +{ +namespace formatters +{ + +bool GoStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); + +SyntheticChildrenFrontEnd *GoSliceSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); + +} // namespace formatters +} // namespace lldb_private + +#endif // liblldb_GoFormatterFunctions_h_ Index: source/Plugins/Language/Go/GoFormatterFunctions.cpp =================================================================== --- /dev/null +++ source/Plugins/Language/Go/GoFormatterFunctions.cpp @@ -0,0 +1,174 @@ +//===-- GoFormatterFunctions.cpp---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "GoFormatterFunctions.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/DataFormatters/StringPrinter.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +namespace +{ +class GoSliceSyntheticFrontEnd : public SyntheticChildrenFrontEnd +{ + public: + GoSliceSyntheticFrontEnd(ValueObject &valobj) + : SyntheticChildrenFrontEnd(valobj) + { + Update(); + } + + ~GoSliceSyntheticFrontEnd() override = default; + + size_t + CalculateNumChildren() override + { + return m_len; + } + + lldb::ValueObjectSP + GetChildAtIndex(size_t idx) override + { + if (idx < m_len) + { + ValueObjectSP &cached = m_children[idx]; + if (!cached) + { + StreamString idx_name; + idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); + lldb::addr_t object_at_idx = m_base_data_address; + object_at_idx += idx * m_type.GetByteSize(nullptr); + cached = CreateValueObjectFromAddress(idx_name.GetData(), object_at_idx, + m_backend.GetExecutionContextRef(), m_type); + } + return cached; + } + return ValueObjectSP(); + } + + bool + Update() override + { + size_t old_count = m_len; + + ConstString array_const_str("array"); + ValueObjectSP array_sp = m_backend.GetChildMemberWithName(array_const_str, true); + if (!array_sp) + { + m_children.clear(); + return old_count == 0; + } + m_type = array_sp->GetCompilerType().GetPointeeType(); + m_base_data_address = array_sp->GetPointerValue(); + + ConstString len_const_str("len"); + ValueObjectSP len_sp = m_backend.GetChildMemberWithName(len_const_str, true); + if (len_sp) + { + m_len = len_sp->GetValueAsUnsigned(0); + m_children.clear(); + } + + return old_count == m_len; + } + + bool + MightHaveChildren() override + { + return true; + } + + size_t + GetIndexOfChildWithName(const ConstString &name) override + { + return ExtractIndexFromString(name.AsCString()); + } + + private: + CompilerType m_type; + lldb::addr_t m_base_data_address; + size_t m_len; + std::map m_children; +}; + +} // anonymous namespace + +bool +lldb_private::formatters::GoStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &opts) +{ + ProcessSP process_sp = valobj.GetProcessSP(); + if (!process_sp) + return false; + + if (valobj.IsPointerType()) + { + Error err; + ValueObjectSP deref = valobj.Dereference(err); + if (!err.Success()) + return false; + return GoStringSummaryProvider(*deref, stream, opts); + } + + ConstString str_name("str"); + ConstString len_name("len"); + + ValueObjectSP data_sp = valobj.GetChildMemberWithName(str_name, true); + ValueObjectSP len_sp = valobj.GetChildMemberWithName(len_name, true); + if (!data_sp || !len_sp) + return false; + bool success; + lldb::addr_t valobj_addr = data_sp->GetValueAsUnsigned(0, &success); + + if (!success) + return false; + + uint64_t length = len_sp->GetValueAsUnsigned(0); + if (length == 0) + { + stream.Printf("\"\""); + return true; + } + + StringPrinter::ReadStringAndDumpToStreamOptions options(valobj); + options.SetLocation(valobj_addr); + options.SetProcessSP(process_sp); + options.SetStream(&stream); + options.SetSourceSize(length); + options.SetNeedsZeroTermination(false); + options.SetLanguage(eLanguageTypeGo); + + if (!StringPrinter::ReadStringAndDumpToStream(options)) + { + stream.Printf("Summary Unavailable"); + return true; + } + + return true; +} + +SyntheticChildrenFrontEnd * +lldb_private::formatters::GoSliceSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) +{ + if (!valobj_sp) + return nullptr; + + lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); + if (!process_sp) + return NULL; + return new GoSliceSyntheticFrontEnd(*valobj_sp); +} Index: source/Plugins/Language/Go/GoLanguage.h =================================================================== --- /dev/null +++ source/Plugins/Language/Go/GoLanguage.h @@ -0,0 +1,66 @@ +//===-- GoLanguage.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_GoLanguage_h_ +#define liblldb_GoLanguage_h_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +#include "llvm/ADT/StringRef.h" + +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Target/Language.h" + +namespace lldb_private +{ + +class GoLanguage : public Language +{ + public: + GoLanguage() = default; + + ~GoLanguage() override = default; + + lldb::LanguageType + GetLanguageType() const override + { + return lldb::eLanguageTypeGo; + } + + HardcodedFormatters::HardcodedSummaryFinder GetHardcodedSummaries() override; + + HardcodedFormatters::HardcodedSyntheticFinder GetHardcodedSynthetics() override; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + + static void Terminate(); + + static lldb_private::Language *CreateInstance(lldb::LanguageType language); + + static lldb_private::ConstString GetPluginNameStatic(); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; +}; + +} // namespace lldb_private + +#endif // liblldb_GoLanguage_h_ Index: source/Plugins/Language/Go/GoLanguage.cpp =================================================================== --- /dev/null +++ source/Plugins/Language/Go/GoLanguage.cpp @@ -0,0 +1,146 @@ +//===-- GoLanguage.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include +// C++ Includes +#include +#include + +// Other libraries and framework includes +#include "llvm/ADT/StringRef.h" + +// Project includes +#include "GoLanguage.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Symbol/GoASTContext.h" +#include "Plugins/Language/Go/GoFormatterFunctions.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +void +GoLanguage::Initialize() +{ + PluginManager::RegisterPlugin(GetPluginNameStatic(), "Go Language", CreateInstance); +} + +void +GoLanguage::Terminate() +{ + PluginManager::UnregisterPlugin(CreateInstance); +} + +lldb_private::ConstString +GoLanguage::GetPluginNameStatic() +{ + static ConstString g_name("Go"); + return g_name; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +lldb_private::ConstString +GoLanguage::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +GoLanguage::GetPluginVersion() +{ + return 1; +} + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ +Language * +GoLanguage::CreateInstance(lldb::LanguageType language) +{ + if (language == eLanguageTypeGo) + return new GoLanguage(); + return nullptr; +} + +HardcodedFormatters::HardcodedSummaryFinder +GoLanguage::GetHardcodedSummaries() +{ + static std::once_flag g_initialize; + static HardcodedFormatters::HardcodedSummaryFinder g_formatters; + + std::call_once(g_initialize, []() -> void + { + g_formatters.push_back( + [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, + FormatManager &) -> TypeSummaryImpl::SharedPointer + { + static CXXFunctionSummaryFormat::SharedPointer formatter_sp(new CXXFunctionSummaryFormat( + TypeSummaryImpl::Flags().SetDontShowChildren(true), + lldb_private::formatters::GoStringSummaryProvider, "Go string summary provider")); + if (GoASTContext::IsGoString(valobj.GetCompilerType())) + { + return formatter_sp; + } + if (GoASTContext::IsGoString(valobj.GetCompilerType().GetPointeeType())) + { + return formatter_sp; + } + return nullptr; + }); + g_formatters.push_back( + [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, + FormatManager &) -> TypeSummaryImpl::SharedPointer + { + static lldb::TypeSummaryImplSP formatter_sp( + new StringSummaryFormat(TypeSummaryImpl::Flags().SetHideItemNames(true), + "(len ${var.len}, cap ${var.cap})")); + if (GoASTContext::IsGoSlice(valobj.GetCompilerType())) + { + return formatter_sp; + } + if (GoASTContext::IsGoSlice(valobj.GetCompilerType().GetPointeeType())) + { + return formatter_sp; + } + return nullptr; + }); + }); + return g_formatters; +} + +HardcodedFormatters::HardcodedSyntheticFinder +GoLanguage::GetHardcodedSynthetics() +{ + static std::once_flag g_initialize; + static HardcodedFormatters::HardcodedSyntheticFinder g_formatters; + + std::call_once(g_initialize, []() -> void + { + g_formatters.push_back( + [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, + FormatManager &fmt_mgr) -> SyntheticChildren::SharedPointer + { + static CXXSyntheticChildren::SharedPointer formatter_sp( + new CXXSyntheticChildren(SyntheticChildren::Flags(), "slice synthetic children", + lldb_private::formatters::GoSliceSyntheticFrontEndCreator)); + if (GoASTContext::IsGoSlice(valobj.GetCompilerType())) + { + return formatter_sp; + } + return nullptr; + }); + }); + + return g_formatters; +} Index: source/Plugins/Language/Go/Makefile =================================================================== --- /dev/null +++ source/Plugins/Language/Go/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/Language/Go -------------------*- 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 := lldbPluginGoLanguage +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile Index: source/Plugins/Makefile =================================================================== --- source/Plugins/Makefile +++ source/Plugins/Makefile @@ -26,6 +26,7 @@ LanguageRuntime/Go/ \ LanguageRuntime/RenderScript/RenderScriptRuntime \ Language/CPlusPlus \ + Language/Go \ Language/ObjC \ Language/ObjCPlusPlus \ DynamicLoader/POSIX-DYLD \ Index: test/lang/go/formatters/TestGoFormatters.py =================================================================== --- /dev/null +++ test/lang/go/formatters/TestGoFormatters.py @@ -0,0 +1,66 @@ +"""Test the Go Data Formatter Plugin.""" + +import os, time +import unittest2 +import lldb +import lldbutil +from lldbtest import * + +class TestGoLanguage(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @python_api_test + @skipIfFreeBSD # llvm.org/pr24895 triggers assertion failure + @skipIfRemote # Not remote test suite ready + @no_debug_info_test + @skipUnlessGoInstalled + def test_go_formatter_plugin(self): + """Test go data formatters.""" + self.buildGo() + self.launchProcess() + self.check_formatters() + + 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_line = line_number(self.main_source, '// stop here') + + def launchProcess(self): + exe = os.path.join(os.getcwd(), "a.out") + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + self.bpt = target.BreakpointCreateByLocation(self.main_source, self.break_line) + self.assertTrue(self.bpt, 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.bpt) + + # 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_formatters(self): + a = self.frame().FindVariable('a') + self.assertEqual('(string) a = "my string"', str(a)) + b = self.frame().FindVariable('b') + self.assertEqual("([]int) b = (len 2, cap 7) {\n [0] = 0\n [1] = 0\n}", str(b)) + + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Index: test/lang/go/formatters/main.go =================================================================== --- /dev/null +++ test/lang/go/formatters/main.go @@ -0,0 +1,9 @@ +package main + +import "fmt" + +func main() { + a := "my string" + b := make([]int, 2, 7) + fmt.Println(a, b) // stop here +} \ No newline at end of file