[Lldb-commits] [lldb] r146204 - in /lldb/trunk: include/lldb/Symbol/ClangASTImporter.h source/Expression/ClangASTSource.cpp source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp source/Symbol/ClangASTImporter.cpp test/lang/c/shared_lib/ test/lang/c/shared_lib/Makefile test/lang/c/shared_lib/TestSharedLib.py test/lang/c/shared_lib/foo.c test/lang/c/shared_lib/foo.h test/lang/c/shared_lib/main.c

Sean Callanan scallanan at apple.com
Thu Dec 8 15:45:45 PST 2011


Author: spyffe
Date: Thu Dec  8 17:45:45 2011
New Revision: 146204

URL: http://llvm.org/viewvc/llvm-project?rev=146204&view=rev
Log:
If the expression parser is unable to complete a TagDecl
in the context in which it was originally found, the
expression parser now goes hunting for it in all modules
(in the appropriate namespace, if applicable).  This means
that forward-declared types that exist in another shared
library will now be resolved correctly.

Added a test case to cover this.  The test case also tests
"frame variable," which does not have this functionality
yet.

Added:
    lldb/trunk/test/lang/c/shared_lib/
    lldb/trunk/test/lang/c/shared_lib/Makefile
    lldb/trunk/test/lang/c/shared_lib/TestSharedLib.py
    lldb/trunk/test/lang/c/shared_lib/foo.c
    lldb/trunk/test/lang/c/shared_lib/foo.h
    lldb/trunk/test/lang/c/shared_lib/main.c
Modified:
    lldb/trunk/include/lldb/Symbol/ClangASTImporter.h
    lldb/trunk/source/Expression/ClangASTSource.cpp
    lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
    lldb/trunk/source/Symbol/ClangASTImporter.cpp

Modified: lldb/trunk/include/lldb/Symbol/ClangASTImporter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/ClangASTImporter.h?rev=146204&r1=146203&r2=146204&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/ClangASTImporter.h (original)
+++ lldb/trunk/include/lldb/Symbol/ClangASTImporter.h Thu Dec  8 17:45:45 2011
@@ -53,10 +53,13 @@
                 clang::ASTContext *src_ctx,
                 clang::Decl *decl);
         
-    void
+    bool
     CompleteTagDecl (clang::TagDecl *decl);
     
-    void
+    bool
+    CompleteTagDeclWithOrigin (clang::TagDecl *decl, clang::TagDecl *origin);
+    
+    bool
     CompleteObjCInterfaceDecl (clang::ObjCInterfaceDecl *interface_decl);
     
     bool

