| //===-- 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/ObjectFile.h" |
| #include "lldb/Symbol/SymbolFile.h" |
| #include "lldb/Symbol/GoASTContext.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").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(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(const char *expr, const char *expr_prefix, lldb::LanguageType language, |
| Expression::ResultType desired_type, const EvaluateExpressionOptions &options) |
| { |
| TargetSP target = m_target_wp.lock(); |
| if (target) |
| return new GoUserExpression(*target, expr, expr_prefix, language, desired_type, options); |
| return nullptr; |
| } |