summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Symbol/ClangASTImporter.h7
-rw-r--r--lldb/source/Expression/ClangASTSource.cpp120
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp35
-rw-r--r--lldb/source/Symbol/ClangASTImporter.cpp42
-rw-r--r--lldb/test/lang/c/shared_lib/Makefile7
-rw-r--r--lldb/test/lang/c/shared_lib/TestSharedLib.py79
-rw-r--r--lldb/test/lang/c/shared_lib/foo.c22
-rw-r--r--lldb/test/lang/c/shared_lib/foo.h12
-rw-r--r--lldb/test/lang/c/shared_lib/main.c13
9 files changed, 304 insertions, 33 deletions
diff --git a/lldb/include/lldb/Symbol/ClangASTImporter.h b/lldb/include/lldb/Symbol/ClangASTImporter.h
index a50c44b6712..330b4520bda 100644
--- a/lldb/include/lldb/Symbol/ClangASTImporter.h
+++ b/lldb/include/lldb/Symbol/ClangASTImporter.h
@@ -53,10 +53,13 @@ public:
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
diff --git a/lldb/source/Expression/ClangASTSource.cpp b/lldb/source/Expression/ClangASTSource.cpp
index 552c54575a7..9831070c9be 100644
--- a/lldb/source/Expression/ClangASTSource.cpp
+++ b/lldb/source/Expression/ClangASTSource.cpp
@@ -149,15 +149,127 @@ ClangASTSource::CompleteType (TagDecl *tag_decl)
{
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 @@ ClangASTSource::FindExternalLexicalDecls (const DeclContext *decl_context,
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;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 196bec836aa..e0abf9a0f44 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -4548,22 +4548,25 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
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);
+ }
}
}
diff --git a/lldb/source/Symbol/ClangASTImporter.cpp b/lldb/source/Symbol/ClangASTImporter.cpp
index eb65c9d03ee..3bbd9c6af35 100644
--- a/lldb/source/Symbol/ClangASTImporter.cpp
+++ b/lldb/source/Symbol/ClangASTImporter.cpp
@@ -95,28 +95,48 @@ ClangASTImporter::DeportDecl (clang::ASTContext *dst_ctx,
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 @@ ClangASTImporter::CompleteObjCInterfaceDecl (clang::ObjCInterfaceDecl *interface
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
diff --git a/lldb/test/lang/c/shared_lib/Makefile b/lldb/test/lang/c/shared_lib/Makefile
new file mode 100644
index 00000000000..9d9972acd57
--- /dev/null
+++ b/lldb/test/lang/c/shared_lib/Makefile
@@ -0,0 +1,7 @@
+LEVEL = ../../../make
+
+DYLIB_NAME := libfoo
+DYLIB_C_SOURCES := foo.c
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/test/lang/c/shared_lib/TestSharedLib.py b/lldb/test/lang/c/shared_lib/TestSharedLib.py
new file mode 100644
index 00000000000..f0dbbb76dc4
--- /dev/null
+++ b/lldb/test/lang/c/shared_lib/TestSharedLib.py
@@ -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()
diff --git a/lldb/test/lang/c/shared_lib/foo.c b/lldb/test/lang/c/shared_lib/foo.c
new file mode 100644
index 00000000000..6431bc496c3
--- /dev/null
+++ b/lldb/test/lang/c/shared_lib/foo.c
@@ -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);
+}
diff --git a/lldb/test/lang/c/shared_lib/foo.h b/lldb/test/lang/c/shared_lib/foo.h
new file mode 100644
index 00000000000..78b3c124538
--- /dev/null
+++ b/lldb/test/lang/c/shared_lib/foo.h
@@ -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);
+
+
diff --git a/lldb/test/lang/c/shared_lib/main.c b/lldb/test/lang/c/shared_lib/main.c
new file mode 100644
index 00000000000..dc4dc3189cc
--- /dev/null
+++ b/lldb/test/lang/c/shared_lib/main.c
@@ -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;
+}
OpenPOWER on IntegriCloud