diff options
-rw-r--r-- | lldb/include/lldb/Symbol/ClangASTImporter.h | 7 | ||||
-rw-r--r-- | lldb/source/Expression/ClangASTSource.cpp | 120 | ||||
-rw-r--r-- | lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 35 | ||||
-rw-r--r-- | lldb/source/Symbol/ClangASTImporter.cpp | 42 | ||||
-rw-r--r-- | lldb/test/lang/c/shared_lib/Makefile | 7 | ||||
-rw-r--r-- | lldb/test/lang/c/shared_lib/TestSharedLib.py | 79 | ||||
-rw-r--r-- | lldb/test/lang/c/shared_lib/foo.c | 22 | ||||
-rw-r--r-- | lldb/test/lang/c/shared_lib/foo.h | 12 | ||||
-rw-r--r-- | lldb/test/lang/c/shared_lib/main.c | 13 |
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; +} |