Add a TypeSystem for Go

Add GoASTContext and DWARFASTParserGo to support go.

Differential Revision: http://reviews.llvm.org/D12585

llvm-svn: 247629
This commit is contained in:
Ryan Brown 2015-09-14 22:45:11 +00:00
parent 3e13005031
commit 57bee1edfc
19 changed files with 2932 additions and 26 deletions

View File

@ -1119,7 +1119,8 @@ protected:
lldb::SymbolVendorUP m_symfile_ap; ///< A pointer to the symbol vendor for this module.
std::vector<lldb::SymbolVendorUP> m_old_symfiles; ///< If anyone calls Module::SetSymbolFileFileSpec() and changes the symbol file,
///< we need to keep all old symbol files around in case anyone has type references to them
lldb::ClangASTContextUP m_ast; ///< The AST context for this module.
lldb::ClangASTContextUP m_ast; ///< The Clang AST context for this module.
lldb::GoASTContextUP m_go_ast; ///< The Go AST context for this module.
PathMappingList m_source_mappings; ///< Module specific source remappings for when you have debug info for a module that doesn't match where the sources currently are
lldb::SectionListUP m_sections_ap; ///< Unified section list for module that is used by the ObjectFile and and ObjectFile instances for the debug info

View File

@ -485,7 +485,6 @@ public:
//------------------------------------------------------------------
// TypeSystem methods
//------------------------------------------------------------------
DWARFASTParser *
GetDWARFParser () override;

View File

@ -318,7 +318,6 @@ public:
static lldb::BasicType
GetBasicTypeEnumeration (const ConstString &name);
//----------------------------------------------------------------------
// If this type is an enumeration, iterate through all of its enumerators
// using a callback. If the callback returns true, keep iterating, else

View File

@ -0,0 +1,335 @@
//===-- GoASTContext.h ------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __lldb__GoASTContext__
#define __lldb__GoASTContext__
#include <map>
#include "lldb/Core/ConstString.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Symbol/CompilerType.h"
namespace lldb_private
{
class Declaration;
class GoType;
class GoASTContext : public TypeSystem
{
public:
GoASTContext();
~GoASTContext();
DWARFASTParser *GetDWARFParser() override;
void
SetAddressByteSize(int byte_size)
{
m_pointer_byte_size = byte_size;
}
//------------------------------------------------------------------
// llvm casting support
//------------------------------------------------------------------
static bool classof(const TypeSystem *ts)
{
return ts->getKind() == TypeSystem::eKindGo;
}
//----------------------------------------------------------------------
// CompilerDeclContext functions
//----------------------------------------------------------------------
virtual bool
DeclContextIsStructUnionOrClass(void *opaque_decl_ctx) override
{
return false;
}
virtual ConstString
DeclContextGetName(void *opaque_decl_ctx) override
{
return ConstString();
}
virtual bool
DeclContextIsClassMethod(void *opaque_decl_ctx, lldb::LanguageType *language_ptr, bool *is_instance_method_ptr,
ConstString *language_object_name_ptr) override
{
return false;
}
//----------------------------------------------------------------------
// Creating Types
//----------------------------------------------------------------------
CompilerType CreateArrayType(const ConstString &name, const CompilerType &element_type, int64_t length);
CompilerType CreateBaseType(int go_kind, const ConstString &type_name_const_str, uint64_t byte_size);
// For interface, map, chan.
CompilerType CreateTypedef(int kind, const ConstString &name, CompilerType impl);
CompilerType CreateVoidType(const ConstString &name);
CompilerType CreateFunctionType(const lldb_private::ConstString &name, CompilerType *params, size_t params_count,
bool is_variadic);
CompilerType CreateStructType(int kind, const ConstString &name, uint32_t byte_size);
void CompleteStructType(const CompilerType &type);
void AddFieldToStruct(const CompilerType &struct_type, const ConstString &name, const CompilerType &field_type,
uint32_t byte_offset);
//----------------------------------------------------------------------
// Tests
//----------------------------------------------------------------------
static bool IsGoString(const CompilerType &type);
static bool IsGoSlice(const CompilerType &type);
static bool IsGoInterface(const CompilerType &type);
static bool IsDirectIface(uint8_t kind);
static bool IsPointerKind(uint8_t kind);
virtual bool IsArrayType(void *type, CompilerType *element_type, uint64_t *size, bool *is_incomplete) override;
virtual bool IsAggregateType(void *type) override;
virtual bool IsCharType(void *type) override;
virtual bool IsCompleteType(void *type) override;
virtual bool IsDefined(void *type) override;
virtual bool IsFloatingPointType(void *type, uint32_t &count, bool &is_complex) override;
virtual bool IsFunctionType(void *type, bool *is_variadic_ptr = NULL) override;
virtual size_t GetNumberOfFunctionArguments(void *type) override;
virtual CompilerType GetFunctionArgumentAtIndex(void *type, const size_t index) override;
virtual bool IsFunctionPointerType(void *type) override;
virtual bool IsIntegerType(void *type, bool &is_signed) override;
virtual bool IsPossibleDynamicType(void *type,
CompilerType *target_type, // Can pass NULL
bool check_cplusplus, bool check_objc) override;
virtual bool IsPointerType(void *type, CompilerType *pointee_type = NULL) override;
virtual bool IsScalarType(void *type) override;
virtual bool IsVoidType(void *type) override;
//----------------------------------------------------------------------
// Type Completion
//----------------------------------------------------------------------
virtual bool GetCompleteType(void *type) override;
//----------------------------------------------------------------------
// AST related queries
//----------------------------------------------------------------------
virtual uint32_t GetPointerByteSize() override;
//----------------------------------------------------------------------
// Accessors
//----------------------------------------------------------------------
virtual ConstString GetTypeName(void *type) override;
virtual uint32_t GetTypeInfo(void *type, CompilerType *pointee_or_element_clang_type = NULL) override;
virtual lldb::LanguageType GetMinimumLanguage(void *type) override;
virtual lldb::TypeClass GetTypeClass(void *type) override;
//----------------------------------------------------------------------
// Creating related types
//----------------------------------------------------------------------
virtual CompilerType GetArrayElementType(void *type, uint64_t *stride = nullptr) override;
virtual CompilerType GetCanonicalType(void *type) override;
// 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.
virtual int GetFunctionArgumentCount(void *type) override;
virtual CompilerType GetFunctionArgumentTypeAtIndex(void *type, size_t idx) override;
virtual CompilerType GetFunctionReturnType(void *type) override;
virtual size_t GetNumMemberFunctions(void *type) override;
virtual TypeMemberFunctionImpl GetMemberFunctionAtIndex(void *type, size_t idx) override;
virtual CompilerType GetPointeeType(void *type) override;
virtual CompilerType GetPointerType(void *type) override;
//----------------------------------------------------------------------
// Exploring the type
//----------------------------------------------------------------------
virtual uint64_t GetBitSize(void *type, ExecutionContextScope *exe_scope) override;
virtual lldb::Encoding GetEncoding(void *type, uint64_t &count) override;
virtual lldb::Format GetFormat(void *type) override;
virtual uint32_t GetNumChildren(void *type, bool omit_empty_base_classes) override;
virtual lldb::BasicType GetBasicTypeEnumeration(void *type) override;
virtual CompilerType GetIntTypeFromBitSize (size_t bit_size, bool is_signed) override;
virtual CompilerType GetFloatTypeFromBitSize (size_t bit_size) override;
virtual uint32_t GetNumFields(void *type) override;
virtual CompilerType GetFieldAtIndex(void *type, size_t idx, std::string &name, uint64_t *bit_offset_ptr,
uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) override;
virtual uint32_t
GetNumDirectBaseClasses(void *type) override
{
return 0;
}
virtual uint32_t
GetNumVirtualBaseClasses(void *type) override
{
return 0;
}
virtual CompilerType
GetDirectBaseClassAtIndex(void *type, size_t idx, uint32_t *bit_offset_ptr) override
{
return CompilerType();
}
virtual CompilerType
GetVirtualBaseClassAtIndex(void *type, size_t idx, uint32_t *bit_offset_ptr) override
{
return CompilerType();
}
virtual CompilerType GetChildClangTypeAtIndex(void *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) override;
// Lookup a child given a name. This function will match base class names
// and member member names in "clang_type" only, not descendants.
virtual uint32_t GetIndexOfChildWithName(void *type, const char *name, bool omit_empty_base_classes) override;
// 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.
virtual size_t GetIndexOfChildMemberWithName(void *type, const char *name, bool omit_empty_base_classes,
std::vector<uint32_t> &child_indexes) override;
virtual size_t
GetNumTemplateArguments(void *type) override
{
return 0;
}
virtual CompilerType
GetTemplateArgument(void *type, size_t idx, lldb::TemplateArgumentKind &kind) override
{
return CompilerType();
}
//----------------------------------------------------------------------
// Dumping types
//----------------------------------------------------------------------
virtual void DumpValue(void *type, ExecutionContext *exe_ctx, Stream *s, lldb::Format format,
const DataExtractor &data, lldb::offset_t data_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) override;
virtual bool DumpTypeValue(void *type, Stream *s, lldb::Format format, const DataExtractor &data,
lldb::offset_t data_offset, size_t data_byte_size, uint32_t bitfield_bit_size,
uint32_t bitfield_bit_offset, ExecutionContextScope *exe_scope) override;
virtual void DumpTypeDescription(void *type) override; // Dump to stdout
virtual void DumpTypeDescription(void *type, Stream *s) override;
//----------------------------------------------------------------------
// TODO: These methods appear unused. Should they be removed?
//----------------------------------------------------------------------
virtual bool IsRuntimeGeneratedType(void *type) override;
virtual void DumpSummary(void *type, ExecutionContext *exe_ctx, Stream *s, const DataExtractor &data,
lldb::offset_t data_offset, size_t data_byte_size) override;
// Converts "s" to a floating point value and place resulting floating
// point bytes in the "dst" buffer.
virtual size_t ConvertStringToFloatValue(void *type, const char *s, uint8_t *dst, size_t dst_size) override;
//----------------------------------------------------------------------
// TODO: Determine if these methods should move to ClangASTContext.
//----------------------------------------------------------------------
virtual bool IsPointerOrReferenceType(void *type, CompilerType *pointee_type = NULL) override;
virtual unsigned GetTypeQualifiers(void *type) override;
virtual bool IsCStringType(void *type, uint32_t &length) override;
virtual size_t GetTypeBitAlign(void *type) override;
virtual CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override;
virtual bool IsBeingDefined(void *type) override;
virtual bool IsConst(void *type) override;
virtual uint32_t IsHomogeneousAggregate(void *type, CompilerType *base_type_ptr) override;
virtual bool IsPolymorphicClass(void *type) override;
virtual bool IsTypedefType(void *type) override;
// If the current object represents a typedef type, get the underlying type
virtual CompilerType GetTypedefedType(void *type) override;
virtual bool IsVectorType(void *type, CompilerType *element_type, uint64_t *size) override;
virtual CompilerType GetFullyUnqualifiedType(void *type) override;
virtual CompilerType GetNonReferenceType(void *type) override;
virtual bool IsReferenceType(void *type, CompilerType *pointee_type = nullptr, bool *is_rvalue = nullptr) override;
private:
typedef std::map<ConstString, std::unique_ptr<GoType>> TypeMap;
int m_pointer_byte_size;
int m_int_byte_size;
std::unique_ptr<TypeMap> m_types;
std::unique_ptr<DWARFASTParser> m_dwarf_ast_parser_ap;
GoASTContext(const GoASTContext &) = delete;
const GoASTContext &operator=(const GoASTContext &) = delete;
};
}
#endif /* defined(__lldb__GoASTContext__) */

