blob: faca778f069c9d42146a511ee1b5cebb0c136760 [file] [log] [blame]
//===-- 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;
}