Modified: lldb/trunk/source/Expression/ClangASTSource.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangASTSource.cpp?rev=146204&r1=146203&r2=146204&view=diff
==============================================================================
--- lldb/trunk/source/Expression/ClangASTSource.cpp (original)
+++ lldb/trunk/source/Expression/ClangASTSource.cpp Thu Dec  8 17:45:45 2011
@@ -149,15 +149,127 @@
 {    
     lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
     
+    static unsigned int invocation_id = 0;
+    unsigned int current_id = invocation_id++;
+    
     if (log)
     {
-        log->Printf("    [CompleteTagDecl] on (ASTContext*)%p Completing a TagDecl named %s", m_ast_context, tag_decl->getName().str().c_str());
-        log->Printf("      [CTD] Before:");
+        log->Printf("    CompleteTagDecl[%u] on (ASTContext*)%p Completing a TagDecl named %s", 
+                    invocation_id, 
+                    m_ast_context, 
+                    tag_decl->getName().str().c_str());
+        
+        log->Printf("      CTD[%u] Before:", current_id);
         ASTDumper dumper((Decl*)tag_decl);
         dumper.ToLog(log, "      [CTD] ");
     }
     
-    m_ast_importer->CompleteTagDecl (tag_decl);
+    if (!m_ast_importer->CompleteTagDecl (tag_decl))
+    {
+        // We couldn't complete the type.  Maybe there's a definition
+        // somewhere else that can be completed.
+        
+        if (log)
+            log->Printf("      CTD[%u] Type could not be completed in the module in which it was first found.", current_id);
+        
+        bool found = false;
+
+        DeclContext *decl_ctx = tag_decl->getDeclContext();
+                
+        if (const NamespaceDecl *namespace_context = dyn_cast<NamespaceDecl>(decl_ctx))
+        {
+            ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer->GetNamespaceMap(namespace_context);
+            
+            if (log && log->GetVerbose())
+                log->Printf("      CTD[%u] Inspecting namespace map %p (%d entries)", 
+                            current_id, 
+                            namespace_map.get(), 
+                            (int)namespace_map->size());
+            
+            if (!namespace_map)
+                return;
+            
+            for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end();
+                 i != e && !found;
+                 ++i)
+            {
+                if (log)
+                    log->Printf("      CTD[%u] Searching namespace %s in module %s",
+                                current_id,
+                                i->second.GetNamespaceDecl()->getNameAsString().c_str(),
+                                i->first->GetFileSpec().GetFilename().GetCString());
+                
+                TypeList types;
+                
+                SymbolContext null_sc;
+                ConstString name(tag_decl->getName().str().c_str());
+                
+                i->first->FindTypes(null_sc, name, &i->second, true, UINT32_MAX, types);
+                
+                for (uint32_t ti = 0, te = types.GetSize();
+                     ti != te && !found;
+                     ++ti)
+                {
+                    lldb::TypeSP type = types.GetTypeAtIndex(ti);
+                    
+                    if (!type)
+                        continue;
+                    
+                    lldb::clang_type_t opaque_type = type->GetClangFullType();
+                    
+                    if (!opaque_type)
+                        continue;
+                    
+                    const TagType *tag_type = dyn_cast<TagType>(QualType::getFromOpaquePtr(opaque_type).getTypePtr());
+                    
+                    if (!tag_type)
+                        continue;
+                    
+                    TagDecl *candidate_tag_decl = const_cast<TagDecl*>(tag_type->getDecl());
+                    
+                    if (m_ast_importer->CompleteTagDeclWithOrigin (tag_decl, candidate_tag_decl))
+                        found = true;
+                }
+            }
+        }
+        else 
+        {
+            TypeList types;
+            
+            SymbolContext null_sc;
+            ConstString name(tag_decl->getName().str().c_str());
+            ClangNamespaceDecl namespace_decl;
+            
+            ModuleList &module_list = m_target->GetImages();
+
+            module_list.FindTypes(null_sc, name, true, UINT32_MAX, types);
+            
+            for (uint32_t ti = 0, te = types.GetSize();
+                 ti != te && !found;
+                 ++ti)
+            {
+                lldb::TypeSP type = types.GetTypeAtIndex(ti);
+                
+                if (!type)
+                    continue;
+                
+                lldb::clang_type_t opaque_type = type->GetClangFullType();
+                
+                if (!opaque_type)
+                    continue;
+                
+                const TagType *tag_type = dyn_cast<TagType>(QualType::getFromOpaquePtr(opaque_type).getTypePtr());
+                
+                if (!tag_type)
+                    continue;
+                
+                TagDecl *candidate_tag_decl = const_cast<TagDecl*>(tag_type->getDecl());
+                
+                if (m_ast_importer->CompleteTagDeclWithOrigin (tag_decl, candidate_tag_decl))
+                    found = true;
+            }
+        }
+    }
     
     if (log)
     {
@@ -249,7 +361,7 @@
             external_source->CompleteType (original_tag_decl);
     }
     
-    DeclContext *original_decl_context = dyn_cast<DeclContext>(original_decl);
+    const DeclContext *original_decl_context = dyn_cast<DeclContext>(original_decl);
     
     if (!original_decl_context)
         return ELR_Failure;

Modified: lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp?rev=146204&r1=146203&r2=146204&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp (original)
+++ lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp Thu Dec  8 17:45:45 2011
@@ -4548,22 +4548,25 @@
                     GetUniqueDWARFASTTypeMap().Insert (type_name_const_str, 
                                                        unique_ast_entry);
                     
