blob: da5c82b2cb55284f5ccd45985fee77f75c7c8d70 [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/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;
}