|  | //===-- 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 <mutex> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "lldb/Core/Module.h" | 
|  | #include "lldb/Core/PluginManager.h" | 
|  | #include "lldb/Core/StreamFile.h" | 
|  | #include "lldb/Core/UniqueCStringMap.h" | 
|  | #include "lldb/Core/ValueObject.h" | 
|  | #include "lldb/DataFormatters/StringPrinter.h" | 
|  | #include "lldb/Symbol/CompilerType.h" | 
|  | #include "lldb/Symbol/GoASTContext.h" | 
|  | #include "lldb/Symbol/ObjectFile.h" | 
|  | #include "lldb/Symbol/SymbolFile.h" | 
|  | #include "lldb/Symbol/Type.h" | 
|  | #include "lldb/Target/ExecutionContext.h" | 
|  | #include "lldb/Target/Target.h" | 
|  |  | 
|  | #include "Plugins/ExpressionParser/Go/GoUserExpression.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, uint64_t length, const CompilerType &elem) | 
|  | : GoElem(KIND_ARRAY, name, elem), m_length(length) {} | 
|  |  | 
|  | uint64_t GetLength() const { return m_length; } | 
|  |  | 
|  | private: | 
|  | uint64_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 == 0 ? KIND_STRUCT : 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<Field> m_fields; | 
|  |  | 
|  | GoStruct(const GoStruct &) = delete; | 
|  | const GoStruct &operator=(const GoStruct &) = delete; | 
|  | }; | 
|  |  | 
|  | GoArray *GoType::GetArray() { | 
|  | if (m_kind == KIND_ARRAY) { | 
|  | return static_cast<GoArray *>(this); | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | GoFunction *GoType::GetFunction() { | 
|  | if (m_kind == KIND_FUNC) { | 
|  | return static_cast<GoFunction *>(this); | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | GoStruct *GoType::GetStruct() { | 
|  | switch (m_kind) { | 
|  | case KIND_STRING: | 
|  | case KIND_STRUCT: | 
|  | case KIND_SLICE: | 
|  | return static_cast<GoStruct *>(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() {} | 
|  |  | 
|  | //------------------------------------------------------------------ | 
|  | // PluginInterface functions | 
|  | //------------------------------------------------------------------ | 
|  |  | 
|  | ConstString GoASTContext::GetPluginNameStatic() { return ConstString("go"); } | 
|  |  | 
|  | ConstString GoASTContext::GetPluginName() { | 
|  | return GoASTContext::GetPluginNameStatic(); | 
|  | } | 
|  |  | 
|  | uint32_t GoASTContext::GetPluginVersion() { return 1; } | 
|  |  | 
|  | lldb::TypeSystemSP GoASTContext::CreateInstance(lldb::LanguageType language, | 
|  | Module *module, | 
|  | Target *target) { | 
|  | if (language == eLanguageTypeGo) { | 
|  | ArchSpec arch; | 
|  | std::shared_ptr<GoASTContext> go_ast_sp; | 
|  | if (module) { | 
|  | arch = module->GetArchitecture(); | 
|  | go_ast_sp = std::shared_ptr<GoASTContext>(new GoASTContext); | 
|  | } else if (target) { | 
|  | arch = target->GetArchitecture(); | 
|  | go_ast_sp = std::shared_ptr<GoASTContextForExpr>( | 
|  | new GoASTContextForExpr(target->shared_from_this())); | 
|  | } | 
|  |  | 
|  | if (arch.IsValid()) { | 
|  | go_ast_sp->SetAddressByteSize(arch.GetAddressByteSize()); | 
|  | return go_ast_sp; | 
|  | } | 
|  | } | 
|  | return lldb::TypeSystemSP(); | 
|  | } | 
|  |  | 
|  | void GoASTContext::EnumerateSupportedLanguages( | 
|  | std::set<lldb::LanguageType> &languages_for_types, | 
|  | std::set<lldb::LanguageType> &languages_for_expressions) { | 
|  | static std::vector<lldb::LanguageType> s_supported_languages_for_types( | 
|  | {lldb::eLanguageTypeGo}); | 
|  |  | 
|  | static std::vector<lldb::LanguageType> s_supported_languages_for_expressions( | 
|  | {}); | 
|  |  | 
|  | languages_for_types.insert(s_supported_languages_for_types.begin(), | 
|  | s_supported_languages_for_types.end()); | 
|  | languages_for_expressions.insert( | 
|  | s_supported_languages_for_expressions.begin(), | 
|  | s_supported_languages_for_expressions.end()); | 
|  | } | 
|  |  | 
|  | void GoASTContext::Initialize() { | 
|  | PluginManager::RegisterPlugin(GetPluginNameStatic(), "AST context plug-in", | 
|  | CreateInstance, EnumerateSupportedLanguages); | 
|  | } | 
|  |  | 
|  | void GoASTContext::Terminate() { | 
|  | PluginManager::UnregisterPlugin(CreateInstance); | 
|  | } | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Tests | 
|  | //---------------------------------------------------------------------- | 
|  |  | 
|  | bool GoASTContext::IsArrayType(lldb::opaque_compiler_type_t 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<GoType *>(type)->GetArray(); | 
|  | if (array) { | 
|  | if (size) | 
|  | *size = array->GetLength(); | 
|  | if (element_type) | 
|  | *element_type = array->GetElementType(); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsVectorType(lldb::opaque_compiler_type_t type, | 
|  | CompilerType *element_type, uint64_t *size) { | 
|  | if (element_type) | 
|  | element_type->Clear(); | 
|  | if (size) | 
|  | *size = 0; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsAggregateType(lldb::opaque_compiler_type_t type) { | 
|  | int kind = static_cast<GoType *>(type)->GetGoKind(); | 
|  | if (kind < GoType::KIND_ARRAY) | 
|  | return false; | 
|  | if (kind == GoType::KIND_PTR) | 
|  | return false; | 
|  | if (kind == GoType::KIND_CHAN) | 
|  | return false; | 
|  | if (kind == GoType::KIND_MAP) | 
|  | return false; | 
|  | if (kind == GoType::KIND_STRING) | 
|  | return false; | 
|  | if (kind == GoType::KIND_UNSAFEPOINTER) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsBeingDefined(lldb::opaque_compiler_type_t type) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsCharType(lldb::opaque_compiler_type_t type) { | 
|  | // Go's DWARF doesn't distinguish between rune and int32. | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsCompleteType(lldb::opaque_compiler_type_t type) { | 
|  | if (!type) | 
|  | return false; | 
|  | GoType *t = static_cast<GoType *>(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(lldb::opaque_compiler_type_t type) { return false; } | 
|  |  | 
|  | bool GoASTContext::IsCStringType(lldb::opaque_compiler_type_t type, | 
|  | uint32_t &length) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsDefined(lldb::opaque_compiler_type_t type) { | 
|  | return type != nullptr; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsFloatingPointType(lldb::opaque_compiler_type_t type, | 
|  | uint32_t &count, bool &is_complex) { | 
|  | int kind = static_cast<GoType *>(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(lldb::opaque_compiler_type_t type, | 
|  | bool *is_variadic_ptr) { | 
|  | GoFunction *func = static_cast<GoType *>(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(lldb::opaque_compiler_type_t type, | 
|  | CompilerType *base_type_ptr) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | size_t | 
|  | GoASTContext::GetNumberOfFunctionArguments(lldb::opaque_compiler_type_t type) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | CompilerType | 
|  | GoASTContext::GetFunctionArgumentAtIndex(lldb::opaque_compiler_type_t type, | 
|  | const size_t index) { | 
|  | return CompilerType(); | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsFunctionPointerType(lldb::opaque_compiler_type_t type) { | 
|  | return IsFunctionType(type); | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsBlockPointerType(lldb::opaque_compiler_type_t type, | 
|  | CompilerType *function_pointer_type_ptr) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsIntegerType(lldb::opaque_compiler_type_t type, | 
|  | bool &is_signed) { | 
|  | is_signed = false; | 
|  | // TODO: Is bool an integer? | 
|  | if (type) { | 
|  | int kind = static_cast<GoType *>(type)->GetGoKind(); | 
|  | if (kind <= GoType::KIND_UINTPTR) { | 
|  | is_signed = (kind != GoType::KIND_BOOL) & (kind <= GoType::KIND_INT64); | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsPolymorphicClass(lldb::opaque_compiler_type_t type) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsPossibleDynamicType( | 
|  | lldb::opaque_compiler_type_t type, | 
|  | CompilerType *target_type, // Can pass NULL | 
|  | bool check_cplusplus, bool check_objc) { | 
|  | if (target_type) | 
|  | target_type->Clear(); | 
|  | if (type) | 
|  | return static_cast<GoType *>(type)->GetGoKind() == GoType::KIND_INTERFACE; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsRuntimeGeneratedType(lldb::opaque_compiler_type_t type) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsPointerType(lldb::opaque_compiler_type_t type, | 
|  | CompilerType *pointee_type) { | 
|  | if (!type) | 
|  | return false; | 
|  | GoType *t = static_cast<GoType *>(type); | 
|  | if (pointee_type) { | 
|  | *pointee_type = t->GetElementType(); | 
|  | } | 
|  | switch (t->GetGoKind()) { | 
|  | case GoType::KIND_PTR: | 
|  | case GoType::KIND_UNSAFEPOINTER: | 
|  | case GoType::KIND_CHAN: | 
|  | case GoType::KIND_MAP: | 
|  | // TODO: is function a pointer? | 
|  | return true; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsPointerOrReferenceType(lldb::opaque_compiler_type_t type, | 
|  | CompilerType *pointee_type) { | 
|  | return IsPointerType(type, pointee_type); | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsReferenceType(lldb::opaque_compiler_type_t type, | 
|  | CompilerType *pointee_type, | 
|  | bool *is_rvalue) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsScalarType(lldb::opaque_compiler_type_t type) { | 
|  | return !IsAggregateType(type); | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsTypedefType(lldb::opaque_compiler_type_t type) { | 
|  | if (type) | 
|  | return static_cast<GoType *>(type)->IsTypedef(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsVoidType(lldb::opaque_compiler_type_t type) { | 
|  | if (!type) | 
|  | return false; | 
|  | return static_cast<GoType *>(type)->GetGoKind() == GoType::KIND_LLDB_VOID; | 
|  | } | 
|  |  | 
|  | bool GoASTContext::SupportsLanguage(lldb::LanguageType language) { | 
|  | return language == eLanguageTypeGo; | 
|  | } | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Type Completion | 
|  | //---------------------------------------------------------------------- | 
|  |  | 
|  | bool GoASTContext::GetCompleteType(lldb::opaque_compiler_type_t type) { | 
|  | if (!type) | 
|  | return false; | 
|  | GoType *t = static_cast<GoType *>(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(lldb::opaque_compiler_type_t type) { | 
|  | if (type) | 
|  | return static_cast<GoType *>(type)->GetName(); | 
|  | return ConstString(); | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | GoASTContext::GetTypeInfo(lldb::opaque_compiler_type_t type, | 
|  | CompilerType *pointee_or_element_compiler_type) { | 
|  | if (pointee_or_element_compiler_type) | 
|  | pointee_or_element_compiler_type->Clear(); | 
|  | if (!type) | 
|  | return 0; | 
|  | GoType *t = static_cast<GoType *>(type); | 
|  | if (pointee_or_element_compiler_type) | 
|  | *pointee_or_element_compiler_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(lldb::opaque_compiler_type_t type) { | 
|  | if (!type) | 
|  | return eTypeClassInvalid; | 
|  | int kind = static_cast<GoType *>(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(lldb::opaque_compiler_type_t type) { | 
|  | ConstString name = GetTypeName(type); | 
|  | if (name) { | 
|  | typedef UniqueCStringMap<lldb::BasicType> 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").GetStringRef(), eBasicTypeVoid); | 
|  | // "int" | 
|  | g_type_map.Append(ConstString("int").GetStringRef(), eBasicTypeInt); | 
|  | g_type_map.Append(ConstString("uint").GetStringRef(), | 
|  | eBasicTypeUnsignedInt); | 
|  |  | 
|  | // Miscellaneous | 
|  | g_type_map.Append(ConstString("bool").GetStringRef(), eBasicTypeBool); | 
|  |  | 
|  | // Others. Should these map to C types? | 
|  | g_type_map.Append(ConstString("byte").GetStringRef(), eBasicTypeOther); | 
|  | g_type_map.Append(ConstString("uint8").GetStringRef(), eBasicTypeOther); | 
|  | g_type_map.Append(ConstString("uint16").GetStringRef(), eBasicTypeOther); | 
|  | g_type_map.Append(ConstString("uint32").GetStringRef(), eBasicTypeOther); | 
|  | g_type_map.Append(ConstString("uint64").GetStringRef(), eBasicTypeOther); | 
|  | g_type_map.Append(ConstString("int8").GetStringRef(), eBasicTypeOther); | 
|  | g_type_map.Append(ConstString("int16").GetStringRef(), eBasicTypeOther); | 
|  | g_type_map.Append(ConstString("int32").GetStringRef(), eBasicTypeOther); | 
|  | g_type_map.Append(ConstString("int64").GetStringRef(), eBasicTypeOther); | 
|  | g_type_map.Append(ConstString("float32").GetStringRef(), eBasicTypeOther); | 
|  | g_type_map.Append(ConstString("float64").GetStringRef(), eBasicTypeOther); | 
|  | g_type_map.Append(ConstString("uintptr").GetStringRef(), eBasicTypeOther); | 
|  |  | 
|  | g_type_map.Sort(); | 
|  | }); | 
|  |  | 
|  | return g_type_map.Find(name.GetStringRef(), eBasicTypeInvalid); | 
|  | } | 
|  | return eBasicTypeInvalid; | 
|  | } | 
|  |  | 
|  | lldb::LanguageType | 
|  | GoASTContext::GetMinimumLanguage(lldb::opaque_compiler_type_t type) { | 
|  | return lldb::eLanguageTypeGo; | 
|  | } | 
|  |  | 
|  | unsigned GoASTContext::GetTypeQualifiers(lldb::opaque_compiler_type_t type) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Creating related types | 
|  | //---------------------------------------------------------------------- | 
|  |  | 
|  | CompilerType | 
|  | GoASTContext::GetArrayElementType(lldb::opaque_compiler_type_t type, | 
|  | uint64_t *stride) { | 
|  | GoArray *array = static_cast<GoType *>(type)->GetArray(); | 
|  | if (array) { | 
|  | if (stride) { | 
|  | *stride = array->GetElementType().GetByteSize(nullptr); | 
|  | } | 
|  | return array->GetElementType(); | 
|  | } | 
|  | return CompilerType(); | 
|  | } | 
|  |  | 
|  | CompilerType GoASTContext::GetCanonicalType(lldb::opaque_compiler_type_t type) { | 
|  | GoType *t = static_cast<GoType *>(type); | 
|  | if (t->IsTypedef()) | 
|  | return t->GetElementType(); | 
|  | return CompilerType(this, type); | 
|  | } | 
|  |  | 
|  | CompilerType | 
|  | GoASTContext::GetFullyUnqualifiedType(lldb::opaque_compiler_type_t 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(lldb::opaque_compiler_type_t type) { | 
|  | return GetNumberOfFunctionArguments(type); | 
|  | } | 
|  |  | 
|  | CompilerType | 
|  | GoASTContext::GetFunctionArgumentTypeAtIndex(lldb::opaque_compiler_type_t type, | 
|  | size_t idx) { | 
|  | return GetFunctionArgumentAtIndex(type, idx); | 
|  | } | 
|  |  | 
|  | CompilerType | 
|  | GoASTContext::GetFunctionReturnType(lldb::opaque_compiler_type_t type) { | 
|  | CompilerType result; | 
|  | if (type) { | 
|  | GoType *t = static_cast<GoType *>(type); | 
|  | if (t->GetGoKind() == GoType::KIND_FUNC) | 
|  | result = t->GetElementType(); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | size_t GoASTContext::GetNumMemberFunctions(lldb::opaque_compiler_type_t type) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | TypeMemberFunctionImpl | 
|  | GoASTContext::GetMemberFunctionAtIndex(lldb::opaque_compiler_type_t type, | 
|  | size_t idx) { | 
|  | return TypeMemberFunctionImpl(); | 
|  | } | 
|  |  | 
|  | CompilerType | 
|  | GoASTContext::GetNonReferenceType(lldb::opaque_compiler_type_t type) { | 
|  | return CompilerType(this, type); | 
|  | } | 
|  |  | 
|  | CompilerType GoASTContext::GetPointeeType(lldb::opaque_compiler_type_t type) { | 
|  | if (!type) | 
|  | return CompilerType(); | 
|  | return static_cast<GoType *>(type)->GetElementType(); | 
|  | } | 
|  |  | 
|  | CompilerType GoASTContext::GetPointerType(lldb::opaque_compiler_type_t 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(lldb::opaque_compiler_type_t type) { | 
|  | if (IsTypedefType(type)) | 
|  | return static_cast<GoType *>(type)->GetElementType(); | 
|  | return CompilerType(); | 
|  | } | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Create related types using the current type's AST | 
|  | //---------------------------------------------------------------------- | 
|  | CompilerType GoASTContext::GetBasicTypeFromAST(lldb::BasicType basic_type) { | 
|  | return CompilerType(); | 
|  | } | 
|  |  | 
|  | CompilerType | 
|  | GoASTContext::GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, | 
|  | size_t bit_size) { | 
|  | return CompilerType(); | 
|  | } | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Exploring the type | 
|  | //---------------------------------------------------------------------- | 
|  |  | 
|  | uint64_t GoASTContext::GetBitSize(lldb::opaque_compiler_type_t type, | 
|  | ExecutionContextScope *exe_scope) { | 
|  | if (!type) | 
|  | return 0; | 
|  | if (!GetCompleteType(type)) | 
|  | return 0; | 
|  | GoType *t = static_cast<GoType *>(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); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | lldb::Encoding GoASTContext::GetEncoding(lldb::opaque_compiler_type_t 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(lldb::opaque_compiler_type_t type) { | 
|  | if (!type) | 
|  | return eFormatDefault; | 
|  | switch (static_cast<GoType *>(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(lldb::opaque_compiler_type_t type) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | uint32_t GoASTContext::GetNumChildren(lldb::opaque_compiler_type_t type, | 
|  | bool omit_empty_base_classes) { | 
|  | if (!type || !GetCompleteType(type)) | 
|  | return 0; | 
|  | GoType *t = static_cast<GoType *>(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(); | 
|  | } else if (t->IsTypedef()) { | 
|  | return t->GetElementType().GetNumChildren(omit_empty_base_classes); | 
|  | } | 
|  |  | 
|  | return GetNumFields(type); | 
|  | } | 
|  |  | 
|  | uint32_t GoASTContext::GetNumFields(lldb::opaque_compiler_type_t type) { | 
|  | if (!type || !GetCompleteType(type)) | 
|  | return 0; | 
|  | GoType *t = static_cast<GoType *>(type); | 
|  | if (t->IsTypedef()) | 
|  | return t->GetElementType().GetNumFields(); | 
|  | GoStruct *s = t->GetStruct(); | 
|  | if (s) | 
|  | return s->GetNumFields(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | CompilerType GoASTContext::GetFieldAtIndex(lldb::opaque_compiler_type_t 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<GoType *>(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::GetChildCompilerTypeAtIndex( | 
|  | lldb::opaque_compiler_type_t 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, uint64_t &language_flags) { | 
|  | 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; | 
|  | language_flags = 0; | 
|  |  | 
|  | if (!type || !GetCompleteType(type)) | 
|  | return CompilerType(); | 
|  |  | 
|  | GoType *t = static_cast<GoType *>(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.GetChildCompilerTypeAtIndex( | 
|  | 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, | 
|  | language_flags); | 
|  | } 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().GetChildCompilerTypeAtIndex( | 
|  | 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, language_flags); | 
|  | } | 
|  | 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(lldb::opaque_compiler_type_t type, | 
|  | const char *name, | 
|  | bool omit_empty_base_classes) { | 
|  | if (!type || !GetCompleteType(type)) | 
|  | return UINT_MAX; | 
|  |  | 
|  | GoType *t = static_cast<GoType *>(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<vector<uint32_t>> | 
|  | // so we catch all names that match a given child name, not just the first. | 
|  | size_t GoASTContext::GetIndexOfChildMemberWithName( | 
|  | lldb::opaque_compiler_type_t type, const char *name, | 
|  | bool omit_empty_base_classes, std::vector<uint32_t> &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(lldb::opaque_compiler_type_t type, | 
|  | const char *s, uint8_t *dst, | 
|  | size_t dst_size) { | 
|  | assert(false); | 
|  | return 0; | 
|  | } | 
|  | //---------------------------------------------------------------------- | 
|  | // Dumping types | 
|  | //---------------------------------------------------------------------- | 
|  | #define DEPTH_INCREMENT 2 | 
|  |  | 
|  | void GoASTContext::DumpValue(lldb::opaque_compiler_type_t type, | 
|  | ExecutionContext *exe_ctx, Stream *s, | 
|  | lldb::Format format, const DataExtractor &data, | 
|  | lldb::offset_t data_byte_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) { | 
|  | if (IsTypedefType(type)) | 
|  | type = GetTypedefedType(type).GetOpaqueQualType(); | 
|  | if (!type) | 
|  | return; | 
|  | GoType *t = static_cast<GoType *>(type); | 
|  |  | 
|  | if (GoStruct *st = t->GetStruct()) { | 
|  | if (GetCompleteType(type)) { | 
|  | uint32_t field_idx = 0; | 
|  | for (auto *field = st->GetField(field_idx); field != nullptr; | 
|  | field_idx++) { | 
|  | // Print the starting squiggly bracket (if this is the | 
|  | // first member) or comma (for member 2 and beyond) for | 
|  | // the struct/union/class member. | 
|  | if (field_idx == 0) | 
|  | s->PutChar('{'); | 
|  | else | 
|  | s->PutChar(','); | 
|  |  | 
|  | // Indent | 
|  | s->Printf("\n%*s", depth + DEPTH_INCREMENT, ""); | 
|  |  | 
|  | // Print the member type if requested | 
|  | if (show_types) { | 
|  | ConstString field_type_name = field->m_type.GetTypeName(); | 
|  | s->Printf("(%s) ", field_type_name.AsCString()); | 
|  | } | 
|  | // Print the member name and equal sign | 
|  | s->Printf("%s = ", field->m_name.AsCString()); | 
|  |  | 
|  | // Dump the value of the member | 
|  | CompilerType field_type = field->m_type; | 
|  | field_type.DumpValue( | 
|  | exe_ctx, | 
|  | s, // Stream to dump to | 
|  | field_type | 
|  | .GetFormat(), // The format with which to display the member | 
|  | data,             // Data buffer containing all bytes for this type | 
|  | data_byte_offset + field->m_byte_offset, // Offset into "data" where | 
|  | // to grab value from | 
|  | field->m_type.GetByteSize( | 
|  | exe_ctx->GetBestExecutionContextScope()), // Size of this type | 
|  | // in bytes | 
|  | 0,                                            // Bitfield bit size | 
|  | 0,                                            // Bitfield bit offset | 
|  | show_types,   // Boolean indicating if we should show the variable | 
|  | // types | 
|  | show_summary, // Boolean indicating if we should show a summary for | 
|  | // the current type | 
|  | verbose,      // Verbose output? | 
|  | depth + DEPTH_INCREMENT); // Scope depth for any types that have | 
|  | // children | 
|  | } | 
|  |  | 
|  | // Indent the trailing squiggly bracket | 
|  | if (field_idx > 0) | 
|  | s->Printf("\n%*s}", depth, ""); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (GoArray *a = t->GetArray()) { | 
|  | CompilerType element_clang_type = a->GetElementType(); | 
|  | lldb::Format element_format = element_clang_type.GetFormat(); | 
|  | uint32_t element_byte_size = | 
|  | element_clang_type.GetByteSize(exe_ctx->GetBestExecutionContextScope()); | 
|  |  | 
|  | uint64_t element_idx; | 
|  | for (element_idx = 0; element_idx < a->GetLength(); ++element_idx) { | 
|  | // Print the starting squiggly bracket (if this is the | 
|  | // first member) or comman (for member 2 and beyong) for | 
|  | // the struct/union/class member. | 
|  | if (element_idx == 0) | 
|  | s->PutChar('{'); | 
|  | else | 
|  | s->PutChar(','); | 
|  |  | 
|  | // Indent and print the index | 
|  | s->Printf("\n%*s[%" PRIu64 "] ", depth + DEPTH_INCREMENT, "", | 
|  | element_idx); | 
|  |  | 
|  | // Figure out the field offset within the current struct/union/class type | 
|  | uint64_t element_offset = element_idx * element_byte_size; | 
|  |  | 
|  | // Dump the value of the member | 
|  | element_clang_type.DumpValue( | 
|  | exe_ctx, | 
|  | s,              // Stream to dump to | 
|  | element_format, // The format with which to display the element | 
|  | data,           // Data buffer containing all bytes for this type | 
|  | data_byte_offset + | 
|  | element_offset, // Offset into "data" where to grab value from | 
|  | element_byte_size,  // Size of this type in bytes | 
|  | 0,                  // Bitfield bit size | 
|  | 0,                  // Bitfield bit offset | 
|  | show_types, // Boolean indicating if we should show the variable types | 
|  | show_summary, // Boolean indicating if we should show a summary for | 
|  | // the current type | 
|  | verbose,      // Verbose output? | 
|  | depth + | 
|  | DEPTH_INCREMENT); // Scope depth for any types that have children | 
|  | } | 
|  |  | 
|  | // Indent the trailing squiggly bracket | 
|  | if (element_idx > 0) | 
|  | s->Printf("\n%*s}", depth, ""); | 
|  | } | 
|  |  | 
|  | if (show_summary) | 
|  | DumpSummary(type, exe_ctx, s, data, data_byte_offset, data_byte_size); | 
|  | } | 
|  |  | 
|  | bool GoASTContext::DumpTypeValue(lldb::opaque_compiler_type_t 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<GoType *>(type); | 
|  | if (t->IsTypedef()) { | 
|  | CompilerType typedef_compiler_type = t->GetElementType(); | 
|  | if (format == eFormatDefault) | 
|  | format = typedef_compiler_type.GetFormat(); | 
|  | uint64_t typedef_byte_size = typedef_compiler_type.GetByteSize(exe_scope); | 
|  |  | 
|  | return typedef_compiler_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(lldb::opaque_compiler_type_t type, | 
|  | ExecutionContext *exe_ctx, Stream *s, | 
|  | const DataExtractor &data, | 
|  | lldb::offset_t data_offset, | 
|  | size_t data_byte_size) { | 
|  | if (type && GoType::KIND_STRING == static_cast<GoType *>(type)->GetGoKind()) { | 
|  | // TODO(ribrdb): read length and data | 
|  | } | 
|  | } | 
|  |  | 
|  | void GoASTContext::DumpTypeDescription(lldb::opaque_compiler_type_t type) { | 
|  | // Dump to stdout | 
|  | StreamFile s(stdout, false); | 
|  | DumpTypeDescription(type, &s); | 
|  | } | 
|  |  | 
|  | void GoASTContext::DumpTypeDescription(lldb::opaque_compiler_type_t type, | 
|  | Stream *s) { | 
|  | if (!type) | 
|  | return; | 
|  | ConstString name = GetTypeName(type); | 
|  | GoType *t = static_cast<GoType *>(type); | 
|  |  | 
|  | if (GoStruct *st = t->GetStruct()) { | 
|  | if (GetCompleteType(type)) { | 
|  | if (NULL == strchr(name.AsCString(), '{')) | 
|  | s->Printf("type %s ", name.AsCString()); | 
|  | s->PutCString("struct {"); | 
|  | if (st->GetNumFields() == 0) { | 
|  | s->PutChar('}'); | 
|  | return; | 
|  | } | 
|  | s->IndentMore(); | 
|  | uint32_t field_idx = 0; | 
|  | for (auto *field = st->GetField(field_idx); field != nullptr; | 
|  | field_idx++) { | 
|  | s->PutChar('\n'); | 
|  | s->Indent(); | 
|  | s->Printf("%s %s", field->m_name.AsCString(), | 
|  | field->m_type.GetTypeName().AsCString()); | 
|  | } | 
|  | s->IndentLess(); | 
|  | s->PutChar('\n'); | 
|  | s->Indent("}"); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | s->PutCString(name.AsCString()); | 
|  | } | 
|  |  | 
|  | CompilerType GoASTContext::CreateArrayType(const ConstString &name, | 
|  | const CompilerType &element_type, | 
|  | uint64_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::CreateTypedefType(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<GoASTContext>(struct_type.GetTypeSystem()); | 
|  | if (!ast) | 
|  | return; | 
|  | GoType *type = static_cast<GoType *>(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<GoASTContext>(struct_type.GetTypeSystem()); | 
|  | if (!ast) | 
|  | return; | 
|  | GoType *type = static_cast<GoType *>(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<GoASTContext>(type.GetTypeSystem())) | 
|  | return false; | 
|  | return GoType::KIND_STRING == | 
|  | static_cast<GoType *>(type.GetOpaqueQualType())->GetGoKind(); | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsGoSlice(const lldb_private::CompilerType &type) { | 
|  | if (!type.IsValid() || | 
|  | !llvm::dyn_cast_or_null<GoASTContext>(type.GetTypeSystem())) | 
|  | return false; | 
|  | return GoType::KIND_SLICE == | 
|  | static_cast<GoType *>(type.GetOpaqueQualType())->GetGoKind(); | 
|  | } | 
|  |  | 
|  | bool GoASTContext::IsGoInterface(const lldb_private::CompilerType &type) { | 
|  | if (!type.IsValid() || | 
|  | !llvm::dyn_cast_or_null<GoASTContext>(type.GetTypeSystem())) | 
|  | return false; | 
|  | return GoType::KIND_INTERFACE == | 
|  | static_cast<GoType *>(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(); | 
|  | } | 
|  |  | 
|  | UserExpression *GoASTContextForExpr::GetUserExpression( | 
|  | llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language, | 
|  | Expression::ResultType desired_type, | 
|  | const EvaluateExpressionOptions &options) { | 
|  | TargetSP target = m_target_wp.lock(); | 
|  | if (target) | 
|  | return new GoUserExpression(*target, expr, prefix, language, desired_type, | 
|  | options); | 
|  | return nullptr; | 
|  | } |