forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			1448 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			1448 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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/DumpDataExtractor.h"
 | |
| #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/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 "llvm/Support/Threading.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 llvm::once_flag g_once_flag;
 | |
|     llvm::call_once(g_once_flag, []() {
 | |
|       // "void"
 | |
|       g_type_map.Append(ConstString("void"), eBasicTypeVoid);
 | |
|       // "int"
 | |
|       g_type_map.Append(ConstString("int"), eBasicTypeInt);
 | |
|       g_type_map.Append(ConstString("uint"), eBasicTypeUnsignedInt);
 | |
| 
 | |
|       // Miscellaneous
 | |
|       g_type_map.Append(ConstString("bool"), eBasicTypeBool);
 | |
| 
 | |
|       // Others. Should these map to C types?
 | |
|       g_type_map.Append(ConstString("byte"), eBasicTypeOther);
 | |
|       g_type_map.Append(ConstString("uint8"), eBasicTypeOther);
 | |
|       g_type_map.Append(ConstString("uint16"), eBasicTypeOther);
 | |
|       g_type_map.Append(ConstString("uint32"), eBasicTypeOther);
 | |
|       g_type_map.Append(ConstString("uint64"), eBasicTypeOther);
 | |
|       g_type_map.Append(ConstString("int8"), eBasicTypeOther);
 | |
|       g_type_map.Append(ConstString("int16"), eBasicTypeOther);
 | |
|       g_type_map.Append(ConstString("int32"), eBasicTypeOther);
 | |
|       g_type_map.Append(ConstString("int64"), eBasicTypeOther);
 | |
|       g_type_map.Append(ConstString("float32"), eBasicTypeOther);
 | |
|       g_type_map.Append(ConstString("float64"), eBasicTypeOther);
 | |
|       g_type_map.Append(ConstString("uintptr"), eBasicTypeOther);
 | |
| 
 | |
|       g_type_map.Sort();
 | |
|     });
 | |
| 
 | |
|     return g_type_map.Find(name, 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 DumpDataExtractor(data, 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;
 | |
| }
 |