View File

@ -99,6 +99,7 @@ class File;
class FileSpec;
class FileSpecList;
class Flags;
class GoASTContext;
class TypeCategoryImpl;
class FormatManager;
class FormattersMatchCandidate;
@ -326,6 +327,7 @@ namespace lldb {
typedef std::shared_ptr<lldb_private::File> FileSP;
typedef std::shared_ptr<lldb_private::Function> FunctionSP;
typedef std::shared_ptr<lldb_private::FuncUnwinders> FuncUnwindersSP;
typedef std::unique_ptr<lldb_private::GoASTContext> GoASTContextUP;
typedef std::shared_ptr<lldb_private::InlineFunctionInfo> InlineFunctionInfoSP;
typedef std::shared_ptr<lldb_private::Instruction> InstructionSP;
typedef std::shared_ptr<lldb_private::InstrumentationRuntime> InstrumentationRuntimeSP;

View File

@ -814,6 +814,8 @@
9AC703AF117675410086C050 /* SBInstruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC703AE117675410086C050 /* SBInstruction.cpp */; };
9AC703B1117675490086C050 /* SBInstructionList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC703B0117675490086C050 /* SBInstructionList.cpp */; };
A36FF33C17D8E94600244D40 /* OptionParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A36FF33B17D8E94600244D40 /* OptionParser.cpp */; };
AE6897281B94F6DE0018845D /* DWARFASTParserGo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE6897261B94F6DE0018845D /* DWARFASTParserGo.cpp */; };
AE7F56291B8FE418001377A8 /* GoASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEFFBA7C1AC4835D0087B932 /* GoASTContext.cpp */; };
AEEA34051AC88A7400AB639D /* TypeSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEEA34041AC88A7400AB639D /* TypeSystem.cpp */; };
AF061F87182C97ED00B6A19C /* RegisterContextHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF061F85182C97ED00B6A19C /* RegisterContextHistory.cpp */; };
AF0C112818580CD800C4C45B /* QueueItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF0C112718580CD800C4C45B /* QueueItem.cpp */; };
@ -2611,8 +2613,12 @@
9AF16CC7114086A1007A7B3F /* SBBreakpointLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBBreakpointLocation.cpp; path = source/API/SBBreakpointLocation.cpp; sourceTree = "<group>"; };
A36FF33B17D8E94600244D40 /* OptionParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OptionParser.cpp; sourceTree = "<group>"; };
A36FF33D17D8E98800244D40 /* OptionParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OptionParser.h; path = include/lldb/Host/OptionParser.h; sourceTree = "<group>"; };
AE6897261B94F6DE0018845D /* DWARFASTParserGo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFASTParserGo.cpp; sourceTree = "<group>"; };
AE6897271B94F6DE0018845D /* DWARFASTParserGo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFASTParserGo.h; sourceTree = "<group>"; };
AEEA33F61AC74FE700AB639D /* TypeSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeSystem.h; path = include/lldb/Symbol/TypeSystem.h; sourceTree = "<group>"; };
AEEA34041AC88A7400AB639D /* TypeSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeSystem.cpp; path = source/Symbol/TypeSystem.cpp; sourceTree = "<group>"; };
AEEA340F1ACA08A000AB639D /* GoASTContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GoASTContext.h; path = include/lldb/Symbol/GoASTContext.h; sourceTree = "<group>"; };
AEFFBA7C1AC4835D0087B932 /* GoASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GoASTContext.cpp; path = source/Symbol/GoASTContext.cpp; sourceTree = "<group>"; };
AF061F85182C97ED00B6A19C /* RegisterContextHistory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterContextHistory.cpp; path = Utility/RegisterContextHistory.cpp; sourceTree = "<group>"; };
AF061F86182C97ED00B6A19C /* RegisterContextHistory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextHistory.h; path = Utility/RegisterContextHistory.h; sourceTree = "<group>"; };
AF061F89182C980000B6A19C /* HistoryThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HistoryThread.h; path = Utility/HistoryThread.h; sourceTree = "<group>"; };
@ -3124,6 +3130,8 @@
269DDD451B8FD01A00D0DBD8 /* DWARFASTParser.h */,
269DDD491B8FD1C300D0DBD8 /* DWARFASTParserClang.h */,
269DDD481B8FD1C300D0DBD8 /* DWARFASTParserClang.cpp */,
AE6897271B94F6DE0018845D /* DWARFASTParserGo.h */,
AE6897261B94F6DE0018845D /* DWARFASTParserGo.cpp */,
260C89B610F57C5600BB2B04 /* DWARFAttribute.h */,
266E829C1B8E542C008FCA06 /* DWARFAttribute.cpp */,
260C89B710F57C5600BB2B04 /* DWARFCompileUnit.cpp */,
@ -4208,6 +4216,8 @@
26BC7F1810F1B8EC00F91463 /* Function.cpp */,
269FF07D12494F7D00225026 /* FuncUnwinders.h */,
961FABB81235DE1600F93A47 /* FuncUnwinders.cpp */,
AEEA340F1ACA08A000AB639D /* GoASTContext.h */,
AEFFBA7C1AC4835D0087B932 /* GoASTContext.cpp */,
26BC7C5B10F1B6E900F91463 /* LineEntry.h */,
26BC7F1910F1B8EC00F91463 /* LineEntry.cpp */,
26BC7C5C10F1B6E900F91463 /* LineTable.h */,
@ -6314,6 +6324,7 @@
2689007C13353E1A00698AC0 /* Symbols.cpp in Sources */,
2689007D13353E2200698AC0 /* Args.cpp in Sources */,
2689007F13353E2200698AC0 /* CommandCompletions.cpp in Sources */,
AE6897281B94F6DE0018845D /* DWARFASTParserGo.cpp in Sources */,
945261C41B9A11FC00BF138D /* LibCxxUnorderedMap.cpp in Sources */,
26CEB5F218762056008F575A /* CommandObjectGUI.cpp in Sources */,
2689008013353E2200698AC0 /* CommandInterpreter.cpp in Sources */,
@ -6630,6 +6641,7 @@
260CC64C15D0440D002BF2E0 /* OptionValueDictionary.cpp in Sources */,
49DCF6FE170E6B4A0092F75E /* IRMemoryMap.cpp in Sources */,
260CC64D15D0440D002BF2E0 /* OptionValueEnumeration.cpp in Sources */,
AE7F56291B8FE418001377A8 /* GoASTContext.cpp in Sources */,
260CC64E15D0440D002BF2E0 /* OptionValueFileSpec.cpp in Sources */,
AF2BCA6C18C7EFDE005B4526 /* JITLoaderGDB.cpp in Sources */,
260CC64F15D0440D002BF2E0 /* OptionValueFileSpecLIst.cpp in Sources */,

