[Lldb-commits] [lldb] r213433 - LLDB now correctly handles virtual inheritance.
Greg Clayton
gclayton at apple.com
Fri Jul 18 17:12:58 PDT 2014
Author: gclayton
Date: Fri Jul 18 19:12:57 2014
New Revision: 213433
URL: http://llvm.org/viewvc/llvm-project?rev=213433&view=rev
Log:
LLDB now correctly handles virtual inheritance.
Test case added as well.
<rdar://problem/16785904>
Added:
lldb/trunk/test/lang/cpp/diamond/
lldb/trunk/test/lang/cpp/diamond/Makefile
lldb/trunk/test/lang/cpp/diamond/TestDiamond.py
lldb/trunk/test/lang/cpp/diamond/main.cpp
Modified:
lldb/trunk/include/lldb/Core/ValueObject.h
lldb/trunk/include/lldb/Symbol/ClangASTType.h
lldb/trunk/source/Core/ValueObject.cpp
lldb/trunk/source/Core/ValueObjectConstResultImpl.cpp
lldb/trunk/source/Symbol/ClangASTType.cpp
Modified: lldb/trunk/include/lldb/Core/ValueObject.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObject.h?rev=213433&r1=213432&r2=213433&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/ValueObject.h (original)
+++ lldb/trunk/include/lldb/Core/ValueObject.h Fri Jul 18 19:12:57 2014
@@ -715,6 +715,10 @@ public:
{
}
+ // Find the address of the C++ vtable pointer
+ virtual lldb::addr_t
+ GetCPPVTableAddress(AddressType &address_type);
+
virtual lldb::ValueObjectSP
Cast (const ClangASTType &clang_ast_type);
Modified: lldb/trunk/include/lldb/Symbol/ClangASTType.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/ClangASTType.h?rev=213433&r1=213432&r2=213433&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/ClangASTType.h (original)
+++ lldb/trunk/include/lldb/Symbol/ClangASTType.h Fri Jul 18 19:12:57 2014
@@ -426,7 +426,6 @@ public:
ClangASTType
GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
- const char *parent_name,
size_t idx,
bool transparent_pointers,
bool omit_empty_base_classes,
@@ -437,7 +436,8 @@ public:
uint32_t &child_bitfield_bit_size,
uint32_t &child_bitfield_bit_offset,
bool &child_is_base_class,
- bool &child_is_deref_of_parent) const;
+ bool &child_is_deref_of_parent,
+ ValueObject *valobj) const;
// Lookup a child given a name. This function will match base class names
// and member member names in "clang_type" only, not descendants.
Modified: lldb/trunk/source/Core/ValueObject.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObject.cpp?rev=213433&r1=213432&r2=213433&view=diff
==============================================================================
--- lldb/trunk/source/Core/ValueObject.cpp (original)
+++ lldb/trunk/source/Core/ValueObject.cpp Fri Jul 18 19:12:57 2014
@@ -793,7 +793,6 @@ ValueObject::CreateChildAtIndex (size_t
ExecutionContext exe_ctx (GetExecutionContextRef());
child_clang_type = GetClangType().GetChildClangTypeAtIndex (&exe_ctx,
- GetName().GetCString(),
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -804,7 +803,8 @@ ValueObject::CreateChildAtIndex (size_t
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- child_is_deref_of_parent);
+ child_is_deref_of_parent,
+ this);
if (child_clang_type)
{
if (synthetic_index)
@@ -3468,6 +3468,38 @@ ValueObject::CreateConstantValue (const
return valobj_sp;
}
+lldb::addr_t
+ValueObject::GetCPPVTableAddress (AddressType &address_type)
+{
+ ClangASTType pointee_type;
+ ClangASTType this_type(GetClangType());
+ uint32_t type_info = this_type.GetTypeInfo(&pointee_type);
+ if (type_info)
+ {
+ bool ptr_or_ref = false;
+ if (type_info & (ClangASTType::eTypeIsPointer | ClangASTType::eTypeIsReference))
+ {
+ ptr_or_ref = true;
+ type_info = pointee_type.GetTypeInfo();
+ }
+
+ const uint32_t cpp_class = ClangASTType::eTypeIsClass | ClangASTType::eTypeIsCPlusPlus;
+ if ((type_info & cpp_class) == cpp_class)
+ {
+ if (ptr_or_ref)
+ {
+ address_type = GetAddressTypeOfChildren();
+ return GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ }
+ else
+ return GetAddressOf (false, &address_type);
+ }
+ }
+
+ address_type = eAddressTypeInvalid;
+ return LLDB_INVALID_ADDRESS;
+}
+
ValueObjectSP
ValueObject::Dereference (Error &error)
{
@@ -3494,7 +3526,6 @@ ValueObject::Dereference (Error &error)
ExecutionContext exe_ctx (GetExecutionContextRef());
child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
- GetName().GetCString(),
0,
transparent_pointers,
omit_empty_base_classes,
@@ -3505,7 +3536,8 @@ ValueObject::Dereference (Error &error)
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- child_is_deref_of_parent);
+ child_is_deref_of_parent,
+ this);
if (child_clang_type && child_byte_size)
{
ConstString child_name;
Modified: lldb/trunk/source/Core/ValueObjectConstResultImpl.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObjectConstResultImpl.cpp?rev=213433&r1=213432&r2=213433&view=diff
==============================================================================
--- lldb/trunk/source/Core/ValueObjectConstResultImpl.cpp (original)
+++ lldb/trunk/source/Core/ValueObjectConstResultImpl.cpp Fri Jul 18 19:12:57 2014
@@ -109,7 +109,6 @@ ValueObjectConstResultImpl::CreateChildA
ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
- m_impl_backend->GetName().GetCString(),
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -120,7 +119,8 @@ ValueObjectConstResultImpl::CreateChildA
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- child_is_deref_of_parent);
+ child_is_deref_of_parent,
+ m_impl_backend);
if (child_clang_type && child_byte_size)
{
if (synthetic_index)
Modified: lldb/trunk/source/Symbol/ClangASTType.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangASTType.cpp?rev=213433&r1=213432&r2=213433&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/ClangASTType.cpp (original)
+++ lldb/trunk/source/Symbol/ClangASTType.cpp Fri Jul 18 19:12:57 2014
@@ -22,6 +22,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
+#include "clang/AST/VTableBuilder.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
@@ -3068,7 +3069,6 @@ ClangASTType::GetNumPointeeChildren () c
ClangASTType
ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
- const char *parent_name,
size_t idx,
bool transparent_pointers,
bool omit_empty_base_classes,
@@ -3079,7 +3079,8 @@ ClangASTType::GetChildClangTypeAtIndex (
uint32_t &child_bitfield_bit_size,
uint32_t &child_bitfield_bit_offset,
bool &child_is_base_class,
- bool &child_is_deref_of_parent) const
+ bool &child_is_deref_of_parent,
+ ValueObject *valobj) const
{
if (!IsValid())
return ClangASTType();
@@ -3146,7 +3147,74 @@ ClangASTType::GetChildClangTypeAtIndex (
if (base_class->isVirtual())
- bit_offset = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8;
+ {
+ bool handled = false;
+ if (valobj)
+ {
+ Error err;
+ AddressType addr_type = eAddressTypeInvalid;
+ lldb::addr_t vtable_ptr_addr = valobj->GetCPPVTableAddress(addr_type);
+
+ if (vtable_ptr_addr != LLDB_INVALID_ADDRESS && addr_type == eAddressTypeLoad)
+ {
+
+ ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ clang::VTableContextBase *vtable_ctx = m_ast->getVTableContext();
+ if (vtable_ctx)
+ {
+ if (vtable_ctx->isMicrosoft())
+ {
+ clang::MicrosoftVTableContext *msoft_vtable_ctx = static_cast<clang::MicrosoftVTableContext *>(vtable_ctx);
+
+ if (vtable_ptr_addr)
+ {
+ const lldb::addr_t vbtable_ptr_addr = vtable_ptr_addr + record_layout.getVBPtrOffset().getQuantity();
+
+ const lldb::addr_t vbtable_ptr = process->ReadPointerFromMemory(vbtable_ptr_addr, err);
+ if (vbtable_ptr != LLDB_INVALID_ADDRESS)
+ {
+ // Get the index into the virtual base table. The index is the index in uint32_t from vbtable_ptr
+ const unsigned vbtable_index = msoft_vtable_ctx->getVBTableIndex(cxx_record_decl, base_class_decl);
+ const lldb::addr_t base_offset_addr = vbtable_ptr + vbtable_index * 4;
+ const uint32_t base_offset = process->ReadUnsignedIntegerFromMemory(base_offset_addr, 4, UINT32_MAX, err);
+ if (base_offset != UINT32_MAX)
+ {
+ handled = true;
+ bit_offset = base_offset * 8;
+ }
+ }
+ }
+ }
+ else
+ {
+ clang::ItaniumVTableContext *itanium_vtable_ctx = static_cast<clang::ItaniumVTableContext *>(vtable_ctx);
+ if (vtable_ptr_addr)
+ {
+ const lldb::addr_t vtable_ptr = process->ReadPointerFromMemory(vtable_ptr_addr, err);
+ if (vtable_ptr != LLDB_INVALID_ADDRESS)
+ {
+ clang::CharUnits base_offset_offset = itanium_vtable_ctx->getVirtualBaseOffsetOffset(cxx_record_decl, base_class_decl);
+ const lldb::addr_t base_offset_addr = vtable_ptr + base_offset_offset.getQuantity();
+ const uint32_t base_offset = process->ReadUnsignedIntegerFromMemory(base_offset_addr, 4, UINT32_MAX, err);
+ if (base_offset != UINT32_MAX)
+ {
+ handled = true;
+ bit_offset = base_offset * 8;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+ if (!handled)
+ bit_offset = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8;
+ }
else
bit_offset = record_layout.getBaseClassOffset(base_class_decl).getQuantity() * 8;
@@ -3321,7 +3389,6 @@ ClangASTType::GetChildClangTypeAtIndex (
child_is_deref_of_parent = false;
bool tmp_child_is_deref_of_parent = false;
return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
- parent_name,
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -3332,11 +3399,13 @@ ClangASTType::GetChildClangTypeAtIndex (
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- tmp_child_is_deref_of_parent);
+ tmp_child_is_deref_of_parent,
+ valobj);
}
else
{
child_is_deref_of_parent = true;
+ const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL;
if (parent_name)
{
child_name.assign(1, '*');
@@ -3411,7 +3480,6 @@ ClangASTType::GetChildClangTypeAtIndex (
child_is_deref_of_parent = false;
bool tmp_child_is_deref_of_parent = false;
return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
- parent_name,
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -3422,12 +3490,14 @@ ClangASTType::GetChildClangTypeAtIndex (
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- tmp_child_is_deref_of_parent);
+ tmp_child_is_deref_of_parent,
+ valobj);
}
else
{
child_is_deref_of_parent = true;
+ const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL;
if (parent_name)
{
child_name.assign(1, '*');
@@ -3456,7 +3526,6 @@ ClangASTType::GetChildClangTypeAtIndex (
child_is_deref_of_parent = false;
bool tmp_child_is_deref_of_parent = false;
return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
- parent_name,
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -3467,10 +3536,12 @@ ClangASTType::GetChildClangTypeAtIndex (
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- tmp_child_is_deref_of_parent);
+ tmp_child_is_deref_of_parent,
+ valobj);
}
else
{
+ const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL;
if (parent_name)
{
child_name.assign(1, '&');
@@ -3492,7 +3563,6 @@ ClangASTType::GetChildClangTypeAtIndex (
{
ClangASTType typedefed_clang_type (m_ast, llvm::cast<clang::TypedefType>(parent_qual_type)->getDecl()->getUnderlyingType());
return typedefed_clang_type.GetChildClangTypeAtIndex (exe_ctx,
- parent_name,
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -3503,7 +3573,8 @@ ClangASTType::GetChildClangTypeAtIndex (
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- child_is_deref_of_parent);
+ child_is_deref_of_parent,
+ valobj);
}
break;
@@ -3511,7 +3582,6 @@ ClangASTType::GetChildClangTypeAtIndex (
{
ClangASTType elaborated_clang_type (m_ast, llvm::cast<clang::ElaboratedType>(parent_qual_type)->getNamedType());
return elaborated_clang_type.GetChildClangTypeAtIndex (exe_ctx,
- parent_name,
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -3522,14 +3592,14 @@ ClangASTType::GetChildClangTypeAtIndex (
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- child_is_deref_of_parent);
+ child_is_deref_of_parent,
+ valobj);
}
case clang::Type::Paren:
{
ClangASTType paren_clang_type (m_ast, llvm::cast<clang::ParenType>(parent_qual_type)->desugar());
return paren_clang_type.GetChildClangTypeAtIndex (exe_ctx,
- parent_name,
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -3540,7 +3610,8 @@ ClangASTType::GetChildClangTypeAtIndex (
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- child_is_deref_of_parent);
+ child_is_deref_of_parent,
+ valobj);
}
Added: lldb/trunk/test/lang/cpp/diamond/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/cpp/diamond/Makefile?rev=213433&view=auto
==============================================================================
--- lldb/trunk/test/lang/cpp/diamond/Makefile (added)
+++ lldb/trunk/test/lang/cpp/diamond/Makefile Fri Jul 18 19:12:57 2014
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
Added: lldb/trunk/test/lang/cpp/diamond/TestDiamond.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/cpp/diamond/TestDiamond.py?rev=213433&view=auto
==============================================================================
--- lldb/trunk/test/lang/cpp/diamond/TestDiamond.py (added)
+++ lldb/trunk/test/lang/cpp/diamond/TestDiamond.py Fri Jul 18 19:12:57 2014
@@ -0,0 +1,63 @@
+"""
+Tests that bool types work
+"""
+import lldb
+from lldbtest import *
+import lldbutil
+
+class CPPTestDiamondInheritance(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+ @dsym_test
+ def test_with_dsym_and_run_command(self):
+ """Test that virtual base classes work in when SBValue objects are used to explore the variable value"""
+ self.buildDsym()
+ self.diamong_inheritace()
+
+ @dwarf_test
+ def test_with_dwarf_and_run_command(self):
+ """Test that virtual base classes work in when SBValue objects are used to explore the variable value"""
+ self.buildDwarf()
+ self.diamong_inheritace()
+
+ def setUp(self):
+ TestBase.setUp(self)
+
+ def set_breakpoint(self, line):
+ # Some compilers (for example GCC 4.4.7 and 4.6.1) emit multiple locations for the statement with the ternary
+ # operator in the test program, while others emit only 1.
+ lldbutil.run_break_set_by_file_and_line (self, "main.cpp", line, num_expected_locations=-1, loc_exact=False)
+
+ def diamong_inheritace(self):
+ """Test that virtual base classes work in when SBValue objects are used to explore the variable value"""
+
+ exe = os.path.join(os.getcwd(), "a.out")
+
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, VALID_TARGET)
+ self.set_breakpoint(line_number('main.cpp', '// breakpoint 1'))
+ self.set_breakpoint(line_number('main.cpp', '// breakpoint 2'))
+ process = target.LaunchSimple (None, None, self.get_process_working_directory())
+ self.assertTrue(process, PROCESS_IS_VALID)
+ thread = process.GetThreadAtIndex(0)
+ frame = thread.GetFrameAtIndex(0)
+ j1 = frame.FindVariable("j1")
+ j1_Derived1 = j1.GetChildAtIndex(0)
+ j1_Derived2 = j1.GetChildAtIndex(1)
+ j1_Derived1_VBase = j1_Derived1.GetChildAtIndex(0)
+ j1_Derived2_VBase = j1_Derived2.GetChildAtIndex(0)
+ j1_Derived1_VBase_m_value = j1_Derived1_VBase.GetChildAtIndex(0)
+ j1_Derived2_VBase_m_value = j1_Derived2_VBase.GetChildAtIndex(0)
+ self.assertTrue(j1_Derived1_VBase.GetLoadAddress() == j1_Derived2_VBase.GetLoadAddress(), "ensure virtual base class is the same between Derived1 and Derived2")
+ self.assertTrue(j1_Derived1_VBase_m_value.GetValueAsUnsigned(1) == j1_Derived2_VBase_m_value.GetValueAsUnsigned(2), "ensure m_value in VBase is the same")
+ self.assertTrue(frame.FindVariable("d").GetChildAtIndex(0).GetChildAtIndex(0).GetValueAsUnsigned(0) == 12345, "ensure Derived2 from j1 is correct");
+ thread.StepOver()
+ self.assertTrue(frame.FindVariable("d").GetChildAtIndex(0).GetChildAtIndex(0).GetValueAsUnsigned(0) == 12346, "ensure Derived2 from j2 is correct");
+
+if __name__ == '__main__':
+ import atexit
+ lldb.SBDebugger.Initialize()
+ atexit.register(lambda: lldb.SBDebugger.Terminate())
+ unittest2.main()
Added: lldb/trunk/test/lang/cpp/diamond/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/cpp/diamond/main.cpp?rev=213433&view=auto
==============================================================================
--- lldb/trunk/test/lang/cpp/diamond/main.cpp (added)
+++ lldb/trunk/test/lang/cpp/diamond/main.cpp Fri Jul 18 19:12:57 2014
@@ -0,0 +1,85 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <stdio.h>
+
+static int g_next_value = 12345;
+
+class VBase
+{
+public:
+ VBase() : m_value(g_next_value++) {}
+ virtual ~VBase() {}
+ void Print()
+ {
+ printf("%p: %s\n%p: m_value = 0x%8.8x\n", this, __PRETTY_FUNCTION__, &m_value, m_value);
+ }
+ int m_value;
+};
+
+class Derived1 : public virtual VBase
+{
+public:
+ Derived1() {};
+ void Print ()
+ {
+ printf("%p: %s\n", this, __PRETTY_FUNCTION__);
+ VBase::Print();
+ }
+
+};
+
+class Derived2 : public virtual VBase
+{
+public:
+ Derived2() {};
+
+ void Print ()
+ {
+ printf("%p: %s\n", this, __PRETTY_FUNCTION__);
+ VBase::Print();
+ }
+};
+
+class Joiner1 : public Derived1, public Derived2
+{
+public:
+ Joiner1() :
+ m_joiner1(3456),
+ m_joiner2(6789) {}
+ void Print ()
+ {
+ printf("%p: %s \n%p: m_joiner1 = 0x%8.8x\n%p: m_joiner2 = 0x%8.8x\n",
+ this,
+ __PRETTY_FUNCTION__,
+ &m_joiner1,
+ m_joiner1,
+ &m_joiner2,
+ m_joiner2);
+ Derived1::Print();
+ Derived2::Print();
+ }
+ int m_joiner1;
+ int m_joiner2;
+};
+
+class Joiner2 : public Derived2
+{
+ int m_stuff[32];
+};
+
+int main(int argc, const char * argv[])
+{
+ Joiner1 j1;
+ Joiner2 j2;
+ j1.Print();
+ j2.Print();
+ Derived2 *d = &j1;
+ d = &j2; // breakpoint 1
+ return 0; // breakpoint 2
+}
More information about the lldb-commits
mailing list