-                    if (die->HasChildren() == false && is_forward_declaration == false)
-                    {
-                        // No children for this struct/union/class, lets finish it
-                        ast.StartTagDeclarationDefinition (clang_type);
-                        ast.CompleteTagDeclarationDefinition (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::ResolveClangOpaqueTypeDefinition(Type *)"
-                        // When the definition needs to be defined.
-                        m_forward_decl_die_to_clang_type[die] = clang_type;
-                        m_forward_decl_clang_type_to_die[ClangASTType::RemoveFastQualifiers (clang_type)] = die;
-                        ClangASTContext::SetHasExternalStorage (clang_type, true);
+                    if (!is_forward_declaration)
+                    {                    
+                        if (die->HasChildren() == false)
+                        {
+                            // No children for this struct/union/class, lets finish it
+                            ast.StartTagDeclarationDefinition (clang_type);
+                            ast.CompleteTagDeclarationDefinition (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::ResolveClangOpaqueTypeDefinition(Type *)"
+                            // When the definition needs to be defined.
+                            m_forward_decl_die_to_clang_type[die] = clang_type;
+                            m_forward_decl_clang_type_to_die[ClangASTType::RemoveFastQualifiers (clang_type)] = die;
+                            ClangASTContext::SetHasExternalStorage (clang_type, true);
+                        }
                     }
                     
                 }

Modified: lldb/trunk/source/Symbol/ClangASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangASTImporter.cpp?rev=146204&r1=146203&r2=146204&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/ClangASTImporter.cpp (original)
+++ lldb/trunk/source/Symbol/ClangASTImporter.cpp Thu Dec  8 17:45:45 2011
@@ -95,28 +95,48 @@
     return result;
 }
 
-void
+bool
 ClangASTImporter::CompleteTagDecl (clang::TagDecl *decl)
-{
-    lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-    
+{   
     DeclOrigin decl_origin = GetDeclOrigin(decl);
     
     if (!decl_origin.Valid())
-        return;
+        return false;
     
     if (!ClangASTContext::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
-        return;
+        return false;
     
     MinionSP minion_sp (GetMinion(&decl->getASTContext(), decl_origin.ctx));
     
     if (minion_sp)
         minion_sp->ImportDefinition(decl_origin.decl);
     
-    return;
+    return true;
 }
 
-void
+bool
+ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin_decl)
+{
+    clang::ASTContext *origin_ast_ctx = &origin_decl->getASTContext();
+        
+    if (!ClangASTContext::GetCompleteDecl(origin_ast_ctx, origin_decl))
+        return false;
+    
+    MinionSP minion_sp (GetMinion(&decl->getASTContext(), origin_ast_ctx));
+    
+    if (minion_sp)
+        minion_sp->ImportDefinition(origin_decl);
+    
+    ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+    OriginMap &origins = context_md->m_origins;
+
+    origins[decl] = DeclOrigin(origin_ast_ctx, origin_decl);
+    
+    return true;
+}
+
+bool
 ClangASTImporter::CompleteObjCInterfaceDecl (clang::ObjCInterfaceDecl *interface_decl)
 {
     lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@@ -124,17 +144,17 @@
     DeclOrigin decl_origin = GetDeclOrigin(interface_decl);
     
     if (!decl_origin.Valid())
-        return;
+        return false;
     
     if (!ClangASTContext::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
-        return;
+        return false;
     
     MinionSP minion_sp (GetMinion(&interface_decl->getASTContext(), decl_origin.ctx));
     
     if (minion_sp)
         minion_sp->ImportDefinition(decl_origin.decl);
     
-    return;
+    return true;
 }
 
 ClangASTImporter::DeclOrigin

Added: lldb/trunk/test/lang/c/shared_lib/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/c/shared_lib/Makefile?rev=146204&view=auto
==============================================================================
--- lldb/trunk/test/lang/c/shared_lib/Makefile (added)
+++ lldb/trunk/test/lang/c/shared_lib/Makefile Thu Dec  8 17:45:45 2011
@@ -0,0 +1,7 @@
+LEVEL = ../../../make
+
+DYLIB_NAME := libfoo
+DYLIB_C_SOURCES := foo.c
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/lang/c/shared_lib/TestSharedLib.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/c/shared_lib/TestSharedLib.py?rev=146204&view=auto
==============================================================================
--- lldb/trunk/test/lang/c/shared_lib/TestSharedLib.py (added)
+++ lldb/trunk/test/lang/c/shared_lib/TestSharedLib.py Thu Dec  8 17:45:45 2011
@@ -0,0 +1,79 @@
+"""Test that types defined in shared libraries work correctly."""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+
+class SharedLibTestCase(TestBase):
+
+    mydir = os.path.join("lang", "c", "shared_lib")
+
+    def test_expr_with_dsym(self):
+        """Test that types work when defined in a shared library and forward-declared in the main executable"""
+        self.buildDsym()
+        self.expr()
+
+    def test_expr_with_dwarf(self):
+        """Test that types work when defined in a shared library and forward-declared in the main executable"""
+        self.buildDwarf()
+        self.expr()
+
+    def test_frame_variable_with_dsym(self):
+        """Test that types work when defined in a shared library and forward-declared in the main executable"""
+        self.buildDsym()
+        self.frame_var()
+
+    def test_frame_variable_with_dwarf(self):
+        """Test that types work when defined in a shared library and forward-declared in the main executable"""
+        self.buildDwarf()
+        self.frame_var()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line number to break inside main().
+        self.line = line_number('main.c', '// Set breakpoint 0 here.')
+
+    def common_setup(self):
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        # Break inside the foo function which takes a bar_ptr argument.
+        self.expect("breakpoint set -f main.c -l %d" % self.line, BREAKPOINT_CREATED,
+            startstr = "Breakpoint created")
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # The stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped',
+                       'stop reason = breakpoint'])
+
+        # The breakpoint should have a hit count of 1.
+        self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
+            substrs = [' resolved, hit count = 1'])
+
+    def expr(self):
+        """Test that types work when defined in a shared library and forward-declared in the main executable"""
+	self.common_setup()
+
+        # This should display correctly.
+        self.expect("expression *my_foo_ptr", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = ["(foo)", "(sub_foo)", "other_element = 3"])
+
+    @unittest2.expectedFailure
+    # rdar://problem/10381325
+    def frame_var(self):
+        """Test that types work when defined in a shared library and forward-declared in the main executable"""
+	self.common_setup()
+
+        # This should display correctly.
+        self.expect("frame variable *my_foo_ptr", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = ["(foo)", "(sub_foo)", "other_element = 3"])
+                       
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/lang/c/shared_lib/foo.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/c/shared_lib/foo.c?rev=146204&view=auto
==============================================================================
--- lldb/trunk/test/lang/c/shared_lib/foo.c (added)
+++ lldb/trunk/test/lang/c/shared_lib/foo.c Thu Dec  8 17:45:45 2011
@@ -0,0 +1,22 @@
+#include "foo.h"
+#include <stdlib.h>
+
+struct foo
+{
+  struct sub_foo sub_element;
+  int    other_element;
+};
+
+struct foo *
+GetMeAFoo()
+{
+  struct foo *ret_val = (struct foo *) malloc (sizeof (struct foo));
+  ret_val->other_element = 3;
+  return ret_val;
+}
+
+struct sub_foo *
+GetMeASubFoo (struct foo *in_foo)
+{
+  return &(in_foo->sub_element);
+}