View File

@ -25,6 +25,7 @@
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/GoASTContext.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolVendor.h"
@ -148,6 +149,7 @@ Module::Module (const ModuleSpec &module_spec) :
m_objfile_sp (),
m_symfile_ap (),
m_ast (new ClangASTContext),
m_go_ast(),
m_source_mappings (),
m_sections_ap(),
m_did_load_objfile (false),
@ -252,6 +254,7 @@ Module::Module(const FileSpec& file_spec,
m_objfile_sp (),
m_symfile_ap (),
m_ast (new ClangASTContext),
m_go_ast(),
m_source_mappings (),
m_sections_ap(),
m_did_load_objfile (false),
@ -298,6 +301,7 @@ Module::Module () :
m_objfile_sp (),
m_symfile_ap (),
m_ast (new ClangASTContext),
m_go_ast(),
m_source_mappings (),
m_sections_ap(),
m_did_load_objfile (false),
@ -420,7 +424,22 @@ Module::GetUUID()
TypeSystem *
Module::GetTypeSystemForLanguage (LanguageType language)
{
if (language != eLanguageTypeSwift)
if (language == eLanguageTypeGo)
{
Mutex::Locker locker (m_mutex);
if (!m_go_ast)
{
ObjectFile * objfile = GetObjectFile();
ArchSpec object_arch;
if (objfile && objfile->GetArchitecture(object_arch))
{
m_go_ast.reset(new GoASTContext);
m_go_ast->SetAddressByteSize(object_arch.GetAddressByteSize());
}
}
return m_go_ast.get();
}
else if (language != eLanguageTypeSwift)
{
// For now assume all languages except swift use the ClangASTContext for types
return &GetClangASTContext();

View File

@ -2,6 +2,7 @@ add_lldb_library(lldbPluginSymbolFileDWARF
DIERef.cpp
DWARFAbbreviationDeclaration.cpp
DWARFASTParserClang.cpp
DWARFASTParserGo.cpp
DWARFAttribute.cpp
DWARFCompileUnit.cpp
DWARFDataExtractor.cpp

View File

@ -0,0 +1,828 @@
//===-- DWARFASTParserGo.cpp ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DWARFASTParserGo.h"
#include "DWARFASTParserGo.h"
#include "DWARFCompileUnit.h"
#include "DWARFDebugInfo.h"
#include "DWARFDeclContext.h"
#include "DWARFDefines.h"
#include "DWARFDIE.h"
#include "DWARFDIECollection.h"
#include "SymbolFileDWARF.h"
#include "SymbolFileDWARFDebugMap.h"
#include "UniqueDWARFASTType.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Value.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/TypeList.h"
//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN
#ifdef ENABLE_DEBUG_PRINTF
#include <stdio.h>
#define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
#else
#define DEBUG_PRINTF(fmt, ...)
#endif
#define DW_AT_go_kind 0x2900
#define DW_AT_go_key 0x2901
#define DW_AT_go_elem 0x2902
using namespace lldb;
using namespace lldb_private;
DWARFASTParserGo::DWARFASTParserGo(GoASTContext &ast)
: m_ast(ast)
{
}
DWARFASTParserGo::~DWARFASTParserGo()
{
}
TypeSP
DWARFASTParserGo::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, const DWARFDIE &die, lldb_private::Log *log,
bool *type_is_new_ptr)
{
TypeSP type_sp;
if (type_is_new_ptr)
*type_is_new_ptr = false;
if (die)
{
SymbolFileDWARF *dwarf = die.GetDWARF();
if (log)
{
dwarf->GetObjectFile()->GetModule()->LogMessage(
log, "DWARFASTParserGo::ParseTypeFromDWARF (die = 0x%8.8x) %s name = '%s')", die.GetOffset(),
DW_TAG_value_to_name(die.Tag()), die.GetName());
}
Type *type_ptr = dwarf->m_die_to_type.lookup(die.GetDIE());
TypeList *type_list = dwarf->GetTypeList();
if (type_ptr == NULL)
{
if (type_is_new_ptr)
*type_is_new_ptr = true;
const dw_tag_t tag = die.Tag();
bool is_forward_declaration = false;
DWARFAttributes attributes;
const char *type_name_cstr = NULL;
ConstString type_name_const_str;
Type::ResolveState resolve_state = Type::eResolveStateUnresolved;
uint64_t byte_size = 0;
uint64_t go_kind = 0;
Declaration decl;
Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID;
CompilerType clang_type;
DWARFFormValue form_value;
dw_attr_t attr;
switch (tag)
{
case DW_TAG_base_type:
case DW_TAG_pointer_type:
case DW_TAG_typedef:
case DW_TAG_unspecified_type:
{
// Set a bit that lets us know that we are currently parsing this
dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED;
const size_t num_attributes = die.GetAttributes(attributes);
uint32_t encoding = 0;
lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
if (num_attributes > 0)
{
uint32_t i;
for (i = 0; i < num_attributes; ++i)
{
attr = attributes.AttributeAtIndex(i);
if (attributes.ExtractFormValueAtIndex(i, form_value))
{
switch (attr)
{
case DW_AT_name:
type_name_cstr = form_value.AsCString();
if (type_name_cstr)
type_name_const_str.SetCString(type_name_cstr);
break;
case DW_AT_byte_size:
byte_size = form_value.Unsigned();
break;
case DW_AT_encoding:
encoding = form_value.Unsigned();
break;
case DW_AT_type:
encoding_uid = form_value.Reference();
break;
case DW_AT_go_kind:
go_kind = form_value.Unsigned();
break;
default:
// Do we care about DW_AT_go_key or DW_AT_go_elem?
break;
}
}
}
}
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8lx\n", dwarf->MakeUserID(die.GetOffset()),
DW_TAG_value_to_name(tag), type_name_cstr, encoding_uid);
switch (tag)
{
default:
break;
case DW_TAG_unspecified_type:
resolve_state = Type::eResolveStateFull;
clang_type = m_ast.CreateVoidType(type_name_const_str);
break;
case DW_TAG_base_type:
resolve_state = Type::eResolveStateFull;
clang_type = m_ast.CreateBaseType(go_kind, type_name_const_str, byte_size);
break;
case DW_TAG_pointer_type:
encoding_data_type = Type::eEncodingIsPointerUID;
break;
case DW_TAG_typedef:
encoding_data_type = Type::eEncodingIsTypedefUID;
CompilerType impl;
Type *type = dwarf->ResolveTypeUID(encoding_uid);
if (type)
{
if (go_kind == 0 && type->GetName() == type_name_const_str)
{
// Go emits extra typedefs as a forward declaration. Ignore these.
dwarf->m_die_to_type[die.GetDIE()] = type;
return type->shared_from_this();
}
impl = type->GetForwardCompilerType();
clang_type = m_ast.CreateTypedef(go_kind, type_name_const_str, impl);
}
break;
}
type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, byte_size,
NULL, encoding_uid, encoding_data_type, &decl, clang_type, resolve_state));
dwarf->m_die_to_type[die.GetDIE()] = type_sp.get();
}
break;
case DW_TAG_structure_type:
{
// Set a bit that lets us know that we are currently parsing this
dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED;
bool byte_size_valid = false;
const size_t num_attributes = die.GetAttributes(attributes);
if (num_attributes > 0)
{
uint32_t i;
for (i = 0; i < num_attributes; ++i)
{
attr = attributes.AttributeAtIndex(i);
if (attributes.ExtractFormValueAtIndex(i, form_value))
{
switch (attr)
{
case DW_AT_name:
type_name_cstr = form_value.AsCString();
type_name_const_str.SetCString(type_name_cstr);
break;
case DW_AT_byte_size:
byte_size = form_value.Unsigned();
byte_size_valid = true;
break;
case DW_AT_go_kind:
go_kind = form_value.Unsigned();
break;
// TODO: Should we use SLICETYPE's DW_AT_go_elem?
default:
break;
}
}
}
}
// TODO(ribrdb): Do we need this?
// UniqueDWARFASTType is large, so don't create a local variables on the
// stack, put it on the heap. This function is often called recursively
// and clang isn't good and sharing the stack space for variables in different blocks.
std::unique_ptr<UniqueDWARFASTType> unique_ast_entry_ap(new UniqueDWARFASTType());
// Only try and unique the type if it has a name.
if (type_name_const_str &&
dwarf->GetUniqueDWARFASTTypeMap().Find(type_name_const_str, die, decl,
byte_size_valid ? byte_size : -1, *unique_ast_entry_ap))
{
// We have already parsed this type or from another
// compile unit. GCC loves to use the "one definition
// rule" which can result in multiple definitions
// of the same class over and over in each compile
// unit.
type_sp = unique_ast_entry_ap->m_type_sp;
if (type_sp)
{
dwarf->m_die_to_type[die.GetDIE()] = type_sp.get();
return type_sp;
}
}
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", dwarf->MakeUserID(die.GetOffset()),
DW_TAG_value_to_name(tag), type_name_cstr);
bool clang_type_was_created = false;
clang_type.SetCompilerType(&m_ast, dwarf->m_forward_decl_die_to_clang_type.lookup(die.GetDIE()));
if (!clang_type)
{
clang_type_was_created = true;
clang_type = m_ast.CreateStructType(go_kind, type_name_const_str, byte_size);
}
type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, byte_size,
NULL, LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, clang_type,
Type::eResolveStateForward));
// Add our type to the unique type map so we don't
// end up creating many copies of the same type over
// and over in the ASTContext for our module
unique_ast_entry_ap->m_type_sp = type_sp;
unique_ast_entry_ap->m_die = die;
unique_ast_entry_ap->m_declaration = decl;
unique_ast_entry_ap->m_byte_size = byte_size;
dwarf->GetUniqueDWARFASTTypeMap().Insert(type_name_const_str, *unique_ast_entry_ap);
if (!is_forward_declaration)
{
// Always start the definition for a class type so that
// if the class has child classes or types that require
// the class to be created for use as their decl contexts
// the class will be ready to accept these child definitions.
if (die.HasChildren() == false)
{
// No children for this struct/union/class, lets finish it
m_ast.CompleteStructType(clang_type);
}
else if (clang_type_was_created)
{
// Leave this as a forward declaration until we need
// to know the details of the type. lldb_private::Type
// will automatically call the SymbolFile virtual function
// "SymbolFileDWARF::CompleteType(Type *)"
// When the definition needs to be defined.
dwarf->m_forward_decl_die_to_clang_type[die.GetDIE()] = clang_type.GetOpaqueQualType();
dwarf->m_forward_decl_clang_type_to_die[clang_type.GetOpaqueQualType()] = die.GetDIERef();
// SetHasExternalStorage (clang_type.GetOpaqueQualType(), true);
}
}
}
break;
case DW_TAG_subprogram:
case DW_TAG_subroutine_type:
{
// Set a bit that lets us know that we are currently parsing this
dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED;
bool is_variadic = false;
clang::StorageClass storage = clang::SC_None; //, Extern, Static, PrivateExtern
const size_t num_attributes = die.GetAttributes(attributes);
if (num_attributes > 0)
{
uint32_t i;
for (i = 0; i < num_attributes; ++i)
{
attr = attributes.AttributeAtIndex(i);
if (attributes.ExtractFormValueAtIndex(i, form_value))
{
switch (attr)
{
case DW_AT_name:
type_name_cstr = form_value.AsCString();
type_name_const_str.SetCString(type_name_cstr);
break;
case DW_AT_external:
if (form_value.Unsigned())
{
if (storage == clang::SC_None)
storage = clang::SC_Extern;
else
storage = clang::SC_PrivateExtern;
}
break;
case DW_AT_high_pc:
case DW_AT_low_pc:
break;
}
}
}
}
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", dwarf->MakeUserID(die.GetOffset()),
DW_TAG_value_to_name(tag), type_name_cstr);
std::vector<CompilerType> function_param_types;
// Parse the function children for the parameters
if (die.HasChildren())
{
ParseChildParameters(sc, die, is_variadic, function_param_types);
}
// clang_type will get the function prototype clang type after this call
clang_type = m_ast.CreateFunctionType(type_name_const_str, function_param_types.data(),
function_param_types.size(), is_variadic);
type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, 0, NULL,
LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, clang_type,
Type::eResolveStateFull));
assert(type_sp.get());
}
break;
case DW_TAG_array_type:
{
// Set a bit that lets us know that we are currently parsing this
dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED;
lldb::user_id_t type_die_offset = DW_INVALID_OFFSET;
int64_t first_index = 0;
uint32_t byte_stride = 0;
uint32_t bit_stride = 0;
const size_t num_attributes = die.GetAttributes(attributes);
if (num_attributes > 0)
{
uint32_t i;
for (i = 0; i < num_attributes; ++i)
{
attr = attributes.AttributeAtIndex(i);
if (attributes.ExtractFormValueAtIndex(i, form_value))
{
switch (attr)
{
case DW_AT_name:
type_name_cstr = form_value.AsCString();
type_name_const_str.SetCString(type_name_cstr);
break;
case DW_AT_type:
type_die_offset = form_value.Reference();
break;
case DW_AT_byte_size:
break; // byte_size = form_value.Unsigned(); break;
case DW_AT_go_kind:
go_kind = form_value.Unsigned();
break;
default:
break;
}
}
}
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", dwarf->MakeUserID(die.GetOffset()),
DW_TAG_value_to_name(tag), type_name_cstr);
Type *element_type = dwarf->ResolveTypeUID(type_die_offset);
if (element_type)
{
std::vector<uint64_t> element_orders;
ParseChildArrayInfo(sc, die, first_index, element_orders, byte_stride, bit_stride);
if (byte_stride == 0)
byte_stride = element_type->GetByteSize();
CompilerType array_element_type = element_type->GetForwardCompilerType();
if (element_orders.size() > 0)
{
if (element_orders.size() > 1)
printf("golang: unsupported multi-dimensional array %s\n", type_name_cstr);
clang_type =
m_ast.CreateArrayType(type_name_const_str, array_element_type, element_orders[0]);
}
else
{
clang_type = m_ast.CreateArrayType(type_name_const_str, array_element_type, 0);
}
type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str,
byte_stride, NULL, type_die_offset, Type::eEncodingIsUID, &decl,
clang_type, Type::eResolveStateFull));
type_sp->SetEncodingType(element_type);
}
}
}
break;
default:
dwarf->GetObjectFile()->GetModule()->ReportError("{0x%8.8x}: unhandled type tag 0x%4.4x (%s), "
"please file a bug and attach the file at the "
"start of this error message",
die.GetOffset(), tag, DW_TAG_value_to_name(tag));
break;
}
if (type_sp.get())
{
DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die);
dw_tag_t sc_parent_tag = sc_parent_die.Tag();
SymbolContextScope *symbol_context_scope = NULL;
if (sc_parent_tag == DW_TAG_compile_unit)
{
symbol_context_scope = sc.comp_unit;
}
else if (sc.function != NULL && sc_parent_die)
{
symbol_context_scope =
sc.function->GetBlock(true).FindBlockByID(dwarf->MakeUserID(sc_parent_die.GetOffset()));
if (symbol_context_scope == NULL)
symbol_context_scope = sc.function;
}
if (symbol_context_scope != NULL)
{
type_sp->SetSymbolContextScope(symbol_context_scope);
}
// We are ready to put this type into the uniqued list up at the module level
type_list->Insert(type_sp);
dwarf->m_die_to_type[die.GetDIE()] = type_sp.get();
}
}
else if (type_ptr != DIE_IS_BEING_PARSED)
{
type_sp = type_ptr->shared_from_this();
}
}
return type_sp;
}
size_t
DWARFASTParserGo::ParseChildParameters(const SymbolContext &sc,
const DWARFDIE &parent_die, bool &is_variadic,
std::vector<CompilerType> &function_param_types)
{
if (!parent_die)
return 0;
size_t arg_idx = 0;
for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling())
{
dw_tag_t tag = die.Tag();
switch (tag)
{
case DW_TAG_formal_parameter:
{
DWARFAttributes attributes;
const size_t num_attributes = die.GetAttributes(attributes);
if (num_attributes > 0)
{
const char *name = NULL;
Declaration decl;
dw_offset_t param_type_die_offset = DW_INVALID_OFFSET;
uint32_t i;
for (i = 0; i < num_attributes; ++i)
{
const dw_attr_t attr = attributes.AttributeAtIndex(i);
DWARFFormValue form_value;
if (attributes.ExtractFormValueAtIndex(i, form_value))
{
switch (attr)
{
case DW_AT_name:
name = form_value.AsCString();
break;
case DW_AT_type:
param_type_die_offset = form_value.Reference();
break;
case DW_AT_location:
// if (form_value.BlockData())
// {
// const DWARFDataExtractor& debug_info_data =
// debug_info();
// uint32_t block_length = form_value.Unsigned();
// DWARFDataExtractor location(debug_info_data,
// form_value.BlockData() - debug_info_data.GetDataStart(),
// block_length);
// }
// else
// {
// }
// break;
default:
break;
}
}
}
Type *type = parent_die.ResolveTypeUID(param_type_die_offset);
if (type)
{
function_param_types.push_back(type->GetForwardCompilerType());
}
}
arg_idx++;
}
break;
case DW_TAG_unspecified_parameters:
is_variadic = true;
break;
default:
break;
}
}
return arg_idx;
}
void
DWARFASTParserGo::ParseChildArrayInfo(const SymbolContext &sc, const DWARFDIE &parent_die, int64_t &first_index,
std::vector<uint64_t> &element_orders, uint32_t &byte_stride,
uint32_t &bit_stride)
{
if (!parent_die)
return;
for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling())
{
const dw_tag_t tag = die.Tag();
switch (tag)
{
case DW_TAG_subrange_type:
{
DWARFAttributes attributes;
const size_t num_child_attributes = die.GetAttributes(attributes);
if (num_child_attributes > 0)
{
uint64_t num_elements = 0;
uint32_t i;
for (i = 0; i < num_child_attributes; ++i)
{
const dw_attr_t attr = attributes.AttributeAtIndex(i);
DWARFFormValue form_value;
if (attributes.ExtractFormValueAtIndex(i, form_value))
{
switch (attr)
{
case DW_AT_count:
num_elements = form_value.Unsigned();
break;
default:
case DW_AT_type:
break;
}
}
}
element_orders.push_back(num_elements);
}
}
break;
}
}
}
bool
DWARFASTParserGo::CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, CompilerType &clang_type)
{
if (!die)
return false;
const dw_tag_t tag = die.Tag();
SymbolFileDWARF *dwarf = die.GetDWARF();
Log *log = nullptr; // (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION));
if (log)
dwarf->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace(
log, "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...", dwarf->MakeUserID(die.GetOffset()),
DW_TAG_value_to_name(tag), type->GetName().AsCString());
assert(clang_type);
DWARFAttributes attributes;
switch (tag)
{
case DW_TAG_structure_type:
{
{
if (die.HasChildren())
{
SymbolContext sc(die.GetLLDBCompileUnit());
ParseChildMembers(sc, die, clang_type);
}
}
m_ast.CompleteStructType(clang_type);
return (bool)clang_type;
}
default:
assert(false && "not a forward go type decl!");
break;
}
return false;
}
size_t
DWARFASTParserGo::ParseChildMembers(const SymbolContext &sc, const DWARFDIE &parent_die, CompilerType &class_clang_type)
{
size_t count = 0;
uint32_t member_idx = 0;
ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule();
GoASTContext *ast = llvm::dyn_cast_or_null<GoASTContext>(class_clang_type.GetTypeSystem());
if (ast == nullptr)
return 0;
for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling())
{
dw_tag_t tag = die.Tag();
switch (tag)
{
case DW_TAG_member:
{
DWARFAttributes attributes;
const size_t num_attributes = die.GetAttributes(attributes);
if (num_attributes > 0)
{
Declaration decl;
const char *name = NULL;
lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
uint32_t member_byte_offset = UINT32_MAX;
uint32_t i;
for (i = 0; i < num_attributes; ++i)
{
const dw_attr_t attr = attributes.AttributeAtIndex(i);
DWARFFormValue form_value;
if (attributes.ExtractFormValueAtIndex(i, form_value))
{
switch (attr)
{
case DW_AT_name:
name = form_value.AsCString();
break;
case DW_AT_type:
encoding_uid = form_value.Reference();
break;
case DW_AT_data_member_location:
if (form_value.BlockData())
{
Value initialValue(0);
Value memberOffset(0);
const DWARFDataExtractor &debug_info_data =
die.GetDWARF()->get_debug_info_data();
uint32_t block_length = form_value.Unsigned();
uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
if (DWARFExpression::Evaluate(NULL, // ExecutionContext *
NULL, // ClangExpressionVariableList *
NULL, // ClangExpressionDeclMap *
NULL, // RegisterContext *
module_sp, debug_info_data, die.GetCU(),
block_offset, block_length, eRegisterKindDWARF,
&initialValue, memberOffset, NULL))
{
member_byte_offset = memberOffset.ResolveValue(NULL).UInt();
}
}
else
{
// With DWARF 3 and later, if the value is an integer constant,
// this form value is the offset in bytes from the beginning
// of the containing entity.
member_byte_offset = form_value.Unsigned();
}
break;
default:
break;
}
}
}
Type *member_type = die.ResolveTypeUID(encoding_uid);
if (member_type)
{
CompilerType member_go_type = member_type->GetFullCompilerType();
ConstString name_const_str(name);
m_ast.AddFieldToStruct(class_clang_type, name_const_str, member_go_type, member_byte_offset);
}
}
++member_idx;
}
break;
default:
break;
}
}
return count;
}
Function *
DWARFASTParserGo::ParseFunctionFromDWARF(const SymbolContext &sc, const DWARFDIE &die)
{
DWARFRangeList func_ranges;
const char *name = NULL;
const char *mangled = NULL;
int decl_file = 0;
int decl_line = 0;
int decl_column = 0;
int call_file = 0;
int call_line = 0;
int call_column = 0;
DWARFExpression frame_base(die.GetCU());
assert(die.Tag() == DW_TAG_subprogram);
if (die.Tag() != DW_TAG_subprogram)
return NULL;
if (die.GetDIENamesAndRanges(name, mangled, func_ranges, decl_file, decl_line, decl_column, call_file, call_line,
call_column, &frame_base))
{
// Union of all ranges in the function DIE (if the function is discontiguous)
AddressRange func_range;
lldb::addr_t lowest_func_addr = func_ranges.GetMinRangeBase(0);
lldb::addr_t highest_func_addr = func_ranges.GetMaxRangeEnd(0);
if (lowest_func_addr != LLDB_INVALID_ADDRESS && lowest_func_addr <= highest_func_addr)
{
ModuleSP module_sp(die.GetModule());
func_range.GetBaseAddress().ResolveAddressUsingFileSections(lowest_func_addr, module_sp->GetSectionList());
if (func_range.GetBaseAddress().IsValid())
func_range.SetByteSize(highest_func_addr - lowest_func_addr);
}
if (func_range.GetBaseAddress().IsValid())
{
Mangled func_name;
func_name.SetValue(ConstString(name), false);
FunctionSP func_sp;
std::unique_ptr<Declaration> decl_ap;
if (decl_file != 0 || decl_line != 0 || decl_column != 0)
decl_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), decl_line,
decl_column));
SymbolFileDWARF *dwarf = die.GetDWARF();
// Supply the type _only_ if it has already been parsed
Type *func_type = dwarf->m_die_to_type.lookup(die.GetDIE());
assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED);
if (dwarf->FixupAddress(func_range.GetBaseAddress()))
{
const user_id_t func_user_id = dwarf->MakeUserID(die.GetOffset());
func_sp.reset(new Function(sc.comp_unit,
dwarf->MakeUserID(func_user_id), // UserID is the DIE offset
dwarf->MakeUserID(func_user_id), func_name, func_type,
func_range)); // first address range
if (func_sp.get() != NULL)
{
if (frame_base.IsValid())
func_sp->GetFrameBaseExpression() = frame_base;
sc.comp_unit->AddFunction(func_sp);
return func_sp.get();
}
}
}
}
return NULL;
}

