> On Sep 2, 2015, at 3:15 PM, Ryan Brown via lldb-dev <lldb-dev@lists.llvm.org> 
> wrote:
> 
> I'm trying to implement a DWARFASTParser for go, and have hit an issue with 
> fields for structs.
> As I understand it, DWARFASTParserClang loads minimal type info for structs 
> at first, and registers the type in SymbolFileDWARF's 
> m_forward_decl_clang_type_to_die. 
> Then later when you call type.GetFullCompilerType() it calls back into the 
> DWARFASTParser to complete the type.
> 
> But it seems like the SBValue's in the python API only get Forward types, and 
> never complete them. For example, I do:
> var = frame.FindVariable('theStruct')
> self.assertEqual(2, var.GetNumChildren())
> 
> But I get 0 children, because the type is incomplete and there doesn't seem 
> to be any way to complete it.
> ValueObject::GetNumChildren goes through 
> ValueObject::MaybeCalculateCompleteType, which seems promising. But it only 
> completes the type for objc. 
> Would a clang variable already have a full type at this point for some 
> reason? If so, how do I arrange that for go?
> 
> Also, TypeSystem has a GetCompleteType method. I don't understand when this 
> would be called or how I can implement it without a reference to 
> SymbolFileDWARF.

The story goes:

lldb_private::ClangASTContext inherits from lldb_private::TypeSystem so it is 
the type system. The ClangASTContext also signs up to be a 
clang::ExternalASTSource so that it can complete types via:

ClangASTContext::CompleteTagDecl()
ClangASTContext::CompleteObjCInterfaceDecl()

ClangASTContext::CompleteTagDecl() completes C and C++ structs, unions and 
classes.

ClangASTContext::CompleteObjCInterfaceDecl() completes Objective C stuff.

The function that actually figures out how many children will be routed through 
"CompilerType::GetNumChildren(bool)" with code like this:

size_t
ValueObjectVariable::CalculateNumChildren()
{    
    CompilerType type(GetCompilerType());
    
    if (!type.IsValid())
        return 0;
    
    const bool omit_empty_base_classes = true;
    return type.GetNumChildren(omit_empty_base_classes);
}


CompilerType passes the ball back to the TypeSystem class (ClangASTContext in 
this case):

uint32_t
CompilerType::GetNumChildren (bool omit_empty_base_classes) const
{
    if (!IsValid())
        return 0;
    return m_type_system->GetNumChildren(m_type, omit_empty_base_classes);
}


Down in ClangASTContext it does:


uint32_t
ClangASTContext::GetNumChildren (void* type, bool omit_empty_base_classes)
{
    if (!type)
        return 0;
    
    uint32_t num_children = 0;
    clang::QualType qual_type(GetQualType(type));
    const clang::Type::TypeClass type_class = qual_type->getTypeClass();
    switch (type_class)
    {
        ...
        case clang::Type::Record:
            if (GetCompleteQualType (getASTContext(), qual_type))
            {




So it is a static function named GetCompleteQualType() in ClangASTContext.cpp 
that completes the type if it needs to:


static bool
GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type, bool 
allow_completion = true)
{
    const clang::Type::TypeClass type_class = qual_type->getTypeClass();
    switch (type_class)
    {
        ...
        case clang::Type::Record:
        case clang::Type::Enum:
        {
            const clang::TagType *tag_type = 
llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
            if (tag_type)
            {
                clang::TagDecl *tag_decl = tag_type->getDecl();
                if (tag_decl)
                {
                    if (tag_decl->isCompleteDefinition())
                        return true;
                    
                    if (!allow_completion)
                        return false;
                    
                    if (tag_decl->hasExternalLexicalStorage())
                    {
                        if (ast)
                        {
                            clang::ExternalASTSource *external_ast_source = 
ast->getExternalSource();
                            if (external_ast_source)
                            {
                                external_ast_source->CompleteType(tag_decl);



So it will ask the clang::ExternalASTSource to complete the type which should 
call ClangASTContext::CompleteTagDecl() to complete your type.

So this is how it would work if you used DWARFASTParserClang. Are you using 
that? Or are you using your own DWARFASTParserGo? If so, then you need to 
implement this type completion in your own TypeSystem. Your type system 
subclass is required to implement many different function for type 
introspection, one of which is:

class TypeSystem {
 
   virtual uint32_t
    GetNumChildren (void *type, bool omit_empty_base_classes) = 0;

};

So the clang version in ClangASTContext::GetNumChildren() knows to complete the 
type if it a forward declaration. If you have a GoASTContext class that 
inherits from TypeSystem, then all function that might need to know about the 
contents of a class or struct, will need to know to complete the type. Or, you 
can fully parse the structs/unions/classes as you parse the DWARF and not worry 
about implementing lazy type completion for Go.

So the main questions I have for you are:
- Do you have a GoASTContext that inherits from TypeSystem?
- If you do, in order for DWARF to parse Go types that use the GoASTContext, 
you will need to write a DWARFASTParser subclass that constructs Go types from 
DWARF. Then your TypeSystem subclass will need to implement:

TypeSystem {

    virtual DWARFASTParser *
    GetDWARFParser ();

};


_______________________________________________
lldb-dev mailing list
lldb-dev@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev

Reply via email to