Added: lldb/trunk/test/lang/c/shared_lib/foo.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/c/shared_lib/foo.h?rev=146204&view=auto
==============================================================================
--- lldb/trunk/test/lang/c/shared_lib/foo.h (added)
+++ lldb/trunk/test/lang/c/shared_lib/foo.h Thu Dec  8 17:45:45 2011
@@ -0,0 +1,12 @@
+struct foo;
+
+struct sub_foo
+{
+  int sub_1;
+  char *sub_2;
+};
+
+struct foo *GetMeAFoo();
+struct sub_foo *GetMeASubFoo (struct foo *in_foo);
+
+

Added: lldb/trunk/test/lang/c/shared_lib/main.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/c/shared_lib/main.c?rev=146204&view=auto
==============================================================================
--- lldb/trunk/test/lang/c/shared_lib/main.c (added)
+++ lldb/trunk/test/lang/c/shared_lib/main.c Thu Dec  8 17:45:45 2011
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include "foo.h"
+
+int 
+main ()
+{
+  struct foo *my_foo_ptr;
+  my_foo_ptr = GetMeAFoo();
+  // Set breakpoint 0 here.
+  printf ("My sub foo has: %d.\n", GetMeASubFoo(my_foo_ptr)->sub_1);
+
+  return 0;
+}





More information about the lldb-commits mailing list