View File

@ -0,0 +1,66 @@
//===-- DWARFASTParserGo.h -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef SymbolFileDWARF_DWARFASTParserGo_h_
#define SymbolFileDWARF_DWARFASTParserGo_h_
#include "DWARFDefines.h"
#include "DWARFASTParser.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Symbol/GoASTContext.h"
class DWARFDebugInfoEntry;
class DWARFDIECollection;
class DWARFASTParserGo : public DWARFASTParser
{
public:
DWARFASTParserGo(lldb_private::GoASTContext &ast);
virtual ~DWARFASTParserGo();
lldb::TypeSP ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, const DWARFDIE &die, lldb_private::Log *log,
bool *type_is_new_ptr) override;
virtual lldb_private::Function *ParseFunctionFromDWARF(const lldb_private::SymbolContext &sc,
const DWARFDIE &die) override;
virtual bool CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type,
lldb_private::CompilerType &go_type) override;
virtual lldb_private::CompilerDeclContext
GetDeclContextForUIDFromDWARF(const DWARFDIE &die) override
{
return lldb_private::CompilerDeclContext();
}
virtual lldb_private::CompilerDeclContext
GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) override
{
return lldb_private::CompilerDeclContext();
}
private:
size_t ParseChildParameters(const lldb_private::SymbolContext &sc, const DWARFDIE &parent_die, bool &is_variadic,
std::vector<lldb_private::CompilerType> &function_param_types);
void ParseChildArrayInfo(const lldb_private::SymbolContext &sc, const DWARFDIE &parent_die, int64_t &first_index,
std::vector<uint64_t> &element_orders, uint32_t &byte_stride, uint32_t &bit_stride);
size_t ParseChildMembers(const lldb_private::SymbolContext &sc, const DWARFDIE &die,
lldb_private::CompilerType &class_clang_type);
lldb_private::GoASTContext &m_ast;
};
#endif // SymbolFileDWARF_DWARFASTParserGo_h_

