Index: lldb/trunk/include/lldb/Core/Module.h =================================================================== --- lldb/trunk/include/lldb/Core/Module.h +++ lldb/trunk/include/lldb/Core/Module.h @@ -1119,7 +1119,8 @@ lldb::SymbolVendorUP m_symfile_ap; ///< A pointer to the symbol vendor for this module. std::vector m_old_symfiles; ///< If anyone calls Module::SetSymbolFileFileSpec() and changes the symbol file, ///< we need to keep all old symbol files around in case anyone has type references to them - lldb::ClangASTContextUP m_ast; ///< The AST context for this module. + lldb::ClangASTContextUP m_ast; ///< The Clang AST context for this module. + lldb::GoASTContextUP m_go_ast; ///< The Go AST context for this module. PathMappingList m_source_mappings; ///< Module specific source remappings for when you have debug info for a module that doesn't match where the sources currently are lldb::SectionListUP m_sections_ap; ///< Unified section list for module that is used by the ObjectFile and and ObjectFile instances for the debug info Index: lldb/trunk/include/lldb/Symbol/ClangASTContext.h =================================================================== --- lldb/trunk/include/lldb/Symbol/ClangASTContext.h +++ lldb/trunk/include/lldb/Symbol/ClangASTContext.h @@ -485,7 +485,6 @@ //------------------------------------------------------------------ // TypeSystem methods //------------------------------------------------------------------ - DWARFASTParser * GetDWARFParser () override; Index: lldb/trunk/include/lldb/Symbol/CompilerType.h =================================================================== --- lldb/trunk/include/lldb/Symbol/CompilerType.h +++ lldb/trunk/include/lldb/Symbol/CompilerType.h @@ -318,7 +318,6 @@ static lldb::BasicType GetBasicTypeEnumeration (const ConstString &name); - //---------------------------------------------------------------------- // If this type is an enumeration, iterate through all of its enumerators // using a callback. If the callback returns true, keep iterating, else Index: lldb/trunk/include/lldb/Symbol/GoASTContext.h =================================================================== --- lldb/trunk/include/lldb/Symbol/GoASTContext.h +++ lldb/trunk/include/lldb/Symbol/GoASTContext.h @@ -0,0 +1,335 @@ +//===-- GoASTContext.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __lldb__GoASTContext__ +#define __lldb__GoASTContext__ + +#include +#include "lldb/Core/ConstString.h" +#include "lldb/Symbol/TypeSystem.h" +#include "lldb/Symbol/CompilerType.h" + +namespace lldb_private +{ + +class Declaration; +class GoType; + +class GoASTContext : public TypeSystem +{ + public: + GoASTContext(); + ~GoASTContext(); + + DWARFASTParser *GetDWARFParser() override; + + void + SetAddressByteSize(int byte_size) + { + m_pointer_byte_size = byte_size; + } + + //------------------------------------------------------------------ + // llvm casting support + //------------------------------------------------------------------ + static bool classof(const TypeSystem *ts) + { + return ts->getKind() == TypeSystem::eKindGo; + } + + //---------------------------------------------------------------------- + // CompilerDeclContext functions + //---------------------------------------------------------------------- + + virtual bool + DeclContextIsStructUnionOrClass(void *opaque_decl_ctx) override + { + return false; + } + + virtual ConstString + DeclContextGetName(void *opaque_decl_ctx) override + { + return ConstString(); + } + + virtual bool + DeclContextIsClassMethod(void *opaque_decl_ctx, lldb::LanguageType *language_ptr, bool *is_instance_method_ptr, + ConstString *language_object_name_ptr) override + { + return false; + } + + //---------------------------------------------------------------------- + // Creating Types + //---------------------------------------------------------------------- + + CompilerType CreateArrayType(const ConstString &name, const CompilerType &element_type, int64_t length); + + CompilerType CreateBaseType(int go_kind, const ConstString &type_name_const_str, uint64_t byte_size); + + // For interface, map, chan. + CompilerType CreateTypedef(int kind, const ConstString &name, CompilerType impl); + + CompilerType CreateVoidType(const ConstString &name); + CompilerType CreateFunctionType(const lldb_private::ConstString &name, CompilerType *params, size_t params_count, + bool is_variadic); + + CompilerType CreateStructType(int kind, const ConstString &name, uint32_t byte_size); + + void CompleteStructType(const CompilerType &type); + + void AddFieldToStruct(const CompilerType &struct_type, const ConstString &name, const CompilerType &field_type, + uint32_t byte_offset); + + //---------------------------------------------------------------------- + // Tests + //---------------------------------------------------------------------- + + static bool IsGoString(const CompilerType &type); + static bool IsGoSlice(const CompilerType &type); + static bool IsGoInterface(const CompilerType &type); + static bool IsDirectIface(uint8_t kind); + static bool IsPointerKind(uint8_t kind); + + virtual bool IsArrayType(void *type, CompilerType *element_type, uint64_t *size, bool *is_incomplete) override; + + virtual bool IsAggregateType(void *type) override; + + virtual bool IsCharType(void *type) override; + + virtual bool IsCompleteType(void *type) override; + + virtual bool IsDefined(void *type) override; + + virtual bool IsFloatingPointType(void *type, uint32_t &count, bool &is_complex) override; + + virtual bool IsFunctionType(void *type, bool *is_variadic_ptr = NULL) override; + + virtual size_t GetNumberOfFunctionArguments(void *type) override; + + virtual CompilerType GetFunctionArgumentAtIndex(void *type, const size_t index) override; + + virtual bool IsFunctionPointerType(void *type) override; + + virtual bool IsIntegerType(void *type, bool &is_signed) override; + + virtual bool IsPossibleDynamicType(void *type, + CompilerType *target_type, // Can pass NULL + bool check_cplusplus, bool check_objc) override; + + virtual bool IsPointerType(void *type, CompilerType *pointee_type = NULL) override; + + virtual bool IsScalarType(void *type) override; + + virtual bool IsVoidType(void *type) override; + + //---------------------------------------------------------------------- + // Type Completion + //---------------------------------------------------------------------- + + virtual bool GetCompleteType(void *type) override; + + //---------------------------------------------------------------------- + // AST related queries + //---------------------------------------------------------------------- + + virtual uint32_t GetPointerByteSize() override; + + //---------------------------------------------------------------------- + // Accessors + //---------------------------------------------------------------------- + + virtual ConstString GetTypeName(void *type) override; + + virtual uint32_t GetTypeInfo(void *type, CompilerType *pointee_or_element_clang_type = NULL) override; + + virtual lldb::LanguageType GetMinimumLanguage(void *type) override; + + virtual lldb::TypeClass GetTypeClass(void *type) override; + + //---------------------------------------------------------------------- + // Creating related types + //---------------------------------------------------------------------- + + virtual CompilerType GetArrayElementType(void *type, uint64_t *stride = nullptr) override; + + virtual CompilerType GetCanonicalType(void *type) override; + + // Returns -1 if this isn't a function of if the function doesn't have a prototype + // Returns a value >= 0 if there is a prototype. + virtual int GetFunctionArgumentCount(void *type) override; + + virtual CompilerType GetFunctionArgumentTypeAtIndex(void *type, size_t idx) override; + + virtual CompilerType GetFunctionReturnType(void *type) override; + + virtual size_t GetNumMemberFunctions(void *type) override; + + virtual TypeMemberFunctionImpl GetMemberFunctionAtIndex(void *type, size_t idx) override; + + virtual CompilerType GetPointeeType(void *type) override; + + virtual CompilerType GetPointerType(void *type) override; + + //---------------------------------------------------------------------- + // Exploring the type + //---------------------------------------------------------------------- + + virtual uint64_t GetBitSize(void *type, ExecutionContextScope *exe_scope) override; + + virtual lldb::Encoding GetEncoding(void *type, uint64_t &count) override; + + virtual lldb::Format GetFormat(void *type) override; + + virtual uint32_t GetNumChildren(void *type, bool omit_empty_base_classes) override; + + virtual lldb::BasicType GetBasicTypeEnumeration(void *type) override; + virtual CompilerType GetIntTypeFromBitSize (size_t bit_size, bool is_signed) override; + virtual CompilerType GetFloatTypeFromBitSize (size_t bit_size) override; + + + virtual uint32_t GetNumFields(void *type) override; + + virtual CompilerType GetFieldAtIndex(void *type, size_t idx, std::string &name, uint64_t *bit_offset_ptr, + uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) override; + + virtual uint32_t + GetNumDirectBaseClasses(void *type) override + { + return 0; + } + + virtual uint32_t + GetNumVirtualBaseClasses(void *type) override + { + return 0; + } + + virtual CompilerType + GetDirectBaseClassAtIndex(void *type, size_t idx, uint32_t *bit_offset_ptr) override + { + return CompilerType(); + } + + virtual CompilerType + GetVirtualBaseClassAtIndex(void *type, size_t idx, uint32_t *bit_offset_ptr) override + { + return CompilerType(); + } + + virtual CompilerType GetChildClangTypeAtIndex(void *type, ExecutionContext *exe_ctx, size_t idx, + bool transparent_pointers, bool omit_empty_base_classes, + bool ignore_array_bounds, std::string &child_name, + uint32_t &child_byte_size, int32_t &child_byte_offset, + uint32_t &child_bitfield_bit_size, + uint32_t &child_bitfield_bit_offset, bool &child_is_base_class, + bool &child_is_deref_of_parent, ValueObject *valobj) override; + + // Lookup a child given a name. This function will match base class names + // and member member names in "clang_type" only, not descendants. + virtual uint32_t GetIndexOfChildWithName(void *type, const char *name, bool omit_empty_base_classes) override; + + // Lookup a child member given a name. This function will match member names + // only and will descend into "clang_type" children in search for the first + // member in this class, or any base class that matches "name". + // TODO: Return all matches for a given name by returning a vector> + // so we catch all names that match a given child name, not just the first. + virtual size_t GetIndexOfChildMemberWithName(void *type, const char *name, bool omit_empty_base_classes, + std::vector &child_indexes) override; + + virtual size_t + GetNumTemplateArguments(void *type) override + { + return 0; + } + + virtual CompilerType + GetTemplateArgument(void *type, size_t idx, lldb::TemplateArgumentKind &kind) override + { + return CompilerType(); + } + + //---------------------------------------------------------------------- + // Dumping types + //---------------------------------------------------------------------- + virtual void DumpValue(void *type, ExecutionContext *exe_ctx, Stream *s, lldb::Format format, + const DataExtractor &data, lldb::offset_t data_offset, size_t data_byte_size, + uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, bool show_types, bool show_summary, + bool verbose, uint32_t depth) override; + + virtual bool DumpTypeValue(void *type, Stream *s, lldb::Format format, const DataExtractor &data, + lldb::offset_t data_offset, size_t data_byte_size, uint32_t bitfield_bit_size, + uint32_t bitfield_bit_offset, ExecutionContextScope *exe_scope) override; + + virtual void DumpTypeDescription(void *type) override; // Dump to stdout + + virtual void DumpTypeDescription(void *type, Stream *s) override; + + //---------------------------------------------------------------------- + // TODO: These methods appear unused. Should they be removed? + //---------------------------------------------------------------------- + + virtual bool IsRuntimeGeneratedType(void *type) override; + + virtual void DumpSummary(void *type, ExecutionContext *exe_ctx, Stream *s, const DataExtractor &data, + lldb::offset_t data_offset, size_t data_byte_size) override; + + // Converts "s" to a floating point value and place resulting floating + // point bytes in the "dst" buffer. + virtual size_t ConvertStringToFloatValue(void *type, const char *s, uint8_t *dst, size_t dst_size) override; + + //---------------------------------------------------------------------- + // TODO: Determine if these methods should move to ClangASTContext. + //---------------------------------------------------------------------- + + virtual bool IsPointerOrReferenceType(void *type, CompilerType *pointee_type = NULL) override; + + virtual unsigned GetTypeQualifiers(void *type) override; + + virtual bool IsCStringType(void *type, uint32_t &length) override; + + virtual size_t GetTypeBitAlign(void *type) override; + + virtual CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override; + + virtual bool IsBeingDefined(void *type) override; + + virtual bool IsConst(void *type) override; + + virtual uint32_t IsHomogeneousAggregate(void *type, CompilerType *base_type_ptr) override; + + virtual bool IsPolymorphicClass(void *type) override; + + virtual bool IsTypedefType(void *type) override; + + // If the current object represents a typedef type, get the underlying type + virtual CompilerType GetTypedefedType(void *type) override; + + virtual bool IsVectorType(void *type, CompilerType *element_type, uint64_t *size) override; + + virtual CompilerType GetFullyUnqualifiedType(void *type) override; + + virtual CompilerType GetNonReferenceType(void *type) override; + + virtual bool IsReferenceType(void *type, CompilerType *pointee_type = nullptr, bool *is_rvalue = nullptr) override; + + private: + typedef std::map> TypeMap; + int m_pointer_byte_size; + int m_int_byte_size; + std::unique_ptr m_types; + std::unique_ptr m_dwarf_ast_parser_ap; + + GoASTContext(const GoASTContext &) = delete; + const GoASTContext &operator=(const GoASTContext &) = delete; +}; +} + +#endif /* defined(__lldb__GoASTContext__) */ Index: lldb/trunk/include/lldb/lldb-forward.h =================================================================== --- lldb/trunk/include/lldb/lldb-forward.h +++ lldb/trunk/include/lldb/lldb-forward.h @@ -99,6 +99,7 @@ class FileSpec; class FileSpecList; class Flags; +class GoASTContext; class TypeCategoryImpl; class FormatManager; class FormattersMatchCandidate; @@ -326,6 +327,7 @@ typedef std::shared_ptr FileSP; typedef std::shared_ptr FunctionSP; typedef std::shared_ptr FuncUnwindersSP; + typedef std::unique_ptr GoASTContextUP; typedef std::shared_ptr InlineFunctionInfoSP; typedef std::shared_ptr InstructionSP; typedef std::shared_ptr InstrumentationRuntimeSP; Index: lldb/trunk/lldb.xcodeproj/project.pbxproj =================================================================== --- lldb/trunk/lldb.xcodeproj/project.pbxproj +++ lldb/trunk/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 */; }; + 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 */; }; AF061F87182C97ED00B6A19C /* RegisterContextHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF061F85182C97ED00B6A19C /* RegisterContextHistory.cpp */; }; AF0C112818580CD800C4C45B /* QueueItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF0C112718580CD800C4C45B /* QueueItem.cpp */; }; @@ -2611,8 +2613,12 @@ 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 = ""; }; + AE6897261B94F6DE0018845D /* DWARFASTParserGo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFASTParserGo.cpp; sourceTree = ""; }; + AE6897271B94F6DE0018845D /* DWARFASTParserGo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFASTParserGo.h; sourceTree = ""; }; AEEA33F61AC74FE700AB639D /* TypeSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeSystem.h; path = include/lldb/Symbol/TypeSystem.h; sourceTree = ""; }; AEEA34041AC88A7400AB639D /* TypeSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeSystem.cpp; path = source/Symbol/TypeSystem.cpp; sourceTree = ""; }; + AEEA340F1ACA08A000AB639D /* GoASTContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GoASTContext.h; path = include/lldb/Symbol/GoASTContext.h; sourceTree = ""; }; + AEFFBA7C1AC4835D0087B932 /* GoASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GoASTContext.cpp; path = source/Symbol/GoASTContext.cpp; sourceTree = ""; }; AF061F85182C97ED00B6A19C /* RegisterContextHistory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterContextHistory.cpp; path = Utility/RegisterContextHistory.cpp; sourceTree = ""; }; AF061F86182C97ED00B6A19C /* RegisterContextHistory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextHistory.h; path = Utility/RegisterContextHistory.h; sourceTree = ""; }; AF061F89182C980000B6A19C /* HistoryThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HistoryThread.h; path = Utility/HistoryThread.h; sourceTree = ""; }; @@ -3124,6 +3130,8 @@ 269DDD451B8FD01A00D0DBD8 /* DWARFASTParser.h */, 269DDD491B8FD1C300D0DBD8 /* DWARFASTParserClang.h */, 269DDD481B8FD1C300D0DBD8 /* DWARFASTParserClang.cpp */, + AE6897271B94F6DE0018845D /* DWARFASTParserGo.h */, + AE6897261B94F6DE0018845D /* DWARFASTParserGo.cpp */, 260C89B610F57C5600BB2B04 /* DWARFAttribute.h */, 266E829C1B8E542C008FCA06 /* DWARFAttribute.cpp */, 260C89B710F57C5600BB2B04 /* DWARFCompileUnit.cpp */, @@ -4208,6 +4216,8 @@ 26BC7F1810F1B8EC00F91463 /* Function.cpp */, 269FF07D12494F7D00225026 /* FuncUnwinders.h */, 961FABB81235DE1600F93A47 /* FuncUnwinders.cpp */, + AEEA340F1ACA08A000AB639D /* GoASTContext.h */, + AEFFBA7C1AC4835D0087B932 /* GoASTContext.cpp */, 26BC7C5B10F1B6E900F91463 /* LineEntry.h */, 26BC7F1910F1B8EC00F91463 /* LineEntry.cpp */, 26BC7C5C10F1B6E900F91463 /* LineTable.h */, @@ -6314,6 +6324,7 @@ 2689007C13353E1A00698AC0 /* Symbols.cpp in Sources */, 2689007D13353E2200698AC0 /* Args.cpp in Sources */, 2689007F13353E2200698AC0 /* CommandCompletions.cpp in Sources */, + AE6897281B94F6DE0018845D /* DWARFASTParserGo.cpp in Sources */, 945261C41B9A11FC00BF138D /* LibCxxUnorderedMap.cpp in Sources */, 26CEB5F218762056008F575A /* CommandObjectGUI.cpp in Sources */, 2689008013353E2200698AC0 /* CommandInterpreter.cpp in Sources */, @@ -6630,6 +6641,7 @@ 260CC64C15D0440D002BF2E0 /* OptionValueDictionary.cpp in Sources */, 49DCF6FE170E6B4A0092F75E /* IRMemoryMap.cpp in Sources */, 260CC64D15D0440D002BF2E0 /* OptionValueEnumeration.cpp in Sources */, + AE7F56291B8FE418001377A8 /* GoASTContext.cpp in Sources */, 260CC64E15D0440D002BF2E0 /* OptionValueFileSpec.cpp in Sources */, AF2BCA6C18C7EFDE005B4526 /* JITLoaderGDB.cpp in Sources */, 260CC64F15D0440D002BF2E0 /* OptionValueFileSpecLIst.cpp in Sources */, Index: lldb/trunk/source/Core/Module.cpp =================================================================== --- lldb/trunk/source/Core/Module.cpp +++ lldb/trunk/source/Core/Module.cpp @@ -25,6 +25,7 @@ #include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/GoASTContext.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolVendor.h" @@ -148,6 +149,7 @@ m_objfile_sp (), m_symfile_ap (), m_ast (new ClangASTContext), + m_go_ast(), m_source_mappings (), m_sections_ap(), m_did_load_objfile (false), @@ -252,6 +254,7 @@ m_objfile_sp (), m_symfile_ap (), m_ast (new ClangASTContext), + m_go_ast(), m_source_mappings (), m_sections_ap(), m_did_load_objfile (false), @@ -298,6 +301,7 @@ m_objfile_sp (), m_symfile_ap (), m_ast (new ClangASTContext), + m_go_ast(), m_source_mappings (), m_sections_ap(), m_did_load_objfile (false), @@ -420,7 +424,22 @@ TypeSystem * Module::GetTypeSystemForLanguage (LanguageType language) { - if (language != eLanguageTypeSwift) + if (language == eLanguageTypeGo) + { + Mutex::Locker locker (m_mutex); + if (!m_go_ast) + { + ObjectFile * objfile = GetObjectFile(); + ArchSpec object_arch; + if (objfile && objfile->GetArchitecture(object_arch)) + { + m_go_ast.reset(new GoASTContext); + m_go_ast->SetAddressByteSize(object_arch.GetAddressByteSize()); + } + } + return m_go_ast.get(); + } + else if (language != eLanguageTypeSwift) { // For now assume all languages except swift use the ClangASTContext for types return &GetClangASTContext(); Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/CMakeLists.txt =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -2,6 +2,7 @@ DIERef.cpp DWARFAbbreviationDeclaration.cpp DWARFASTParserClang.cpp + DWARFASTParserGo.cpp DWARFAttribute.cpp DWARFCompileUnit.cpp DWARFDataExtractor.cpp Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.h =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.h +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.h @@ -0,0 +1,66 @@ +//===-- DWARFASTParserGo.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SymbolFileDWARF_DWARFASTParserGo_h_ +#define SymbolFileDWARF_DWARFASTParserGo_h_ + +#include "DWARFDefines.h" +#include "DWARFASTParser.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" + +#include "lldb/Core/PluginInterface.h" +#include "lldb/Symbol/GoASTContext.h" + +class DWARFDebugInfoEntry; +class DWARFDIECollection; + +class DWARFASTParserGo : public DWARFASTParser +{ + public: + DWARFASTParserGo(lldb_private::GoASTContext &ast); + + virtual ~DWARFASTParserGo(); + + lldb::TypeSP ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, const DWARFDIE &die, lldb_private::Log *log, + bool *type_is_new_ptr) override; + + virtual lldb_private::Function *ParseFunctionFromDWARF(const lldb_private::SymbolContext &sc, + const DWARFDIE &die) override; + + virtual bool CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, + lldb_private::CompilerType &go_type) override; + + virtual lldb_private::CompilerDeclContext + GetDeclContextForUIDFromDWARF(const DWARFDIE &die) override + { + return lldb_private::CompilerDeclContext(); + } + + virtual lldb_private::CompilerDeclContext + GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) override + { + return lldb_private::CompilerDeclContext(); + } + + private: + size_t ParseChildParameters(const lldb_private::SymbolContext &sc, const DWARFDIE &parent_die, bool &is_variadic, + std::vector &function_param_types); + void ParseChildArrayInfo(const lldb_private::SymbolContext &sc, const DWARFDIE &parent_die, int64_t &first_index, + std::vector &element_orders, uint32_t &byte_stride, uint32_t &bit_stride); + + size_t ParseChildMembers(const lldb_private::SymbolContext &sc, const DWARFDIE &die, + lldb_private::CompilerType &class_clang_type); + + lldb_private::GoASTContext &m_ast; +}; + +#endif // SymbolFileDWARF_DWARFASTParserGo_h_ Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp @@ -0,0 +1,828 @@ +//===-- DWARFASTParserGo.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFASTParserGo.h" + +#include "DWARFASTParserGo.h" +#include "DWARFCompileUnit.h" +#include "DWARFDebugInfo.h" +#include "DWARFDeclContext.h" +#include "DWARFDefines.h" +#include "DWARFDIE.h" +#include "DWARFDIECollection.h" +#include "SymbolFileDWARF.h" +#include "SymbolFileDWARFDebugMap.h" +#include "UniqueDWARFASTType.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/Value.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/TypeList.h" + +//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN + +#ifdef ENABLE_DEBUG_PRINTF +#include +#define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__) +#else +#define DEBUG_PRINTF(fmt, ...) +#endif + +#define DW_AT_go_kind 0x2900 +#define DW_AT_go_key 0x2901 +#define DW_AT_go_elem 0x2902 + +using namespace lldb; +using namespace lldb_private; +DWARFASTParserGo::DWARFASTParserGo(GoASTContext &ast) + : m_ast(ast) +{ +} + +DWARFASTParserGo::~DWARFASTParserGo() +{ +} + +TypeSP +DWARFASTParserGo::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, const DWARFDIE &die, lldb_private::Log *log, + bool *type_is_new_ptr) +{ + TypeSP type_sp; + + if (type_is_new_ptr) + *type_is_new_ptr = false; + + if (die) + { + SymbolFileDWARF *dwarf = die.GetDWARF(); + if (log) + { + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, "DWARFASTParserGo::ParseTypeFromDWARF (die = 0x%8.8x) %s name = '%s')", die.GetOffset(), + DW_TAG_value_to_name(die.Tag()), die.GetName()); + } + + Type *type_ptr = dwarf->m_die_to_type.lookup(die.GetDIE()); + TypeList *type_list = dwarf->GetTypeList(); + if (type_ptr == NULL) + { + if (type_is_new_ptr) + *type_is_new_ptr = true; + + const dw_tag_t tag = die.Tag(); + + bool is_forward_declaration = false; + DWARFAttributes attributes; + const char *type_name_cstr = NULL; + ConstString type_name_const_str; + Type::ResolveState resolve_state = Type::eResolveStateUnresolved; + uint64_t byte_size = 0; + uint64_t go_kind = 0; + Declaration decl; + + Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; + CompilerType clang_type; + DWARFFormValue form_value; + + dw_attr_t attr; + + switch (tag) + { + case DW_TAG_base_type: + case DW_TAG_pointer_type: + case DW_TAG_typedef: + case DW_TAG_unspecified_type: + { + // Set a bit that lets us know that we are currently parsing this + dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; + + const size_t num_attributes = die.GetAttributes(attributes); + uint32_t encoding = 0; + lldb::user_id_t encoding_uid = LLDB_INVALID_UID; + + if (num_attributes > 0) + { + uint32_t i; + for (i = 0; i < num_attributes; ++i) + { + attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attr) + { + case DW_AT_name: + type_name_cstr = form_value.AsCString(); + if (type_name_cstr) + type_name_const_str.SetCString(type_name_cstr); + break; + case DW_AT_byte_size: + byte_size = form_value.Unsigned(); + break; + case DW_AT_encoding: + encoding = form_value.Unsigned(); + break; + case DW_AT_type: + encoding_uid = form_value.Reference(); + break; + case DW_AT_go_kind: + go_kind = form_value.Unsigned(); + break; + default: + // Do we care about DW_AT_go_key or DW_AT_go_elem? + break; + } + } + } + } + + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8lx\n", dwarf->MakeUserID(die.GetOffset()), + DW_TAG_value_to_name(tag), type_name_cstr, encoding_uid); + + switch (tag) + { + default: + break; + + case DW_TAG_unspecified_type: + resolve_state = Type::eResolveStateFull; + clang_type = m_ast.CreateVoidType(type_name_const_str); + break; + + case DW_TAG_base_type: + resolve_state = Type::eResolveStateFull; + clang_type = m_ast.CreateBaseType(go_kind, type_name_const_str, byte_size); + break; + + case DW_TAG_pointer_type: + encoding_data_type = Type::eEncodingIsPointerUID; + break; + case DW_TAG_typedef: + encoding_data_type = Type::eEncodingIsTypedefUID; + CompilerType impl; + Type *type = dwarf->ResolveTypeUID(encoding_uid); + if (type) + { + if (go_kind == 0 && type->GetName() == type_name_const_str) + { + // Go emits extra typedefs as a forward declaration. Ignore these. + dwarf->m_die_to_type[die.GetDIE()] = type; + return type->shared_from_this(); + } + impl = type->GetForwardCompilerType(); + clang_type = m_ast.CreateTypedef(go_kind, type_name_const_str, impl); + } + break; + } + + type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, byte_size, + NULL, encoding_uid, encoding_data_type, &decl, clang_type, resolve_state)); + + dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); + } + break; + + case DW_TAG_structure_type: + { + // Set a bit that lets us know that we are currently parsing this + dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; + bool byte_size_valid = false; + + const size_t num_attributes = die.GetAttributes(attributes); + if (num_attributes > 0) + { + uint32_t i; + for (i = 0; i < num_attributes; ++i) + { + attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attr) + { + case DW_AT_name: + type_name_cstr = form_value.AsCString(); + type_name_const_str.SetCString(type_name_cstr); + break; + + case DW_AT_byte_size: + byte_size = form_value.Unsigned(); + byte_size_valid = true; + break; + + case DW_AT_go_kind: + go_kind = form_value.Unsigned(); + break; + + // TODO: Should we use SLICETYPE's DW_AT_go_elem? + default: + break; + } + } + } + } + + // TODO(ribrdb): Do we need this? + + // UniqueDWARFASTType is large, so don't create a local variables on the + // stack, put it on the heap. This function is often called recursively + // and clang isn't good and sharing the stack space for variables in different blocks. + std::unique_ptr unique_ast_entry_ap(new UniqueDWARFASTType()); + + // Only try and unique the type if it has a name. + if (type_name_const_str && + dwarf->GetUniqueDWARFASTTypeMap().Find(type_name_const_str, die, decl, + byte_size_valid ? byte_size : -1, *unique_ast_entry_ap)) + { + // We have already parsed this type or from another + // compile unit. GCC loves to use the "one definition + // rule" which can result in multiple definitions + // of the same class over and over in each compile + // unit. + type_sp = unique_ast_entry_ap->m_type_sp; + if (type_sp) + { + dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); + return type_sp; + } + } + + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", dwarf->MakeUserID(die.GetOffset()), + DW_TAG_value_to_name(tag), type_name_cstr); + + bool clang_type_was_created = false; + clang_type.SetCompilerType(&m_ast, dwarf->m_forward_decl_die_to_clang_type.lookup(die.GetDIE())); + if (!clang_type) + { + clang_type_was_created = true; + clang_type = m_ast.CreateStructType(go_kind, type_name_const_str, byte_size); + } + + type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, byte_size, + NULL, LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, clang_type, + Type::eResolveStateForward)); + + // Add our type to the unique type map so we don't + // end up creating many copies of the same type over + // and over in the ASTContext for our module + unique_ast_entry_ap->m_type_sp = type_sp; + unique_ast_entry_ap->m_die = die; + unique_ast_entry_ap->m_declaration = decl; + unique_ast_entry_ap->m_byte_size = byte_size; + dwarf->GetUniqueDWARFASTTypeMap().Insert(type_name_const_str, *unique_ast_entry_ap); + + if (!is_forward_declaration) + { + // Always start the definition for a class type so that + // if the class has child classes or types that require + // the class to be created for use as their decl contexts + // the class will be ready to accept these child definitions. + if (die.HasChildren() == false) + { + // No children for this struct/union/class, lets finish it + m_ast.CompleteStructType(clang_type); + } + else if (clang_type_was_created) + { + // Leave this as a forward declaration until we need + // to know the details of the type. lldb_private::Type + // will automatically call the SymbolFile virtual function + // "SymbolFileDWARF::CompleteType(Type *)" + // When the definition needs to be defined. + dwarf->m_forward_decl_die_to_clang_type[die.GetDIE()] = clang_type.GetOpaqueQualType(); + dwarf->m_forward_decl_clang_type_to_die[clang_type.GetOpaqueQualType()] = die.GetDIERef(); + // SetHasExternalStorage (clang_type.GetOpaqueQualType(), true); + } + } + } + break; + + case DW_TAG_subprogram: + case DW_TAG_subroutine_type: + { + // Set a bit that lets us know that we are currently parsing this + dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; + + bool is_variadic = false; + clang::StorageClass storage = clang::SC_None; //, Extern, Static, PrivateExtern + + const size_t num_attributes = die.GetAttributes(attributes); + if (num_attributes > 0) + { + uint32_t i; + for (i = 0; i < num_attributes; ++i) + { + attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attr) + { + case DW_AT_name: + type_name_cstr = form_value.AsCString(); + type_name_const_str.SetCString(type_name_cstr); + break; + + case DW_AT_external: + if (form_value.Unsigned()) + { + if (storage == clang::SC_None) + storage = clang::SC_Extern; + else + storage = clang::SC_PrivateExtern; + } + break; + + case DW_AT_high_pc: + case DW_AT_low_pc: + break; + } + } + } + } + + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", dwarf->MakeUserID(die.GetOffset()), + DW_TAG_value_to_name(tag), type_name_cstr); + + std::vector function_param_types; + + // Parse the function children for the parameters + + if (die.HasChildren()) + { + ParseChildParameters(sc, die, is_variadic, function_param_types); + } + + // clang_type will get the function prototype clang type after this call + clang_type = m_ast.CreateFunctionType(type_name_const_str, function_param_types.data(), + function_param_types.size(), is_variadic); + + type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, 0, NULL, + LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, clang_type, + Type::eResolveStateFull)); + assert(type_sp.get()); + } + break; + + case DW_TAG_array_type: + { + // Set a bit that lets us know that we are currently parsing this + dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; + + lldb::user_id_t type_die_offset = DW_INVALID_OFFSET; + int64_t first_index = 0; + uint32_t byte_stride = 0; + uint32_t bit_stride = 0; + const size_t num_attributes = die.GetAttributes(attributes); + + if (num_attributes > 0) + { + uint32_t i; + for (i = 0; i < num_attributes; ++i) + { + attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attr) + { + case DW_AT_name: + type_name_cstr = form_value.AsCString(); + type_name_const_str.SetCString(type_name_cstr); + break; + + case DW_AT_type: + type_die_offset = form_value.Reference(); + break; + case DW_AT_byte_size: + break; // byte_size = form_value.Unsigned(); break; + case DW_AT_go_kind: + go_kind = form_value.Unsigned(); + break; + default: + break; + } + } + } + + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", dwarf->MakeUserID(die.GetOffset()), + DW_TAG_value_to_name(tag), type_name_cstr); + + Type *element_type = dwarf->ResolveTypeUID(type_die_offset); + + if (element_type) + { + std::vector element_orders; + ParseChildArrayInfo(sc, die, first_index, element_orders, byte_stride, bit_stride); + if (byte_stride == 0) + byte_stride = element_type->GetByteSize(); + CompilerType array_element_type = element_type->GetForwardCompilerType(); + if (element_orders.size() > 0) + { + if (element_orders.size() > 1) + printf("golang: unsupported multi-dimensional array %s\n", type_name_cstr); + clang_type = + m_ast.CreateArrayType(type_name_const_str, array_element_type, element_orders[0]); + } + else + { + clang_type = m_ast.CreateArrayType(type_name_const_str, array_element_type, 0); + } + type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, + byte_stride, NULL, type_die_offset, Type::eEncodingIsUID, &decl, + clang_type, Type::eResolveStateFull)); + type_sp->SetEncodingType(element_type); + } + } + } + break; + + default: + dwarf->GetObjectFile()->GetModule()->ReportError("{0x%8.8x}: unhandled type tag 0x%4.4x (%s), " + "please file a bug and attach the file at the " + "start of this error message", + die.GetOffset(), tag, DW_TAG_value_to_name(tag)); + break; + } + + if (type_sp.get()) + { + DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die); + dw_tag_t sc_parent_tag = sc_parent_die.Tag(); + + SymbolContextScope *symbol_context_scope = NULL; + if (sc_parent_tag == DW_TAG_compile_unit) + { + symbol_context_scope = sc.comp_unit; + } + else if (sc.function != NULL && sc_parent_die) + { + symbol_context_scope = + sc.function->GetBlock(true).FindBlockByID(dwarf->MakeUserID(sc_parent_die.GetOffset())); + if (symbol_context_scope == NULL) + symbol_context_scope = sc.function; + } + + if (symbol_context_scope != NULL) + { + type_sp->SetSymbolContextScope(symbol_context_scope); + } + + // We are ready to put this type into the uniqued list up at the module level + type_list->Insert(type_sp); + + dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); + } + } + else if (type_ptr != DIE_IS_BEING_PARSED) + { + type_sp = type_ptr->shared_from_this(); + } + } + return type_sp; +} + +size_t +DWARFASTParserGo::ParseChildParameters(const SymbolContext &sc, + + const DWARFDIE &parent_die, bool &is_variadic, + std::vector &function_param_types) +{ + if (!parent_die) + return 0; + + size_t arg_idx = 0; + for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling()) + { + + dw_tag_t tag = die.Tag(); + switch (tag) + { + case DW_TAG_formal_parameter: + { + DWARFAttributes attributes; + const size_t num_attributes = die.GetAttributes(attributes); + if (num_attributes > 0) + { + const char *name = NULL; + Declaration decl; + dw_offset_t param_type_die_offset = DW_INVALID_OFFSET; + + uint32_t i; + for (i = 0; i < num_attributes; ++i) + { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attr) + { + case DW_AT_name: + name = form_value.AsCString(); + break; + case DW_AT_type: + param_type_die_offset = form_value.Reference(); + break; + case DW_AT_location: + // if (form_value.BlockData()) + // { + // const DWARFDataExtractor& debug_info_data = + // debug_info(); + // uint32_t block_length = form_value.Unsigned(); + // DWARFDataExtractor location(debug_info_data, + // form_value.BlockData() - debug_info_data.GetDataStart(), + // block_length); + // } + // else + // { + // } + // break; + default: + break; + } + } + } + + Type *type = parent_die.ResolveTypeUID(param_type_die_offset); + if (type) + { + function_param_types.push_back(type->GetForwardCompilerType()); + } + } + arg_idx++; + } + break; + + case DW_TAG_unspecified_parameters: + is_variadic = true; + break; + + default: + break; + } + } + return arg_idx; +} + +void +DWARFASTParserGo::ParseChildArrayInfo(const SymbolContext &sc, const DWARFDIE &parent_die, int64_t &first_index, + std::vector &element_orders, uint32_t &byte_stride, + uint32_t &bit_stride) +{ + if (!parent_die) + return; + + for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling()) + { + const dw_tag_t tag = die.Tag(); + switch (tag) + { + case DW_TAG_subrange_type: + { + DWARFAttributes attributes; + const size_t num_child_attributes = die.GetAttributes(attributes); + if (num_child_attributes > 0) + { + uint64_t num_elements = 0; + uint32_t i; + for (i = 0; i < num_child_attributes; ++i) + { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attr) + { + case DW_AT_count: + num_elements = form_value.Unsigned(); + break; + + default: + case DW_AT_type: + break; + } + } + } + + element_orders.push_back(num_elements); + } + } + break; + } + } +} + +bool +DWARFASTParserGo::CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, CompilerType &clang_type) +{ + if (!die) + return false; + + const dw_tag_t tag = die.Tag(); + + SymbolFileDWARF *dwarf = die.GetDWARF(); + Log *log = nullptr; // (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION)); + if (log) + dwarf->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( + log, "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...", dwarf->MakeUserID(die.GetOffset()), + DW_TAG_value_to_name(tag), type->GetName().AsCString()); + assert(clang_type); + DWARFAttributes attributes; + + switch (tag) + { + case DW_TAG_structure_type: + { + { + if (die.HasChildren()) + { + SymbolContext sc(die.GetLLDBCompileUnit()); + + ParseChildMembers(sc, die, clang_type); + } + } + m_ast.CompleteStructType(clang_type); + return (bool)clang_type; + } + + default: + assert(false && "not a forward go type decl!"); + break; + } + + return false; +} + +size_t +DWARFASTParserGo::ParseChildMembers(const SymbolContext &sc, const DWARFDIE &parent_die, CompilerType &class_clang_type) +{ + size_t count = 0; + uint32_t member_idx = 0; + + ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); + GoASTContext *ast = llvm::dyn_cast_or_null(class_clang_type.GetTypeSystem()); + if (ast == nullptr) + return 0; + + for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling()) + { + dw_tag_t tag = die.Tag(); + + switch (tag) + { + case DW_TAG_member: + { + DWARFAttributes attributes; + const size_t num_attributes = die.GetAttributes(attributes); + if (num_attributes > 0) + { + Declaration decl; + const char *name = NULL; + + lldb::user_id_t encoding_uid = LLDB_INVALID_UID; + uint32_t member_byte_offset = UINT32_MAX; + uint32_t i; + for (i = 0; i < num_attributes; ++i) + { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attr) + { + case DW_AT_name: + name = form_value.AsCString(); + break; + case DW_AT_type: + encoding_uid = form_value.Reference(); + break; + case DW_AT_data_member_location: + if (form_value.BlockData()) + { + Value initialValue(0); + Value memberOffset(0); + const DWARFDataExtractor &debug_info_data = + die.GetDWARF()->get_debug_info_data(); + uint32_t block_length = form_value.Unsigned(); + uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); + if (DWARFExpression::Evaluate(NULL, // ExecutionContext * + NULL, // ClangExpressionVariableList * + NULL, // ClangExpressionDeclMap * + NULL, // RegisterContext * + module_sp, debug_info_data, die.GetCU(), + block_offset, block_length, eRegisterKindDWARF, + &initialValue, memberOffset, NULL)) + { + member_byte_offset = memberOffset.ResolveValue(NULL).UInt(); + } + } + else + { + // With DWARF 3 and later, if the value is an integer constant, + // this form value is the offset in bytes from the beginning + // of the containing entity. + member_byte_offset = form_value.Unsigned(); + } + break; + + default: + break; + } + } + } + + Type *member_type = die.ResolveTypeUID(encoding_uid); + if (member_type) + { + CompilerType member_go_type = member_type->GetFullCompilerType(); + ConstString name_const_str(name); + m_ast.AddFieldToStruct(class_clang_type, name_const_str, member_go_type, member_byte_offset); + } + } + ++member_idx; + } + break; + + default: + break; + } + } + + return count; +} + +Function * +DWARFASTParserGo::ParseFunctionFromDWARF(const SymbolContext &sc, const DWARFDIE &die) +{ + DWARFRangeList func_ranges; + const char *name = NULL; + const char *mangled = NULL; + int decl_file = 0; + int decl_line = 0; + int decl_column = 0; + int call_file = 0; + int call_line = 0; + int call_column = 0; + DWARFExpression frame_base(die.GetCU()); + + assert(die.Tag() == DW_TAG_subprogram); + + if (die.Tag() != DW_TAG_subprogram) + return NULL; + + if (die.GetDIENamesAndRanges(name, mangled, func_ranges, decl_file, decl_line, decl_column, call_file, call_line, + call_column, &frame_base)) + { + // Union of all ranges in the function DIE (if the function is discontiguous) + AddressRange func_range; + lldb::addr_t lowest_func_addr = func_ranges.GetMinRangeBase(0); + lldb::addr_t highest_func_addr = func_ranges.GetMaxRangeEnd(0); + if (lowest_func_addr != LLDB_INVALID_ADDRESS && lowest_func_addr <= highest_func_addr) + { + ModuleSP module_sp(die.GetModule()); + func_range.GetBaseAddress().ResolveAddressUsingFileSections(lowest_func_addr, module_sp->GetSectionList()); + if (func_range.GetBaseAddress().IsValid()) + func_range.SetByteSize(highest_func_addr - lowest_func_addr); + } + + if (func_range.GetBaseAddress().IsValid()) + { + Mangled func_name; + func_name.SetValue(ConstString(name), false); + + FunctionSP func_sp; + std::unique_ptr decl_ap; + if (decl_file != 0 || decl_line != 0 || decl_column != 0) + decl_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), decl_line, + decl_column)); + + SymbolFileDWARF *dwarf = die.GetDWARF(); + // Supply the type _only_ if it has already been parsed + Type *func_type = dwarf->m_die_to_type.lookup(die.GetDIE()); + + assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED); + + if (dwarf->FixupAddress(func_range.GetBaseAddress())) + { + const user_id_t func_user_id = dwarf->MakeUserID(die.GetOffset()); + func_sp.reset(new Function(sc.comp_unit, + dwarf->MakeUserID(func_user_id), // UserID is the DIE offset + dwarf->MakeUserID(func_user_id), func_name, func_type, + func_range)); // first address range + + if (func_sp.get() != NULL) + { + if (frame_base.IsValid()) + func_sp->GetFrameBaseExpression() = frame_base; + sc.comp_unit->AddFunction(func_sp); + return func_sp.get(); + } + } + } + } + return NULL; +} Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -69,6 +69,7 @@ friend class DebugMapModule; friend class DWARFCompileUnit; friend class DWARFASTParserClang; + friend class DWARFASTParserGo; //------------------------------------------------------------------ // Static Functions Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -49,6 +49,7 @@ #include "lldb/Symbol/Block.h" #include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/GoASTContext.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolVendor.h" @@ -507,10 +508,18 @@ SymbolFileDWARF::GetTypeSystemForLanguage (LanguageType language) { SymbolFileDWARFDebugMap * debug_map_symfile = GetDebugMapSymfile (); + TypeSystem *type_system; if (debug_map_symfile) - return debug_map_symfile->GetTypeSystemForLanguage (language); + { + type_system = debug_map_symfile->GetTypeSystemForLanguage(language); + } else - return m_obj_file->GetModule()->GetTypeSystemForLanguage (language); + { + type_system = m_obj_file->GetModule()->GetTypeSystemForLanguage(language); + if (type_system) + type_system->SetSymbolFile(this); + } + return type_system; } void Index: lldb/trunk/source/Symbol/CMakeLists.txt =================================================================== --- lldb/trunk/source/Symbol/CMakeLists.txt +++ lldb/trunk/source/Symbol/CMakeLists.txt @@ -12,6 +12,7 @@ DWARFCallFrameInfo.cpp Function.cpp FuncUnwinders.cpp + GoASTContext.cpp LineEntry.cpp LineTable.cpp ObjectFile.cpp Index: lldb/trunk/source/Symbol/ClangASTContext.cpp =================================================================== --- lldb/trunk/source/Symbol/ClangASTContext.cpp +++ lldb/trunk/source/Symbol/ClangASTContext.cpp @@ -3021,7 +3021,7 @@ bool ClangASTContext::IsObjCObjectOrInterfaceType (const CompilerType& type) { - if (type) + if (IsClangType(type)) return GetCanonicalQualType(type)->isObjCObjectOrInterfaceType(); return false; } @@ -3269,12 +3269,14 @@ if (type) { clang::QualType qual_type (GetCanonicalQualType(type)); - - clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); - if (cxx_record_decl) + if (!qual_type.isNull()) { - class_name.assign (cxx_record_decl->getIdentifier()->getNameStart()); - return true; + clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + class_name.assign(cxx_record_decl->getIdentifier()->getNameStart()); + return true; + } } } class_name.clear(); @@ -3289,7 +3291,7 @@ return false; clang::QualType qual_type (GetCanonicalQualType(type)); - if (qual_type->getAsCXXRecordDecl() != nullptr) + if (!qual_type.isNull() && qual_type->getAsCXXRecordDecl() != nullptr) return true; return false; } @@ -3313,8 +3315,8 @@ return false; clang::QualType qual_type (GetCanonicalQualType(type)); - - if (qual_type->isObjCObjectPointerType()) + + if (!qual_type.isNull() && qual_type->isObjCObjectPointerType()) { if (class_type_ptr) { @@ -3750,7 +3752,7 @@ CompilerType ClangASTContext::AddConstModifier (const CompilerType& type) { - if (type && llvm::dyn_cast(type.GetTypeSystem())) + if (IsClangType(type)) { // Make sure this type is a clang AST type clang::QualType result(GetQualType(type)); @@ -3764,7 +3766,7 @@ CompilerType ClangASTContext::AddRestrictModifier (const CompilerType& type) { - if (type && llvm::dyn_cast(type.GetTypeSystem())) + if (IsClangType(type)) { clang::QualType result(GetQualType(type)); result.getQualifiers().setRestrict (true); @@ -3776,7 +3778,7 @@ CompilerType ClangASTContext::AddVolatileModifier (const CompilerType& type) { - if (type && llvm::dyn_cast(type.GetTypeSystem())) + if (IsClangType(type)) { clang::QualType result(GetQualType(type)); result.getQualifiers().setVolatile (true); @@ -4077,11 +4079,10 @@ CompilerType ClangASTContext::GetLValueReferenceType (const CompilerType& type) { - if (type) + if (IsClangType(type)) { ClangASTContext *ast = llvm::dyn_cast(type.GetTypeSystem()); - if (ast) - return CompilerType(ast->getASTContext(), ast->getASTContext()->getLValueReferenceType(GetQualType(type))); + return CompilerType(ast->getASTContext(), ast->getASTContext()->getLValueReferenceType(GetQualType(type))); } return CompilerType(); } @@ -4089,11 +4090,10 @@ CompilerType ClangASTContext::GetRValueReferenceType (const CompilerType& type) { - if (type) + if (IsClangType(type)) { ClangASTContext *ast = llvm::dyn_cast(type.GetTypeSystem()); - if (ast) - return CompilerType(ast->getASTContext(), ast->getASTContext()->getRValueReferenceType(GetQualType(type))); + return CompilerType(ast->getASTContext(), ast->getASTContext()->getRValueReferenceType(GetQualType(type))); } return CompilerType(); } @@ -4186,7 +4186,7 @@ CompilerType ClangASTContext::RemoveFastQualifiers (const CompilerType& type) { - if (type && llvm::dyn_cast(type.GetTypeSystem())) + if (IsClangType(type)) { clang::QualType qual_type(GetQualType(type)); qual_type.getQualifiers().removeFastQualifiers(); Index: lldb/trunk/source/Symbol/GoASTContext.cpp =================================================================== --- lldb/trunk/source/Symbol/GoASTContext.cpp +++ lldb/trunk/source/Symbol/GoASTContext.cpp @@ -0,0 +1,1417 @@ +//===-- GoASTContext.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +#include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/StringPrinter.h" +#include "lldb/Symbol/CompilerType.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/GoASTContext.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Target/ExecutionContext.h" + +#include "Plugins/SymbolFile/DWARF/DWARFASTParserGo.h" + +using namespace lldb; + +namespace lldb_private +{ +class GoArray; +class GoFunction; +class GoStruct; + +class GoType +{ + public: + enum + { + KIND_BOOL = 1, + KIND_INT = 2, + KIND_INT8 = 3, + KIND_INT16 = 4, + KIND_INT32 = 5, + KIND_INT64 = 6, + KIND_UINT = 7, + KIND_UINT8 = 8, + KIND_UINT16 = 9, + KIND_UINT32 = 10, + KIND_UINT64 = 11, + KIND_UINTPTR = 12, + KIND_FLOAT32 = 13, + KIND_FLOAT64 = 14, + KIND_COMPLEX64 = 15, + KIND_COMPLEX128 = 16, + KIND_ARRAY = 17, + KIND_CHAN = 18, + KIND_FUNC = 19, + KIND_INTERFACE = 20, + KIND_MAP = 21, + KIND_PTR = 22, + KIND_SLICE = 23, + KIND_STRING = 24, + KIND_STRUCT = 25, + KIND_UNSAFEPOINTER = 26, + KIND_LLDB_VOID, // Extension for LLDB, not used by go runtime. + KIND_MASK = (1 << 5) - 1, + KIND_DIRECT_IFACE = 1 << 5 + }; + GoType(int kind, const ConstString &name) + : m_kind(kind & KIND_MASK) + , m_name(name) + { + if (m_kind == KIND_FUNC) + m_kind = KIND_FUNC; + } + virtual ~GoType() {} + + int + GetGoKind() const + { + return m_kind; + } + const ConstString & + GetName() const + { + return m_name; + } + virtual CompilerType + GetElementType() const + { + return CompilerType(); + } + + bool + IsTypedef() const + { + switch (m_kind) + { + case KIND_CHAN: + case KIND_MAP: + case KIND_INTERFACE: + return true; + default: + return false; + } + } + + GoArray *GetArray(); + GoFunction *GetFunction(); + GoStruct *GetStruct(); + + private: + int m_kind; + ConstString m_name; + GoType(const GoType &) = delete; + const GoType &operator=(const GoType &) = delete; +}; + +class GoElem : public GoType +{ + public: + GoElem(int kind, const ConstString &name, const CompilerType &elem) + : GoType(kind, name) + , m_elem(elem) + { + } + virtual CompilerType + GetElementType() const + { + return m_elem; + } + + private: + // TODO: should we store this differently? + CompilerType m_elem; + + GoElem(const GoElem &) = delete; + const GoElem &operator=(const GoElem &) = delete; +}; + +class GoArray : public GoElem +{ + public: + GoArray(const ConstString &name, int64_t length, const CompilerType &elem) + : GoElem(KIND_ARRAY, name, elem) + , m_length(length) + { + } + + int64_t + GetLength() const + { + return m_length; + } + + private: + int64_t m_length; + GoArray(const GoArray &) = delete; + const GoArray &operator=(const GoArray &) = delete; +}; + +class GoFunction : public GoType +{ + public: + GoFunction(const ConstString &name, bool is_variadic) + : GoType(KIND_FUNC, name) + , m_is_variadic(is_variadic) + { + } + + bool + IsVariadic() const + { + return m_is_variadic; + } + + private: + bool m_is_variadic; + GoFunction(const GoFunction &) = delete; + const GoFunction &operator=(const GoFunction &) = delete; +}; + +class GoStruct : public GoType +{ + public: + struct Field + { + Field(const ConstString &name, const CompilerType &type, uint64_t offset) + : m_name(name) + , m_type(type) + , m_byte_offset(offset) + { + } + ConstString m_name; + CompilerType m_type; + uint64_t m_byte_offset; + }; + + GoStruct(int kind, const ConstString &name, int64_t byte_size) + : GoType(kind, name) + , m_is_complete(false) + , m_byte_size(byte_size) + { + } + + uint32_t + GetNumFields() const + { + return m_fields.size(); + } + + const Field * + GetField(uint32_t i) const + { + if (i < m_fields.size()) + return &m_fields[i]; + return nullptr; + } + + void + AddField(const ConstString &name, const CompilerType &type, uint64_t offset) + { + m_fields.push_back(Field(name, type, offset)); + } + + bool + IsComplete() const + { + return m_is_complete; + } + + void + SetComplete() + { + m_is_complete = true; + } + + int64_t + GetByteSize() const + { + return m_byte_size; + } + + private: + bool m_is_complete; + int64_t m_byte_size; + std::vector m_fields; + + GoStruct(const GoStruct &) = delete; + const GoStruct &operator=(const GoStruct &) = delete; +}; + +GoArray * +GoType::GetArray() +{ + if (m_kind == KIND_ARRAY) + { + return static_cast(this); + } + return nullptr; +} + +GoFunction * +GoType::GetFunction() +{ + if (m_kind == KIND_FUNC) + { + return static_cast(this); + } + return nullptr; +} + +GoStruct * +GoType::GetStruct() +{ + switch (m_kind) + { + case KIND_STRING: + case KIND_STRUCT: + case KIND_SLICE: + return static_cast(this); + } + return nullptr; +} +} // namespace lldb_private +using namespace lldb_private; + +GoASTContext::GoASTContext() + : TypeSystem(eKindGo) + , m_pointer_byte_size(0) + , m_int_byte_size(0) + , m_types(new TypeMap) +{ +} +GoASTContext::~GoASTContext() +{ +} + +//---------------------------------------------------------------------- +// Tests +//---------------------------------------------------------------------- + +bool +GoASTContext::IsArrayType(void *type, CompilerType *element_type, uint64_t *size, bool *is_incomplete) +{ + if (element_type) + element_type->Clear(); + if (size) + *size = 0; + if (is_incomplete) + *is_incomplete = false; + GoArray *array = static_cast(type)->GetArray(); + if (array) + { + if (array->GetLength() == -1) + { + if (is_incomplete) + { + *is_incomplete = true; + } + } + else if (size) + { + *size = array->GetLength(); + } + if (element_type) + *element_type = array->GetElementType(); + return true; + } + return false; +} + +bool +GoASTContext::IsVectorType(void *type, CompilerType *element_type, uint64_t *size) +{ + if (element_type) + element_type->Clear(); + if (size) + *size = 0; + return false; +} + +bool +GoASTContext::IsAggregateType(void *type) +{ + int kind = static_cast(type)->GetGoKind(); + if (kind < GoType::KIND_ARRAY) + return false; + if (kind == GoType::KIND_PTR) + return false; + if (kind == GoType::KIND_STRING) + return false; + if (kind == GoType::KIND_UNSAFEPOINTER) + return false; + return true; +} + +bool +GoASTContext::IsBeingDefined(void *type) +{ + return false; +} + +bool +GoASTContext::IsCharType(void *type) +{ + // Go's DWARF doesn't distinguish between rune and int32. + return false; +} + +bool +GoASTContext::IsCompleteType(void *type) +{ + if (!type) + return false; + GoType *t = static_cast(type); + if (GoStruct *s = t->GetStruct()) + return s->IsComplete(); + if (t->IsTypedef() || t->GetGoKind() == GoType::KIND_PTR) + return t->GetElementType().IsCompleteType(); + return true; +} + +bool +GoASTContext::IsConst(void *type) +{ + return false; +} + +bool +GoASTContext::IsCStringType(void *type, uint32_t &length) +{ + return false; +} + +bool +GoASTContext::IsDefined(void *type) +{ + return type != nullptr; +} + +bool +GoASTContext::IsFloatingPointType(void *type, uint32_t &count, bool &is_complex) +{ + int kind = static_cast(type)->GetGoKind(); + if (kind >= GoType::KIND_FLOAT32 && kind <= GoType::KIND_COMPLEX128) + { + if (kind >= GoType::KIND_COMPLEX64) + { + is_complex = true; + count = 2; + } + else + { + is_complex = false; + count = 1; + } + return true; + } + count = 0; + is_complex = false; + return false; +} + +bool +GoASTContext::IsFunctionType(void *type, bool *is_variadic_ptr) +{ + GoFunction *func = static_cast(type)->GetFunction(); + if (func) + { + if (is_variadic_ptr) + *is_variadic_ptr = func->IsVariadic(); + return true; + } + if (is_variadic_ptr) + *is_variadic_ptr = false; + return false; +} + +uint32_t +GoASTContext::IsHomogeneousAggregate(void *type, CompilerType *base_type_ptr) +{ + return false; +} + +size_t +GoASTContext::GetNumberOfFunctionArguments(void *type) +{ + return 0; +} + +CompilerType +GoASTContext::GetFunctionArgumentAtIndex(void *type, const size_t index) +{ + return CompilerType(); +} + +bool +GoASTContext::IsFunctionPointerType(void *type) +{ + return IsFunctionType(type); +} + +bool +GoASTContext::IsIntegerType(void *type, bool &is_signed) +{ + is_signed = false; + // TODO: Is bool an integer? + if (type) + { + int kind = static_cast(type)->GetGoKind(); + if (kind <= GoType::KIND_UINTPTR) + { + is_signed = (kind != GoType::KIND_BOOL) & (kind <= GoType::KIND_INT64); + return true; + } + } + return false; +} + +bool +GoASTContext::IsPolymorphicClass(void *type) +{ + return false; +} + +bool +GoASTContext::IsPossibleDynamicType(void *type, + CompilerType *target_type, // Can pass NULL + bool check_cplusplus, bool check_objc) +{ + if (target_type) + target_type->Clear(); + if (type) + return static_cast(type)->GetGoKind() == GoType::KIND_INTERFACE; + return false; +} + +bool +GoASTContext::IsRuntimeGeneratedType(void *type) +{ + return false; +} + +bool +GoASTContext::IsPointerType(void *type, CompilerType *pointee_type) +{ + if (!type) + return false; + GoType *t = static_cast(type); + if (pointee_type) + { + *pointee_type = t->GetElementType(); + } + switch (t->GetGoKind()) + { + case GoType::KIND_PTR: + case GoType::KIND_UNSAFEPOINTER: + case GoType::KIND_CHAN: + // TODO: is map a pointer? string? function? + return true; + default: + return false; + } +} + +bool +GoASTContext::IsPointerOrReferenceType(void *type, CompilerType *pointee_type) +{ + return IsPointerType(type, pointee_type); +} + +bool +GoASTContext::IsReferenceType(void *type, CompilerType *pointee_type, bool *is_rvalue) +{ + return false; +} + +bool +GoASTContext::IsScalarType(void *type) +{ + return !IsAggregateType(type); +} + +bool +GoASTContext::IsTypedefType(void *type) +{ + if (type) + return static_cast(type)->IsTypedef(); + return false; +} + +bool +GoASTContext::IsVoidType(void *type) +{ + if (!type) + return false; + return static_cast(type)->GetGoKind() == GoType::KIND_LLDB_VOID; +} + +//---------------------------------------------------------------------- +// Type Completion +//---------------------------------------------------------------------- + +bool +GoASTContext::GetCompleteType(void *type) +{ + if (!type) + return false; + GoType *t = static_cast(type); + if (t->IsTypedef() || t->GetGoKind() == GoType::KIND_PTR || t->GetArray()) + return t->GetElementType().GetCompleteType(); + if (GoStruct *s = t->GetStruct()) + { + if (s->IsComplete()) + return true; + CompilerType compiler_type(this, s); + SymbolFile *symbols = GetSymbolFile(); + return symbols && symbols->CompleteType(compiler_type); + } + return true; +} + +//---------------------------------------------------------------------- +// AST related queries +//---------------------------------------------------------------------- + +uint32_t +GoASTContext::GetPointerByteSize() +{ + return m_pointer_byte_size; +} + +//---------------------------------------------------------------------- +// Accessors +//---------------------------------------------------------------------- + +ConstString +GoASTContext::GetTypeName(void *type) +{ + if (type) + return static_cast(type)->GetName(); + return ConstString(); +} + +uint32_t +GoASTContext::GetTypeInfo(void *type, CompilerType *pointee_or_element_clang_type) +{ + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->Clear(); + if (!type) + return 0; + GoType *t = static_cast(type); + if (pointee_or_element_clang_type) + *pointee_or_element_clang_type = t->GetElementType(); + int kind = t->GetGoKind(); + if (kind == GoType::KIND_ARRAY) + return eTypeHasChildren | eTypeIsArray; + if (kind < GoType::KIND_ARRAY) + { + uint32_t builtin_type_flags = eTypeIsBuiltIn | eTypeHasValue; + if (kind < GoType::KIND_FLOAT32) + { + builtin_type_flags |= eTypeIsInteger | eTypeIsScalar; + if (kind >= GoType::KIND_INT && kind <= GoType::KIND_INT64) + builtin_type_flags |= eTypeIsSigned; + } + else + { + builtin_type_flags |= eTypeIsFloat; + if (kind < GoType::KIND_COMPLEX64) + builtin_type_flags |= eTypeIsComplex; + else + builtin_type_flags |= eTypeIsScalar; + } + return builtin_type_flags; + } + if (kind == GoType::KIND_STRING) + return eTypeHasValue | eTypeIsBuiltIn; + if (kind == GoType::KIND_FUNC) + return eTypeIsFuncPrototype | eTypeHasValue; + if (IsPointerType(type)) + return eTypeIsPointer | eTypeHasValue | eTypeHasChildren; + if (kind == GoType::KIND_LLDB_VOID) + return 0; + return eTypeHasChildren | eTypeIsStructUnion; +} + +lldb::TypeClass +GoASTContext::GetTypeClass(void *type) +{ + if (!type) + return eTypeClassInvalid; + int kind = static_cast(type)->GetGoKind(); + if (kind == GoType::KIND_FUNC) + return eTypeClassFunction; + if (IsPointerType(type)) + return eTypeClassPointer; + if (kind < GoType::KIND_COMPLEX64) + return eTypeClassBuiltin; + if (kind <= GoType::KIND_COMPLEX128) + return eTypeClassComplexFloat; + if (kind == GoType::KIND_LLDB_VOID) + return eTypeClassInvalid; + return eTypeClassStruct; +} + +lldb::BasicType +GoASTContext::GetBasicTypeEnumeration(void *type) +{ + ConstString name = GetTypeName(type); + if (name) + { + typedef UniqueCStringMap TypeNameToBasicTypeMap; + static TypeNameToBasicTypeMap g_type_map; + static std::once_flag g_once_flag; + std::call_once(g_once_flag, [](){ + // "void" + g_type_map.Append(ConstString("void").GetCString(), eBasicTypeVoid); + // "int" + g_type_map.Append(ConstString("int").GetCString(), eBasicTypeInt); + g_type_map.Append(ConstString("uint").GetCString(), eBasicTypeUnsignedInt); + + // Miscellaneous + g_type_map.Append(ConstString("bool").GetCString(), eBasicTypeBool); + + // Others. Should these map to C types? + g_type_map.Append(ConstString("byte").GetCString(), eBasicTypeOther); + g_type_map.Append(ConstString("uint8").GetCString(), eBasicTypeOther); + g_type_map.Append(ConstString("uint16").GetCString(), eBasicTypeOther); + g_type_map.Append(ConstString("uint32").GetCString(), eBasicTypeOther); + g_type_map.Append(ConstString("uint64").GetCString(), eBasicTypeOther); + g_type_map.Append(ConstString("int8").GetCString(), eBasicTypeOther); + g_type_map.Append(ConstString("int16").GetCString(), eBasicTypeOther); + g_type_map.Append(ConstString("int32").GetCString(), eBasicTypeOther); + g_type_map.Append(ConstString("int64").GetCString(), eBasicTypeOther); + g_type_map.Append(ConstString("float32").GetCString(), eBasicTypeOther); + g_type_map.Append(ConstString("float64").GetCString(), eBasicTypeOther); + g_type_map.Append(ConstString("uintptr").GetCString(), eBasicTypeOther); + + g_type_map.Sort(); + }); + + return g_type_map.Find(name.GetCString(), eBasicTypeInvalid); + } + return eBasicTypeInvalid; +} + +lldb::LanguageType +GoASTContext::GetMinimumLanguage(void *type) +{ + return lldb::eLanguageTypeGo; +} + +unsigned +GoASTContext::GetTypeQualifiers(void *type) +{ + return 0; +} + +//---------------------------------------------------------------------- +// Creating related types +//---------------------------------------------------------------------- + +CompilerType +GoASTContext::GetArrayElementType(void *type, uint64_t *stride) +{ + GoArray *array = static_cast(type)->GetArray(); + if (array) + { + if (stride) + { + *stride = array->GetElementType().GetByteSize(nullptr); + } + return array->GetElementType(); + } + return CompilerType(); +} + +CompilerType +GoASTContext::GetCanonicalType(void *type) +{ + GoType *t = static_cast(type); + if (t->IsTypedef()) + return t->GetElementType(); + return CompilerType(this, type); +} + +CompilerType +GoASTContext::GetFullyUnqualifiedType(void *type) +{ + return CompilerType(this, type); +} + +// Returns -1 if this isn't a function of if the function doesn't have a prototype +// Returns a value >= 0 if there is a prototype. +int +GoASTContext::GetFunctionArgumentCount(void *type) +{ + return GetNumberOfFunctionArguments(type); +} + +CompilerType +GoASTContext::GetFunctionArgumentTypeAtIndex(void *type, size_t idx) +{ + return GetFunctionArgumentAtIndex(type, idx); +} + +CompilerType +GoASTContext::GetFunctionReturnType(void *type) +{ + CompilerType result; + if (type) + { + GoType *t = static_cast(type); + if (t->GetGoKind() == GoType::KIND_FUNC) + result = t->GetElementType(); + } + return result; +} + +size_t +GoASTContext::GetNumMemberFunctions(void *type) +{ + return 0; +} + +TypeMemberFunctionImpl +GoASTContext::GetMemberFunctionAtIndex(void *type, size_t idx) +{ + return TypeMemberFunctionImpl(); +} + +CompilerType +GoASTContext::GetNonReferenceType(void *type) +{ + return CompilerType(this, type); +} + +CompilerType +GoASTContext::GetPointeeType(void *type) +{ + if (!type) + return CompilerType(); + return static_cast(type)->GetElementType(); +} + +CompilerType +GoASTContext::GetPointerType(void *type) +{ + if (!type) + return CompilerType(); + ConstString type_name = GetTypeName(type); + ConstString pointer_name(std::string("*") + type_name.GetCString()); + GoType *pointer = (*m_types)[pointer_name].get(); + if (pointer == nullptr) + { + pointer = new GoElem(GoType::KIND_PTR, pointer_name, CompilerType(this, type)); + (*m_types)[pointer_name].reset(pointer); + } + return CompilerType(this, pointer); +} + +// If the current object represents a typedef type, get the underlying type +CompilerType +GoASTContext::GetTypedefedType(void *type) +{ + if (IsTypedefType(type)) + return static_cast(type)->GetElementType(); + return CompilerType(); +} + +//---------------------------------------------------------------------- +// Create related types using the current type's AST +//---------------------------------------------------------------------- +CompilerType +GoASTContext::GetBasicTypeFromAST(lldb::BasicType basic_type) +{ + return CompilerType(); +} + +CompilerType GoASTContext::GetIntTypeFromBitSize (size_t bit_size, bool is_signed) +{ + return CompilerType(); +} +CompilerType GoASTContext::GetFloatTypeFromBitSize (size_t bit_size) +{ + return CompilerType(); +} + + +//---------------------------------------------------------------------- +// Exploring the type +//---------------------------------------------------------------------- + +uint64_t +GoASTContext::GetBitSize(void *type, ExecutionContextScope *exe_scope) +{ + if (!type) + return 0; + if (!GetCompleteType(type)) + return 0; + GoType *t = static_cast(type); + GoArray *array = nullptr; + switch (t->GetGoKind()) + { + case GoType::KIND_BOOL: + case GoType::KIND_INT8: + case GoType::KIND_UINT8: + return 8; + case GoType::KIND_INT16: + case GoType::KIND_UINT16: + return 16; + case GoType::KIND_INT32: + case GoType::KIND_UINT32: + case GoType::KIND_FLOAT32: + return 32; + case GoType::KIND_INT64: + case GoType::KIND_UINT64: + case GoType::KIND_FLOAT64: + case GoType::KIND_COMPLEX64: + return 64; + case GoType::KIND_COMPLEX128: + return 128; + case GoType::KIND_INT: + case GoType::KIND_UINT: + return m_int_byte_size * 8; + case GoType::KIND_UINTPTR: + case GoType::KIND_FUNC: // I assume this is a pointer? + case GoType::KIND_CHAN: + case GoType::KIND_PTR: + case GoType::KIND_UNSAFEPOINTER: + case GoType::KIND_MAP: + return m_pointer_byte_size * 8; + case GoType::KIND_ARRAY: + array = t->GetArray(); + return array->GetLength() * array->GetElementType().GetBitSize(exe_scope); + case GoType::KIND_INTERFACE: + return t->GetElementType().GetBitSize(exe_scope); + case GoType::KIND_SLICE: + case GoType::KIND_STRING: + case GoType::KIND_STRUCT: + return t->GetStruct()->GetByteSize() * 8; + default: + assert(false); + } +} + +lldb::Encoding +GoASTContext::GetEncoding(void *type, uint64_t &count) +{ + count = 1; + bool is_signed; + if (IsIntegerType(type, is_signed)) + return is_signed ? lldb::eEncodingSint : eEncodingUint; + bool is_complex; + uint32_t complex_count; + if (IsFloatingPointType(type, complex_count, is_complex)) + { + count = complex_count; + return eEncodingIEEE754; + } + if (IsPointerType(type)) + return eEncodingUint; + return eEncodingInvalid; +} + +lldb::Format +GoASTContext::GetFormat(void *type) +{ + if (!type) + return eFormatDefault; + switch (static_cast(type)->GetGoKind()) + { + case GoType::KIND_BOOL: + return eFormatBoolean; + case GoType::KIND_INT: + case GoType::KIND_INT8: + case GoType::KIND_INT16: + case GoType::KIND_INT32: + case GoType::KIND_INT64: + return eFormatDecimal; + case GoType::KIND_UINT: + case GoType::KIND_UINT8: + case GoType::KIND_UINT16: + case GoType::KIND_UINT32: + case GoType::KIND_UINT64: + return eFormatUnsigned; + case GoType::KIND_FLOAT32: + case GoType::KIND_FLOAT64: + return eFormatFloat; + case GoType::KIND_COMPLEX64: + case GoType::KIND_COMPLEX128: + return eFormatComplexFloat; + case GoType::KIND_UINTPTR: + case GoType::KIND_CHAN: + case GoType::KIND_PTR: + case GoType::KIND_MAP: + case GoType::KIND_UNSAFEPOINTER: + return eFormatHex; + case GoType::KIND_STRING: + return eFormatCString; + case GoType::KIND_ARRAY: + case GoType::KIND_INTERFACE: + case GoType::KIND_SLICE: + case GoType::KIND_STRUCT: + default: + // Don't know how to display this. + return eFormatBytes; + } +} + +size_t +GoASTContext::GetTypeBitAlign(void *type) +{ + return 0; +} + +uint32_t +GoASTContext::GetNumChildren(void *type, bool omit_empty_base_classes) +{ + if (!type || !GetCompleteType(type)) + return 0; + GoType *t = static_cast(type); + if (t->GetGoKind() == GoType::KIND_PTR) + { + CompilerType elem = t->GetElementType(); + if (elem.IsAggregateType()) + return elem.GetNumChildren(omit_empty_base_classes); + return 1; + } + else if (GoArray *array = t->GetArray()) + { + return array->GetLength(); + } + return GetNumFields(type); +} + +uint32_t +GoASTContext::GetNumFields(void *type) +{ + if (!type || !GetCompleteType(type)) + return 0; + GoType *t = static_cast(type); + if (t->IsTypedef()) + return t->GetElementType().GetNumFields(); + GoStruct *s = t->GetStruct(); + if (s) + return s->GetNumFields(); + return 0; +} + +CompilerType +GoASTContext::GetFieldAtIndex(void *type, size_t idx, std::string &name, uint64_t *bit_offset_ptr, + uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) +{ + if (bit_offset_ptr) + *bit_offset_ptr = 0; + if (bitfield_bit_size_ptr) + *bitfield_bit_size_ptr = 0; + if (is_bitfield_ptr) + *is_bitfield_ptr = false; + + if (!type || !GetCompleteType(type)) + return CompilerType(); + + GoType *t = static_cast(type); + if (t->IsTypedef()) + return t->GetElementType().GetFieldAtIndex(idx, name, bit_offset_ptr, bitfield_bit_size_ptr, is_bitfield_ptr); + + GoStruct *s = t->GetStruct(); + if (s) + { + const auto *field = s->GetField(idx); + if (field) + { + name = field->m_name.GetStringRef(); + if (bit_offset_ptr) + *bit_offset_ptr = field->m_byte_offset * 8; + return field->m_type; + } + } + return CompilerType(); +} + +CompilerType +GoASTContext::GetChildClangTypeAtIndex(void *type, ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, + bool omit_empty_base_classes, bool ignore_array_bounds, std::string &child_name, + uint32_t &child_byte_size, int32_t &child_byte_offset, + uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset, + bool &child_is_base_class, bool &child_is_deref_of_parent, ValueObject *valobj) +{ + child_name.clear(); + child_byte_size = 0; + child_byte_offset = 0; + child_bitfield_bit_size = 0; + child_bitfield_bit_offset = 0; + child_is_base_class = false; + child_is_deref_of_parent = false; + + if (!type || !GetCompleteType(type)) + return CompilerType(); + + GoType *t = static_cast(type); + if (t->GetStruct()) + { + uint64_t bit_offset; + CompilerType ret = GetFieldAtIndex(type, idx, child_name, &bit_offset, nullptr, nullptr); + child_byte_size = ret.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr); + child_byte_offset = bit_offset / 8; + return ret; + } + else if (t->GetGoKind() == GoType::KIND_PTR) + { + CompilerType pointee = t->GetElementType(); + if (!pointee.IsValid() || pointee.IsVoidType()) + return CompilerType(); + if (transparent_pointers && pointee.IsAggregateType()) + { + bool tmp_child_is_deref_of_parent = false; + return pointee.GetChildClangTypeAtIndex(exe_ctx, idx, transparent_pointers, omit_empty_base_classes, + ignore_array_bounds, child_name, child_byte_size, child_byte_offset, + child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, tmp_child_is_deref_of_parent, valobj); + } + else + { + child_is_deref_of_parent = true; + const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL; + if (parent_name) + { + child_name.assign(1, '*'); + child_name += parent_name; + } + + // We have a pointer to an simple type + if (idx == 0 && pointee.GetCompleteType()) + { + child_byte_size = pointee.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL); + child_byte_offset = 0; + return pointee; + } + } + } + else if (GoArray *a = t->GetArray()) + { + if (ignore_array_bounds || idx < a->GetLength()) + { + CompilerType element_type = a->GetElementType(); + if (element_type.GetCompleteType()) + { + char element_name[64]; + ::snprintf(element_name, sizeof(element_name), "[%zu]", idx); + child_name.assign(element_name); + child_byte_size = element_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL); + child_byte_offset = (int32_t)idx * (int32_t)child_byte_size; + return element_type; + } + } + } + else if (t->IsTypedef()) + { + return t->GetElementType().GetChildClangTypeAtIndex( + exe_ctx, idx, transparent_pointers, omit_empty_base_classes, ignore_array_bounds, child_name, + child_byte_size, child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, + child_is_deref_of_parent, valobj); + } + return CompilerType(); +} + +// Lookup a child given a name. This function will match base class names +// and member member names in "clang_type" only, not descendants. +uint32_t +GoASTContext::GetIndexOfChildWithName(void *type, const char *name, bool omit_empty_base_classes) +{ + GoType *t = static_cast(type); + GoStruct *s = t->GetStruct(); + if (s) + { + for (uint32_t i = 0; i < s->GetNumFields(); ++i) + { + const GoStruct::Field *f = s->GetField(i); + if (f->m_name.GetStringRef() == name) + return i; + } + } + else if (t->GetGoKind() == GoType::KIND_PTR || t->IsTypedef()) + { + return t->GetElementType().GetIndexOfChildWithName(name, omit_empty_base_classes); + } + return UINT_MAX; +} + +// Lookup a child member given a name. This function will match member names +// only and will descend into "clang_type" children in search for the first +// member in this class, or any base class that matches "name". +// TODO: Return all matches for a given name by returning a vector> +// so we catch all names that match a given child name, not just the first. +size_t +GoASTContext::GetIndexOfChildMemberWithName(void *type, const char *name, bool omit_empty_base_classes, + std::vector &child_indexes) +{ + uint32_t index = GetIndexOfChildWithName(type, name, omit_empty_base_classes); + if (index == UINT_MAX) + return 0; + child_indexes.push_back(index); + return 1; +} + +// Converts "s" to a floating point value and place resulting floating +// point bytes in the "dst" buffer. +size_t +GoASTContext::ConvertStringToFloatValue(void *type, const char *s, uint8_t *dst, size_t dst_size) +{ + assert(false); +} +//---------------------------------------------------------------------- +// Dumping types +//---------------------------------------------------------------------- +void +GoASTContext::DumpValue(void *type, ExecutionContext *exe_ctx, Stream *s, lldb::Format format, + const DataExtractor &data, lldb::offset_t data_offset, size_t data_byte_size, + uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, bool show_types, bool show_summary, + bool verbose, uint32_t depth) +{ + assert(false); +} + +bool +GoASTContext::DumpTypeValue(void *type, Stream *s, lldb::Format format, const DataExtractor &data, + lldb::offset_t byte_offset, size_t byte_size, uint32_t bitfield_bit_size, + uint32_t bitfield_bit_offset, ExecutionContextScope *exe_scope) +{ + if (!type) + return false; + if (IsAggregateType(type)) + { + return false; + } + else + { + GoType *t = static_cast(type); + if (t->IsTypedef()) + { + CompilerType typedef_clang_type = t->GetElementType(); + if (format == eFormatDefault) + format = typedef_clang_type.GetFormat(); + uint64_t typedef_byte_size = typedef_clang_type.GetByteSize(exe_scope); + + return typedef_clang_type.DumpTypeValue( + s, + format, // The format with which to display the element + data, // Data buffer containing all bytes for this type + byte_offset, // Offset into "data" where to grab value from + typedef_byte_size, // Size of this type in bytes + bitfield_bit_size, // Size in bits of a bitfield value, if zero don't treat as a bitfield + bitfield_bit_offset, // Offset in bits of a bitfield value if bitfield_bit_size != 0 + exe_scope); + } + + uint32_t item_count = 1; + // A few formats, we might need to modify our size and count for depending + // on how we are trying to display the value... + switch (format) + { + default: + case eFormatBoolean: + case eFormatBinary: + case eFormatComplex: + case eFormatCString: // NULL terminated C strings + case eFormatDecimal: + case eFormatEnum: + case eFormatHex: + case eFormatHexUppercase: + case eFormatFloat: + case eFormatOctal: + case eFormatOSType: + case eFormatUnsigned: + case eFormatPointer: + case eFormatVectorOfChar: + case eFormatVectorOfSInt8: + case eFormatVectorOfUInt8: + case eFormatVectorOfSInt16: + case eFormatVectorOfUInt16: + case eFormatVectorOfSInt32: + case eFormatVectorOfUInt32: + case eFormatVectorOfSInt64: + case eFormatVectorOfUInt64: + case eFormatVectorOfFloat32: + case eFormatVectorOfFloat64: + case eFormatVectorOfUInt128: + break; + + case eFormatChar: + case eFormatCharPrintable: + case eFormatCharArray: + case eFormatBytes: + case eFormatBytesWithASCII: + item_count = byte_size; + byte_size = 1; + break; + + case eFormatUnicode16: + item_count = byte_size / 2; + byte_size = 2; + break; + + case eFormatUnicode32: + item_count = byte_size / 4; + byte_size = 4; + break; + } + return data.Dump(s, byte_offset, format, byte_size, item_count, UINT32_MAX, LLDB_INVALID_ADDRESS, + bitfield_bit_size, bitfield_bit_offset, exe_scope); + } + return 0; +} + +void +GoASTContext::DumpSummary(void *type, ExecutionContext *exe_ctx, Stream *s, const DataExtractor &data, + lldb::offset_t data_offset, size_t data_byte_size) +{ + assert(false); +} + +void +GoASTContext::DumpTypeDescription(void *type) +{ + assert(false); +} // Dump to stdout + +void +GoASTContext::DumpTypeDescription(void *type, Stream *s) +{ + assert(false); +} + +CompilerType +GoASTContext::CreateArrayType(const ConstString &name, const CompilerType &element_type, int64_t length) +{ + GoType *type = new GoArray(name, length, element_type); + (*m_types)[name].reset(type); + return CompilerType(this, type); +} + +CompilerType +GoASTContext::CreateBaseType(int go_kind, const lldb_private::ConstString &name, uint64_t byte_size) +{ + if (go_kind == GoType::KIND_UINT || go_kind == GoType::KIND_INT) + m_int_byte_size = byte_size; + GoType *type = new GoType(go_kind, name); + (*m_types)[name].reset(type); + return CompilerType(this, type); +} + +CompilerType +GoASTContext::CreateTypedef(int kind, const ConstString &name, CompilerType impl) +{ + GoType *type = new GoElem(kind, name, impl); + (*m_types)[name].reset(type); + return CompilerType(this, type); +} + +CompilerType +GoASTContext::CreateVoidType(const lldb_private::ConstString &name) +{ + GoType *type = new GoType(GoType::KIND_LLDB_VOID, name); + (*m_types)[name].reset(type); + return CompilerType(this, type); +} + +CompilerType +GoASTContext::CreateStructType(int kind, const lldb_private::ConstString &name, uint32_t byte_size) +{ + GoType *type = new GoStruct(kind, name, byte_size); + (*m_types)[name].reset(type); + return CompilerType(this, type); +} + +void +GoASTContext::AddFieldToStruct(const lldb_private::CompilerType &struct_type, const lldb_private::ConstString &name, + const lldb_private::CompilerType &field_type, uint32_t byte_offset) +{ + if (!struct_type) + return; + GoASTContext *ast = llvm::dyn_cast_or_null(struct_type.GetTypeSystem()); + if (!ast) + return; + GoType *type = static_cast(struct_type.GetOpaqueQualType()); + if (GoStruct *s = type->GetStruct()) + s->AddField(name, field_type, byte_offset); +} + +void +GoASTContext::CompleteStructType(const lldb_private::CompilerType &struct_type) +{ + if (!struct_type) + return; + GoASTContext *ast = llvm::dyn_cast_or_null(struct_type.GetTypeSystem()); + if (!ast) + return; + GoType *type = static_cast(struct_type.GetOpaqueQualType()); + if (GoStruct *s = type->GetStruct()) + s->SetComplete(); +} + +CompilerType +GoASTContext::CreateFunctionType(const lldb_private::ConstString &name, CompilerType *params, size_t params_count, + bool is_variadic) +{ + GoType *type = new GoFunction(name, is_variadic); + (*m_types)[name].reset(type); + return CompilerType(this, type); +} + +bool +GoASTContext::IsGoString(const lldb_private::CompilerType &type) +{ + if (!type.IsValid() || !llvm::dyn_cast_or_null(type.GetTypeSystem())) + return false; + return GoType::KIND_STRING == static_cast(type.GetOpaqueQualType())->GetGoKind(); +} + +bool +GoASTContext::IsGoSlice(const lldb_private::CompilerType &type) +{ + if (!type.IsValid() || !llvm::dyn_cast_or_null(type.GetTypeSystem())) + return false; + return GoType::KIND_SLICE == static_cast(type.GetOpaqueQualType())->GetGoKind(); +} + +bool +GoASTContext::IsGoInterface(const lldb_private::CompilerType &type) +{ + if (!type.IsValid() || !llvm::dyn_cast_or_null(type.GetTypeSystem())) + return false; + return GoType::KIND_INTERFACE == static_cast(type.GetOpaqueQualType())->GetGoKind(); +} + +bool +GoASTContext::IsPointerKind(uint8_t kind) +{ + return (kind & GoType::KIND_MASK) == GoType::KIND_PTR; +} + +bool +GoASTContext::IsDirectIface(uint8_t kind) +{ + return (kind & GoType::KIND_DIRECT_IFACE) == GoType::KIND_DIRECT_IFACE; +} + +DWARFASTParser * +GoASTContext::GetDWARFParser() +{ + if (!m_dwarf_ast_parser_ap) + m_dwarf_ast_parser_ap.reset(new DWARFASTParserGo(*this)); + return m_dwarf_ast_parser_ap.get(); +} Index: lldb/trunk/source/Symbol/SymbolFile.cpp =================================================================== --- lldb/trunk/source/Symbol/SymbolFile.cpp +++ lldb/trunk/source/Symbol/SymbolFile.cpp @@ -93,7 +93,10 @@ TypeSystem * SymbolFile::GetTypeSystemForLanguage (lldb::LanguageType language) { - return m_obj_file->GetModule()->GetTypeSystemForLanguage (language); + TypeSystem *type_system = m_obj_file->GetModule()->GetTypeSystemForLanguage(language); + if (type_system) + type_system->SetSymbolFile(this); + return type_system; } uint32_t Index: lldb/trunk/test/lang/go/types/TestGoASTContext.py =================================================================== --- lldb/trunk/test/lang/go/types/TestGoASTContext.py +++ lldb/trunk/test/lang/go/types/TestGoASTContext.py @@ -0,0 +1,134 @@ +"""Test the go DWARF type parsing.""" + +import os, time +import unittest2 +import lldb +import lldbutil +from lldbtest import * + +class TestGoASTContext(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @python_api_test + @skipUnlessGoInstalled + def test_with_dsym_and_python_api(self): + """Test GoASTContext dwarf parsing.""" + self.buildGo() + self.launchProcess() + self.go_builtin_types() + self.check_main_vars() + + 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, '// Set breakpoint here.') + + def check_builtin(self, name, size=0, typeclass=lldb.eTypeClassBuiltin): + tl = self.target().FindTypes(name) + self.assertEqual(1, len(tl)) + t = list(tl)[0] + self.assertEqual(name, t.name) + self.assertEqual(typeclass, t.type) + if size > 0: + self.assertEqual(size, t.size) + + def launchProcess(self): + exe = os.path.join(os.getcwd(), "a.out") + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + bpt = target.BreakpointCreateByLocation(self.main_source, self.break_line) + self.assertTrue(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, 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 go_builtin_types(self): + address_size = self.target().GetAddressByteSize() + self.check_builtin('bool') + self.check_builtin('uint8', 1) + self.check_builtin('int8', 1) + self.check_builtin('uint16', 2) + self.check_builtin('int16', 2) + self.check_builtin('uint32', 4) + self.check_builtin('int32', 4) + self.check_builtin('uint64', 8) + self.check_builtin('int64', 8) + self.check_builtin('uintptr', address_size) + self.check_builtin('int', address_size) + self.check_builtin('uint', address_size) + self.check_builtin('float32', 4) + self.check_builtin('float64', 8) + self.check_builtin('complex64', 8, lldb.eTypeClassComplexFloat) + self.check_builtin('complex128', 16, lldb.eTypeClassComplexFloat) + + def var(self, name): + var = self.frame().FindVariable(name) + self.assertTrue(var.IsValid(), "%s %s" % (VALID_VARIABLE, name)) + return var + + def check_main_vars(self): + v = self.var('theBool') + self.assertEqual('true', v.value) + + v = self.var('theInt') + self.assertEqual('-7', v.value) + + v = self.var('theComplex') + self.assertEqual('1 + 2i', v.value) + + v = self.var('thePointer') + self.assertTrue(v.TypeIsPointerType()) + self.assertEqual('-10', v.Dereference().value) + self.assertEqual(1, v.GetNumChildren()) + self.assertEqual('-10', v.GetChildAtIndex(0).value) + + # print + # print os.getpid() + # time.sleep(60) + v = self.var('theStruct') + if v.TypeIsPointerType(): + v = v.Dereference() + self.assertEqual(2, v.GetNumChildren()) + self.assertEqual('7', v.GetChildAtIndex(0).value) + self.assertEqual('7', v.GetChildMemberWithName('myInt').value) + self.assertEqual(v.load_addr, v.GetChildAtIndex(1).GetValueAsUnsigned()) + self.assertEqual(v.load_addr, v.GetChildMemberWithName('myPointer').GetValueAsUnsigned()) + + # Test accessing struct fields through pointers. + v = v.GetChildMemberWithName('myPointer') + self.assertTrue(v.TypeIsPointerType()) + self.assertEqual(2, v.GetNumChildren()) + self.assertEqual('7', v.GetChildAtIndex(0).value) + c = v.GetChildMemberWithName('myPointer') + self.assertTrue(c.TypeIsPointerType()) + self.assertEqual(2, c.GetNumChildren()) + self.assertEqual('7', c.GetChildAtIndex(0).value) + + v = self.var('theArray') + self.assertEqual(5, v.GetNumChildren()) + for i in xrange(5): + self.assertEqual(str(i + 1), v.GetChildAtIndex(i).value) + + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Index: lldb/trunk/test/lang/go/types/main.go =================================================================== --- lldb/trunk/test/lang/go/types/main.go +++ lldb/trunk/test/lang/go/types/main.go @@ -0,0 +1,47 @@ +package main + +import "fmt" + +type Fooer interface { + Foo() int +} + +type SomeFooer struct { + val int +} + +func (s SomeFooer) Foo() int { + return s.val +} + +type mystruct struct { + myInt int + myPointer *mystruct +} + +func main() { + theBool := true + theInt := -7 + theComplex := 1 + 2i + pointee := -10 + thePointer := &pointee + theStruct := &mystruct { myInt: 7} + theStruct.myPointer = theStruct + theArray := [5]byte{1, 2, 3, 4, 5} + theSlice := theArray[1:2] + theString := "abc" + + f := SomeFooer {9} + var theEface interface{} = f + var theFooer Fooer = f + + theChan := make(chan int) + theMap := make(map[int]string) + theMap[1] = "1" + + fmt.Println(theBool) // Set breakpoint here. + // Reference all the variables so the compiler is happy. + fmt.Println(theInt, theComplex, thePointer, theStruct.myInt) + fmt.Println(theArray[0], theSlice[0], theString) + fmt.Println(theEface, theFooer, theChan, theMap) +} \ No newline at end of file Index: lldb/trunk/test/lldbtest.py =================================================================== --- lldb/trunk/test/lldbtest.py +++ lldb/trunk/test/lldbtest.py @@ -893,6 +893,21 @@ """Decorate the item to skip tests that should be skipped on any non Darwin platform.""" return skipUnlessPlatform(getDarwinOSTriples())(func) +def skipUnlessGoInstalled(func): + """Decorate the item to skip tests when no Go compiler is available.""" + if isinstance(func, type) and issubclass(func, unittest2.TestCase): + raise Exception("@skipIfGcc can only be used to decorate a test method") + @wraps(func) + def wrapper(*args, **kwargs): + from unittest2 import case + self = args[0] + compiler = self.getGoCompilerVersion() + if not compiler: + self.skipTest("skipping because go compiler not found") + else: + func(*args, **kwargs) + return wrapper + def getPlatform(): """Returns the target platform which the tests are running on.""" platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2] @@ -1868,6 +1883,18 @@ version = m.group(1) return version + def getGoCompilerVersion(self): + """ Returns a string that represents the go compiler version, or None if go is not found. + """ + compiler = which("go") + if compiler: + version_output = system([[compiler, "version"]])[0] + for line in version_output.split(os.linesep): + m = re.search('go version (devel|go\\S+)', line) + if m: + return m.group(1) + return None + def platformIsDarwin(self): """Returns true if the OS triple for the selected platform is any valid apple OS""" return platformIsDarwin() @@ -2053,6 +2080,11 @@ if not module.buildDwarf(self, architecture, compiler, dictionary, clean): raise Exception("Don't know how to build binary with dwarf") + def buildGo(self): + """Build the default go binary. + """ + system([[which('go'), 'build -gcflags "-N -l" -o a.out main.go']]) + def signBinary(self, binary_path): if sys.platform.startswith("darwin"): codesign_cmd = "codesign --force --sign lldb_codesign %s" % (binary_path)