Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -615,6 +615,10 @@ // so lets use it and cache the fact that we found // a complete type for this die dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + clang::DeclContext *defn_decl_ctx = GetCachedClangDeclContextForDIE( + dwarf->DebugInfo()->GetDIE(DIERef(type_sp->GetID()))); + if (defn_decl_ctx) + LinkDeclContextToDIE(defn_decl_ctx, die); return type_sp; } } @@ -1101,8 +1105,11 @@ Type *class_type = dwarf->ResolveType (decl_ctx_die); if (class_type) { + bool alternate_defn = false; if (class_type->GetID() != decl_ctx_die.GetID()) { + alternate_defn = true; + // We uniqued the parent class of this function to another class // so we now need to associate all dies under "decl_ctx_die" to // DIEs in the DIE for "class_type"... @@ -1193,13 +1200,8 @@ CompilerType class_opaque_type = class_type->GetForwardCompilerType (); if (ClangASTContext::IsCXXClassType(class_opaque_type)) { - if (class_opaque_type.IsBeingDefined ()) + if (class_opaque_type.IsBeingDefined () || alternate_defn) { - // Neither GCC 4.2 nor clang++ currently set a valid accessibility - // in the DWARF for C++ methods... Default to public for now... - if (accessibility == eAccessNone) - accessibility = eAccessPublic; - if (!is_static && !die.HasChildren()) { // We have a C++ member function with no children (this pointer!) @@ -1209,52 +1211,87 @@ } else { - clang::CXXMethodDecl *cxx_method_decl; - // REMOVE THE CRASH DESCRIPTION BELOW - Host::SetCrashDescriptionWithFormat ("SymbolFileDWARF::ParseType() is adding a method %s to class %s in DIE 0x%8.8" PRIx64 " from %s", - type_name_cstr, - class_type->GetName().GetCString(), - die.GetID(), - dwarf->GetObjectFile()->GetFileSpec().GetPath().c_str()); - - const bool is_attr_used = false; - - cxx_method_decl = m_ast.AddMethodToCXXRecordType (class_opaque_type.GetOpaqueQualType(), - type_name_cstr, - clang_type, - accessibility, - is_virtual, - is_static, - is_inline, - is_explicit, - is_attr_used, - is_artificial); - - type_handled = cxx_method_decl != NULL; - - if (type_handled) + bool add_method = true; + if (alternate_defn) { - LinkDeclContextToDIE(ClangASTContext::GetAsDeclContext(cxx_method_decl), die); - - Host::SetCrashDescription (NULL); - - - ClangASTMetadata metadata; - metadata.SetUserID(die.GetID()); - - if (!object_pointer_name.empty()) + // If an alternate definition for the class exists, then add the method only if an + // equivalent is not already present. + clang::CXXRecordDecl *record_decl = m_ast.GetAsCXXRecordDecl(class_opaque_type.GetOpaqueQualType()); + if (record_decl) { - metadata.SetObjectPtrName(object_pointer_name.c_str()); - if (log) - log->Printf ("Setting object pointer name: %s on method object %p.\n", - object_pointer_name.c_str(), - static_cast(cxx_method_decl)); + for (auto method_iter = record_decl->method_begin(); + method_iter != record_decl->method_end(); + method_iter++) + { + clang::CXXMethodDecl *method_decl = *method_iter; + if (method_decl->getNameInfo().getAsString() == std::string(type_name_cstr)) + { + if (method_decl->getType() == ClangASTContext::GetQualType(clang_type)) + { + add_method = false; + LinkDeclContextToDIE(ClangASTContext::GetAsDeclContext(method_decl), die); + type_handled = true; + + break; + } + } + } } - m_ast.SetMetadata (cxx_method_decl, metadata); } - else + + if (add_method) { - ignore_containing_context = true; + // REMOVE THE CRASH DESCRIPTION BELOW + Host::SetCrashDescriptionWithFormat ("SymbolFileDWARF::ParseType() is adding a method %s to class %s in DIE 0x%8.8" PRIx64 " from %s", + type_name_cstr, + class_type->GetName().GetCString(), + die.GetID(), + dwarf->GetObjectFile()->GetFileSpec().GetPath().c_str()); + + const bool is_attr_used = false; + // Neither GCC 4.2 nor clang++ currently set a valid accessibility + // in the DWARF for C++ methods... Default to public for now... + if (accessibility == eAccessNone) + accessibility = eAccessPublic; + + clang::CXXMethodDecl *cxx_method_decl; + cxx_method_decl = m_ast.AddMethodToCXXRecordType (class_opaque_type.GetOpaqueQualType(), + type_name_cstr, + clang_type, + accessibility, + is_virtual, + is_static, + is_inline, + is_explicit, + is_attr_used, + is_artificial); + + type_handled = cxx_method_decl != NULL; + + if (type_handled) + { + LinkDeclContextToDIE(ClangASTContext::GetAsDeclContext(cxx_method_decl), die); + + Host::SetCrashDescription (NULL); + + + ClangASTMetadata metadata; + metadata.SetUserID(die.GetID()); + + if (!object_pointer_name.empty()) + { + metadata.SetObjectPtrName(object_pointer_name.c_str()); + if (log) + log->Printf ("Setting object pointer name: %s on method object %p.\n", + object_pointer_name.c_str(), + static_cast(cxx_method_decl)); + } + m_ast.SetMetadata (cxx_method_decl, metadata); + } + else + { + ignore_containing_context = true; + } } } } Index: test/lang/cpp/pr24916/Makefile =================================================================== --- /dev/null +++ test/lang/cpp/pr24916/Makefile @@ -0,0 +1,7 @@ +LEVEL = ../../../make + +CXX_SOURCES = main.cpp derived.cpp base.cpp + +CFLAGS_EXTRAS += $(LIMIT_DEBUG_INFO_FLAGS) + +include $(LEVEL)/Makefile.rules Index: test/lang/cpp/pr24916/TestWithLimitDebugInfo.py =================================================================== --- /dev/null +++ test/lang/cpp/pr24916/TestWithLimitDebugInfo.py @@ -0,0 +1,48 @@ +import lldb +from lldbtest import * +import lldbutil + +class TestWithLimitDebugInfo(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @dwarf_test + def test_with_dwarf(self): + self.buildDwarf() + + cwd = os.getcwd() + + src_file = os.path.join(cwd, "main.cpp") + src_file_spec = lldb.SBFileSpec(src_file) + self.assertTrue(src_file_spec.IsValid(), "breakpoint file") + + # Get the path of the executable + exe_path = os.path.join(cwd, 'a.out') + + # Load the executable + target = self.dbg.CreateTarget(exe_path) + self.assertTrue(target.IsValid(), VALID_TARGET) + + # Break on main function + breakpoint = target.BreakpointCreateBySourceRegex("break here", src_file_spec) + self.assertTrue(breakpoint.IsValid() and breakpoint.GetNumLocations() >= 1, VALID_BREAKPOINT) + + # Launch the process + process = target.LaunchSimple(None, None, self.get_process_working_directory()) + self.assertTrue(process.IsValid(), PROCESS_IS_VALID) + + # Get the thread of the process + self.assertTrue(process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) + thread.StepInto() + + # Get frame for current thread + frame = thread.GetSelectedFrame() + + v1 = frame.EvaluateExpression("1") + self.assertTrue(v1.IsValid(), "'expr 1' results in a valid SBValue object") + self.assertTrue(v1.GetError().Success(), "'expr 1' succeeds without an error.") + + v2 = frame.EvaluateExpression("this") + self.assertTrue(v2.IsValid(), "'expr this' results in a valid SBValue object") + self.assertTrue(v2.GetError().Success(), "'expr this' succeeds without an error.") Index: test/lang/cpp/pr24916/base.h =================================================================== --- /dev/null +++ test/lang/cpp/pr24916/base.h @@ -0,0 +1,10 @@ +class FooNS +{ +public: + virtual void bar(); + virtual char baz() = 0; + +protected: + int x; +}; + Index: test/lang/cpp/pr24916/base.cpp =================================================================== --- /dev/null +++ test/lang/cpp/pr24916/base.cpp @@ -0,0 +1,6 @@ +#include "base.h" + +void FooNS::bar() { + x = 54321; +} + Index: test/lang/cpp/pr24916/derived.h =================================================================== --- /dev/null +++ test/lang/cpp/pr24916/derived.h @@ -0,0 +1,13 @@ +#include "base.h" + +class Foo : public FooNS +{ +public: + Foo() { + a = 12345; + } + + char baz() override; + int a; +}; + Index: test/lang/cpp/pr24916/derived.cpp =================================================================== --- /dev/null +++ test/lang/cpp/pr24916/derived.cpp @@ -0,0 +1,6 @@ +#include "derived.h" + +char Foo::baz() { + return (char)(x&0xff); +} + Index: test/lang/cpp/pr24916/main.cpp =================================================================== --- /dev/null +++ test/lang/cpp/pr24916/main.cpp @@ -0,0 +1,7 @@ +#include "derived.h" + +int main() { + Foo f; // break here + f.bar(); + return f.baz(); +} Index: test/make/Makefile.rules =================================================================== --- test/make/Makefile.rules +++ test/make/Makefile.rules @@ -170,6 +170,11 @@ endif endif +LIMIT_DEBUG_INFO_FLAGS = +ifneq (,$(findstring clang,$(CC))) + LIMIT_DEBUG_INFO_FLAGS += -flimit-debug-info +endif + CFLAGS ?= -g -O0 -fno-builtin ifeq "$(OS)" "Darwin" CFLAGS += $(ARCHFLAG) $(ARCH) $(FRAMEWORK_INCLUDES) $(CFLAGS_EXTRAS) -I$(LLDB_BASE_DIR)include