View File

@ -49,6 +49,7 @@
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/GoASTContext.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolVendor.h"
@ -507,10 +508,18 @@ TypeSystem *
SymbolFileDWARF::GetTypeSystemForLanguage (LanguageType language)
{
SymbolFileDWARFDebugMap * debug_map_symfile = GetDebugMapSymfile ();
TypeSystem *type_system;
if (debug_map_symfile)
return debug_map_symfile->GetTypeSystemForLanguage (language);
{
type_system = debug_map_symfile->GetTypeSystemForLanguage(language);
}
else
return m_obj_file->GetModule()->GetTypeSystemForLanguage (language);
{
type_system = m_obj_file->GetModule()->GetTypeSystemForLanguage(language);
if (type_system)
type_system->SetSymbolFile(this);
}
return type_system;
}
void

View File

@ -69,6 +69,7 @@ public:
friend class DebugMapModule;
friend class DWARFCompileUnit;
friend class DWARFASTParserClang;
friend class DWARFASTParserGo;
//------------------------------------------------------------------
// Static Functions

View File

@ -12,6 +12,7 @@ add_lldb_library(lldbSymbol
DWARFCallFrameInfo.cpp
Function.cpp
FuncUnwinders.cpp
GoASTContext.cpp
LineEntry.cpp
LineTable.cpp
ObjectFile.cpp

View File

@ -3021,7 +3021,7 @@ ClangASTContext::IsObjCClassType (const CompilerType& type)
bool
ClangASTContext::IsObjCObjectOrInterfaceType (const CompilerType& type)
{
if (type)
if (IsClangType(type))
return GetCanonicalQualType(type)->isObjCObjectOrInterfaceType();
return false;
}
@ -3269,12 +3269,14 @@ ClangASTContext::GetCXXClassName (const CompilerType& type, std::string &class_n
if (type)
{
clang::QualType qual_type (GetCanonicalQualType(type));
clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
if (cxx_record_decl)
if (!qual_type.isNull())
{
class_name.assign (cxx_record_decl->getIdentifier()->getNameStart());
return true;
clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
if (cxx_record_decl)
{
class_name.assign(cxx_record_decl->getIdentifier()->getNameStart());
return true;
}
}
}
class_name.clear();
@ -3289,7 +3291,7 @@ ClangASTContext::IsCXXClassType (const CompilerType& type)
return false;
clang::QualType qual_type (GetCanonicalQualType(type));
if (qual_type->getAsCXXRecordDecl() != nullptr)
if (!qual_type.isNull() && qual_type->getAsCXXRecordDecl() != nullptr)
return true;
return false;
}
@ -3313,8 +3315,8 @@ ClangASTContext::IsObjCObjectPointerType (const CompilerType& type, CompilerType
return false;
clang::QualType qual_type (GetCanonicalQualType(type));
if (qual_type->isObjCObjectPointerType())
if (!qual_type.isNull() && qual_type->isObjCObjectPointerType())
{
if (class_type_ptr)
{
@ -3750,7 +3752,7 @@ ClangASTContext::GetTypeQualifiers(void* type)
CompilerType
ClangASTContext::AddConstModifier (const CompilerType& type)
{
if (type && llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()))
if (IsClangType(type))
{
// Make sure this type is a clang AST type
clang::QualType result(GetQualType(type));
@ -3764,7 +3766,7 @@ ClangASTContext::AddConstModifier (const CompilerType& type)
CompilerType
ClangASTContext::AddRestrictModifier (const CompilerType& type)
{
if (type && llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()))
if (IsClangType(type))
{
clang::QualType result(GetQualType(type));
result.getQualifiers().setRestrict (true);
@ -3776,7 +3778,7 @@ ClangASTContext::AddRestrictModifier (const CompilerType& type)
CompilerType
ClangASTContext::AddVolatileModifier (const CompilerType& type)
{
if (type && llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()))
if (IsClangType(type))
{
clang::QualType result(GetQualType(type));
result.getQualifiers().setVolatile (true);
@ -4077,11 +4079,10 @@ ClangASTContext::GetMemberFunctionAtIndex (void* type, size_t idx)
CompilerType
ClangASTContext::GetLValueReferenceType (const CompilerType& type)
{
if (type)
if (IsClangType(type))
{
ClangASTContext *ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem());
if (ast)
return CompilerType(ast->getASTContext(), ast->getASTContext()->getLValueReferenceType(GetQualType(type)));
return CompilerType(ast->getASTContext(), ast->getASTContext()->getLValueReferenceType(GetQualType(type)));
}
return CompilerType();
}
@ -4089,11 +4090,10 @@ ClangASTContext::GetLValueReferenceType (const CompilerType& type)
CompilerType
ClangASTContext::GetRValueReferenceType (const CompilerType& type)
{
if (type)
if (IsClangType(type))
{
ClangASTContext *ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem());
if (ast)
return CompilerType(ast->getASTContext(), ast->getASTContext()->getRValueReferenceType(GetQualType(type)));
return CompilerType(ast->getASTContext(), ast->getASTContext()->getRValueReferenceType(GetQualType(type)));
}
return CompilerType();
}
@ -4186,7 +4186,7 @@ ClangASTContext::GetTypedefedType (void* type)
CompilerType
ClangASTContext::RemoveFastQualifiers (const CompilerType& type)
{
if (type && llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()))
if (IsClangType(type))
{
clang::QualType qual_type(GetQualType(type));
qual_type.getQualifiers().removeFastQualifiers();

File diff suppressed because it is too large Load Diff

View File

@ -93,7 +93,10 @@ SymbolFile::GetClangASTContext ()
TypeSystem *
SymbolFile::GetTypeSystemForLanguage (lldb::LanguageType language)
{
return m_obj_file->GetModule()->GetTypeSystemForLanguage (language);
TypeSystem *type_system = m_obj_file->GetModule()->GetTypeSystemForLanguage(language);
if (type_system)
type_system->SetSymbolFile(this);
return type_system;
}
uint32_t

View File

@ -0,0 +1,134 @@
"""Test the go DWARF type parsing."""
import os, time
import unittest2
import lldb
import lldbutil
from lldbtest import *
class TestGoASTContext(TestBase):
mydir = TestBase.compute_mydir(__file__)
@python_api_test
@skipUnlessGoInstalled
def test_with_dsym_and_python_api(self):
"""Test GoASTContext dwarf parsing."""
self.buildGo()
self.launchProcess()
self.go_builtin_types()
self.check_main_vars()
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Find the line numbers to break inside main().
self.main_source = "main.go"
self.break_line = line_number(self.main_source, '// Set breakpoint here.')
def check_builtin(self, name, size=0, typeclass=lldb.eTypeClassBuiltin):
tl = self.target().FindTypes(name)
self.assertEqual(1, len(tl))
t = list(tl)[0]
self.assertEqual(name, t.name)
self.assertEqual(typeclass, t.type)
if size > 0:
self.assertEqual(size, t.size)
def launchProcess(self):
exe = os.path.join(os.getcwd(), "a.out")
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
bpt = target.BreakpointCreateByLocation(self.main_source, self.break_line)
self.assertTrue(bpt, VALID_BREAKPOINT)
# Now launch the process, and do not stop at entry point.
process = target.LaunchSimple (None, None, self.get_process_working_directory())
self.assertTrue(process, PROCESS_IS_VALID)
# The stop reason of the thread should be breakpoint.
thread_list = lldbutil.get_threads_stopped_at_breakpoint (process, bpt)
# Make sure we stopped at the first breakpoint.
self.assertTrue (len(thread_list) != 0, "No thread stopped at our breakpoint.")
self.assertTrue (len(thread_list) == 1, "More than one thread stopped at our breakpoint.")
frame = thread_list[0].GetFrameAtIndex(0)
self.assertTrue (frame, "Got a valid frame 0 frame.")
def go_builtin_types(self):
address_size = self.target().GetAddressByteSize()
self.check_builtin('bool')
self.check_builtin('uint8', 1)
self.check_builtin('int8', 1)
self.check_builtin('uint16', 2)
self.check_builtin('int16', 2)
self.check_builtin('uint32', 4)
self.check_builtin('int32', 4)
self.check_builtin('uint64', 8)
self.check_builtin('int64', 8)
self.check_builtin('uintptr', address_size)
self.check_builtin('int', address_size)
self.check_builtin('uint', address_size)
self.check_builtin('float32', 4)
self.check_builtin('float64', 8)
self.check_builtin('complex64', 8, lldb.eTypeClassComplexFloat)
self.check_builtin('complex128', 16, lldb.eTypeClassComplexFloat)
def var(self, name):
var = self.frame().FindVariable(name)
self.assertTrue(var.IsValid(), "%s %s" % (VALID_VARIABLE, name))
return var
def check_main_vars(self):
v = self.var('theBool')
self.assertEqual('true', v.value)
v = self.var('theInt')
self.assertEqual('-7', v.value)
v = self.var('theComplex')
self.assertEqual('1 + 2i', v.value)
v = self.var('thePointer')
self.assertTrue(v.TypeIsPointerType())
self.assertEqual('-10', v.Dereference().value)
self.assertEqual(1, v.GetNumChildren())
self.assertEqual('-10', v.GetChildAtIndex(0).value)
# print
# print os.getpid()
# time.sleep(60)
v = self.var('theStruct')
if v.TypeIsPointerType():
v = v.Dereference()
self.assertEqual(2, v.GetNumChildren())
self.assertEqual('7', v.GetChildAtIndex(0).value)
self.assertEqual('7', v.GetChildMemberWithName('myInt').value)
self.assertEqual(v.load_addr, v.GetChildAtIndex(1).GetValueAsUnsigned())
self.assertEqual(v.load_addr, v.GetChildMemberWithName('myPointer').GetValueAsUnsigned())
# Test accessing struct fields through pointers.
v = v.GetChildMemberWithName('myPointer')
self.assertTrue(v.TypeIsPointerType())
self.assertEqual(2, v.GetNumChildren())
self.assertEqual('7', v.GetChildAtIndex(0).value)
c = v.GetChildMemberWithName('myPointer')
self.assertTrue(c.TypeIsPointerType())
self.assertEqual(2, c.GetNumChildren())
self.assertEqual('7', c.GetChildAtIndex(0).value)
v = self.var('theArray')
self.assertEqual(5, v.GetNumChildren())
for i in xrange(5):
self.assertEqual(str(i + 1), v.GetChildAtIndex(i).value)
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()

View File

@ -0,0 +1,47 @@
package main
import "fmt"
type Fooer interface {
Foo() int
}
type SomeFooer struct {
val int
}
func (s SomeFooer) Foo() int {
return s.val
}
type mystruct struct {
myInt int
myPointer *mystruct
}
func main() {
theBool := true
theInt := -7
theComplex := 1 + 2i
pointee := -10
thePointer := &pointee
theStruct := &mystruct { myInt: 7}
theStruct.myPointer = theStruct
theArray := [5]byte{1, 2, 3, 4, 5}
theSlice := theArray[1:2]
theString := "abc"
f := SomeFooer {9}
var theEface interface{} = f
var theFooer Fooer = f
theChan := make(chan int)
theMap := make(map[int]string)
theMap[1] = "1"
fmt.Println(theBool) // Set breakpoint here.
// Reference all the variables so the compiler is happy.
fmt.Println(theInt, theComplex, thePointer, theStruct.myInt)
fmt.Println(theArray[0], theSlice[0], theString)
fmt.Println(theEface, theFooer, theChan, theMap)
}

View File

@ -893,6 +893,21 @@ def skipUnlessDarwin(func):
"""Decorate the item to skip tests that should be skipped on any non Darwin platform."""
return skipUnlessPlatform(getDarwinOSTriples())(func)
def skipUnlessGoInstalled(func):
"""Decorate the item to skip tests when no Go compiler is available."""
if isinstance(func, type) and issubclass(func, unittest2.TestCase):
raise Exception("@skipIfGcc can only be used to decorate a test method")
@wraps(func)
def wrapper(*args, **kwargs):
from unittest2 import case
self = args[0]
compiler = self.getGoCompilerVersion()
if not compiler:
self.skipTest("skipping because go compiler not found")
else:
func(*args, **kwargs)
return wrapper
def getPlatform():
"""Returns the target platform which the tests are running on."""
platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2]
@ -1868,6 +1883,18 @@ class Base(unittest2.TestCase):
version = m.group(1)
return version
def getGoCompilerVersion(self):
""" Returns a string that represents the go compiler version, or None if go is not found.
"""
compiler = which("go")
if compiler:
version_output = system([[compiler, "version"]])[0]
for line in version_output.split(os.linesep):
m = re.search('go version (devel|go\\S+)', line)
if m:
return m.group(1)
return None
def platformIsDarwin(self):
"""Returns true if the OS triple for the selected platform is any valid apple OS"""
return platformIsDarwin()
@ -2053,6 +2080,11 @@ class Base(unittest2.TestCase):
if not module.buildDwarf(self, architecture, compiler, dictionary, clean):
raise Exception("Don't know how to build binary with dwarf")
def buildGo(self):
"""Build the default go binary.
"""
system([[which('go'), 'build -gcflags "-N -l" -o a.out main.go']])
def signBinary(self, binary_path):
if sys.platform.startswith("darwin"):
codesign_cmd = "codesign --force --sign lldb_codesign %s" % (binary_path)