LLDB now correctly handles virtual inheritance.
Test case added as well. <rdar://problem/16785904> llvm-svn: 213433
This commit is contained in:
parent
cfd17dd2be
commit
759e7441af
|
@ -715,6 +715,10 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the address of the C++ vtable pointer
|
||||||
|
virtual lldb::addr_t
|
||||||
|
GetCPPVTableAddress(AddressType &address_type);
|
||||||
|
|
||||||
virtual lldb::ValueObjectSP
|
virtual lldb::ValueObjectSP
|
||||||
Cast (const ClangASTType &clang_ast_type);
|
Cast (const ClangASTType &clang_ast_type);
|
||||||
|
|
||||||
|
|
|
@ -426,7 +426,6 @@ public:
|
||||||
|
|
||||||
ClangASTType
|
ClangASTType
|
||||||
GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
const char *parent_name,
|
|
||||||
size_t idx,
|
size_t idx,
|
||||||
bool transparent_pointers,
|
bool transparent_pointers,
|
||||||
bool omit_empty_base_classes,
|
bool omit_empty_base_classes,
|
||||||
|
@ -437,7 +436,8 @@ public:
|
||||||
uint32_t &child_bitfield_bit_size,
|
uint32_t &child_bitfield_bit_size,
|
||||||
uint32_t &child_bitfield_bit_offset,
|
uint32_t &child_bitfield_bit_offset,
|
||||||
bool &child_is_base_class,
|
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
|
// Lookup a child given a name. This function will match base class names
|
||||||
// and member member names in "clang_type" only, not descendants.
|
// and member member names in "clang_type" only, not descendants.
|
||||||
|
|
|
@ -793,7 +793,6 @@ ValueObject::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_
|
||||||
ExecutionContext exe_ctx (GetExecutionContextRef());
|
ExecutionContext exe_ctx (GetExecutionContextRef());
|
||||||
|
|
||||||
child_clang_type = GetClangType().GetChildClangTypeAtIndex (&exe_ctx,
|
child_clang_type = GetClangType().GetChildClangTypeAtIndex (&exe_ctx,
|
||||||
GetName().GetCString(),
|
|
||||||
idx,
|
idx,
|
||||||
transparent_pointers,
|
transparent_pointers,
|
||||||
omit_empty_base_classes,
|
omit_empty_base_classes,
|
||||||
|
@ -804,7 +803,8 @@ ValueObject::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_
|
||||||
child_bitfield_bit_size,
|
child_bitfield_bit_size,
|
||||||
child_bitfield_bit_offset,
|
child_bitfield_bit_offset,
|
||||||
child_is_base_class,
|
child_is_base_class,
|
||||||
child_is_deref_of_parent);
|
child_is_deref_of_parent,
|
||||||
|
this);
|
||||||
if (child_clang_type)
|
if (child_clang_type)
|
||||||
{
|
{
|
||||||
if (synthetic_index)
|
if (synthetic_index)
|
||||||
|
@ -3468,6 +3468,38 @@ ValueObject::CreateConstantValue (const ConstString &name)
|
||||||
return valobj_sp;
|
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
|
ValueObjectSP
|
||||||
ValueObject::Dereference (Error &error)
|
ValueObject::Dereference (Error &error)
|
||||||
{
|
{
|
||||||
|
@ -3494,7 +3526,6 @@ ValueObject::Dereference (Error &error)
|
||||||
ExecutionContext exe_ctx (GetExecutionContextRef());
|
ExecutionContext exe_ctx (GetExecutionContextRef());
|
||||||
|
|
||||||
child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
|
child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
|
||||||
GetName().GetCString(),
|
|
||||||
0,
|
0,
|
||||||
transparent_pointers,
|
transparent_pointers,
|
||||||
omit_empty_base_classes,
|
omit_empty_base_classes,
|
||||||
|
@ -3505,7 +3536,8 @@ ValueObject::Dereference (Error &error)
|
||||||
child_bitfield_bit_size,
|
child_bitfield_bit_size,
|
||||||
child_bitfield_bit_offset,
|
child_bitfield_bit_offset,
|
||||||
child_is_base_class,
|
child_is_base_class,
|
||||||
child_is_deref_of_parent);
|
child_is_deref_of_parent,
|
||||||
|
this);
|
||||||
if (child_clang_type && child_byte_size)
|
if (child_clang_type && child_byte_size)
|
||||||
{
|
{
|
||||||
ConstString child_name;
|
ConstString child_name;
|
||||||
|
|
|
@ -109,7 +109,6 @@ ValueObjectConstResultImpl::CreateChildAtIndex (size_t idx, bool synthetic_array
|
||||||
ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
|
ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
|
||||||
|
|
||||||
child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
|
child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
|
||||||
m_impl_backend->GetName().GetCString(),
|
|
||||||
idx,
|
idx,
|
||||||
transparent_pointers,
|
transparent_pointers,
|
||||||
omit_empty_base_classes,
|
omit_empty_base_classes,
|
||||||
|
@ -120,7 +119,8 @@ ValueObjectConstResultImpl::CreateChildAtIndex (size_t idx, bool synthetic_array
|
||||||
child_bitfield_bit_size,
|
child_bitfield_bit_size,
|
||||||
child_bitfield_bit_offset,
|
child_bitfield_bit_offset,
|
||||||
child_is_base_class,
|
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 (child_clang_type && child_byte_size)
|
||||||
{
|
{
|
||||||
if (synthetic_index)
|
if (synthetic_index)
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "clang/AST/DeclTemplate.h"
|
#include "clang/AST/DeclTemplate.h"
|
||||||
#include "clang/AST/RecordLayout.h"
|
#include "clang/AST/RecordLayout.h"
|
||||||
#include "clang/AST/Type.h"
|
#include "clang/AST/Type.h"
|
||||||
|
#include "clang/AST/VTableBuilder.h"
|
||||||
|
|
||||||
#include "clang/Basic/Builtins.h"
|
#include "clang/Basic/Builtins.h"
|
||||||
#include "clang/Basic/IdentifierTable.h"
|
#include "clang/Basic/IdentifierTable.h"
|
||||||
|
@ -3068,7 +3069,6 @@ ClangASTType::GetNumPointeeChildren () const
|
||||||
|
|
||||||
ClangASTType
|
ClangASTType
|
||||||
ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
const char *parent_name,
|
|
||||||
size_t idx,
|
size_t idx,
|
||||||
bool transparent_pointers,
|
bool transparent_pointers,
|
||||||
bool omit_empty_base_classes,
|
bool omit_empty_base_classes,
|
||||||
|
@ -3079,7 +3079,8 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
uint32_t &child_bitfield_bit_size,
|
uint32_t &child_bitfield_bit_size,
|
||||||
uint32_t &child_bitfield_bit_offset,
|
uint32_t &child_bitfield_bit_offset,
|
||||||
bool &child_is_base_class,
|
bool &child_is_base_class,
|
||||||
bool &child_is_deref_of_parent) const
|
bool &child_is_deref_of_parent,
|
||||||
|
ValueObject *valobj) const
|
||||||
{
|
{
|
||||||
if (!IsValid())
|
if (!IsValid())
|
||||||
return ClangASTType();
|
return ClangASTType();
|
||||||
|
@ -3146,7 +3147,74 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
|
|
||||||
|
|
||||||
if (base_class->isVirtual())
|
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
|
else
|
||||||
bit_offset = record_layout.getBaseClassOffset(base_class_decl).getQuantity() * 8;
|
bit_offset = record_layout.getBaseClassOffset(base_class_decl).getQuantity() * 8;
|
||||||
|
|
||||||
|
@ -3321,7 +3389,6 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
child_is_deref_of_parent = false;
|
child_is_deref_of_parent = false;
|
||||||
bool tmp_child_is_deref_of_parent = false;
|
bool tmp_child_is_deref_of_parent = false;
|
||||||
return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
|
return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
|
||||||
parent_name,
|
|
||||||
idx,
|
idx,
|
||||||
transparent_pointers,
|
transparent_pointers,
|
||||||
omit_empty_base_classes,
|
omit_empty_base_classes,
|
||||||
|
@ -3332,11 +3399,13 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
child_bitfield_bit_size,
|
child_bitfield_bit_size,
|
||||||
child_bitfield_bit_offset,
|
child_bitfield_bit_offset,
|
||||||
child_is_base_class,
|
child_is_base_class,
|
||||||
tmp_child_is_deref_of_parent);
|
tmp_child_is_deref_of_parent,
|
||||||
|
valobj);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
child_is_deref_of_parent = true;
|
child_is_deref_of_parent = true;
|
||||||
|
const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL;
|
||||||
if (parent_name)
|
if (parent_name)
|
||||||
{
|
{
|
||||||
child_name.assign(1, '*');
|
child_name.assign(1, '*');
|
||||||
|
@ -3411,7 +3480,6 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
child_is_deref_of_parent = false;
|
child_is_deref_of_parent = false;
|
||||||
bool tmp_child_is_deref_of_parent = false;
|
bool tmp_child_is_deref_of_parent = false;
|
||||||
return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
|
return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
|
||||||
parent_name,
|
|
||||||
idx,
|
idx,
|
||||||
transparent_pointers,
|
transparent_pointers,
|
||||||
omit_empty_base_classes,
|
omit_empty_base_classes,
|
||||||
|
@ -3422,12 +3490,14 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
child_bitfield_bit_size,
|
child_bitfield_bit_size,
|
||||||
child_bitfield_bit_offset,
|
child_bitfield_bit_offset,
|
||||||
child_is_base_class,
|
child_is_base_class,
|
||||||
tmp_child_is_deref_of_parent);
|
tmp_child_is_deref_of_parent,
|
||||||
|
valobj);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
child_is_deref_of_parent = true;
|
child_is_deref_of_parent = true;
|
||||||
|
|
||||||
|
const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL;
|
||||||
if (parent_name)
|
if (parent_name)
|
||||||
{
|
{
|
||||||
child_name.assign(1, '*');
|
child_name.assign(1, '*');
|
||||||
|
@ -3456,7 +3526,6 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
child_is_deref_of_parent = false;
|
child_is_deref_of_parent = false;
|
||||||
bool tmp_child_is_deref_of_parent = false;
|
bool tmp_child_is_deref_of_parent = false;
|
||||||
return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
|
return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
|
||||||
parent_name,
|
|
||||||
idx,
|
idx,
|
||||||
transparent_pointers,
|
transparent_pointers,
|
||||||
omit_empty_base_classes,
|
omit_empty_base_classes,
|
||||||
|
@ -3467,10 +3536,12 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
child_bitfield_bit_size,
|
child_bitfield_bit_size,
|
||||||
child_bitfield_bit_offset,
|
child_bitfield_bit_offset,
|
||||||
child_is_base_class,
|
child_is_base_class,
|
||||||
tmp_child_is_deref_of_parent);
|
tmp_child_is_deref_of_parent,
|
||||||
|
valobj);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL;
|
||||||
if (parent_name)
|
if (parent_name)
|
||||||
{
|
{
|
||||||
child_name.assign(1, '&');
|
child_name.assign(1, '&');
|
||||||
|
@ -3492,7 +3563,6 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
{
|
{
|
||||||
ClangASTType typedefed_clang_type (m_ast, llvm::cast<clang::TypedefType>(parent_qual_type)->getDecl()->getUnderlyingType());
|
ClangASTType typedefed_clang_type (m_ast, llvm::cast<clang::TypedefType>(parent_qual_type)->getDecl()->getUnderlyingType());
|
||||||
return typedefed_clang_type.GetChildClangTypeAtIndex (exe_ctx,
|
return typedefed_clang_type.GetChildClangTypeAtIndex (exe_ctx,
|
||||||
parent_name,
|
|
||||||
idx,
|
idx,
|
||||||
transparent_pointers,
|
transparent_pointers,
|
||||||
omit_empty_base_classes,
|
omit_empty_base_classes,
|
||||||
|
@ -3503,7 +3573,8 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
child_bitfield_bit_size,
|
child_bitfield_bit_size,
|
||||||
child_bitfield_bit_offset,
|
child_bitfield_bit_offset,
|
||||||
child_is_base_class,
|
child_is_base_class,
|
||||||
child_is_deref_of_parent);
|
child_is_deref_of_parent,
|
||||||
|
valobj);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -3511,7 +3582,6 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
{
|
{
|
||||||
ClangASTType elaborated_clang_type (m_ast, llvm::cast<clang::ElaboratedType>(parent_qual_type)->getNamedType());
|
ClangASTType elaborated_clang_type (m_ast, llvm::cast<clang::ElaboratedType>(parent_qual_type)->getNamedType());
|
||||||
return elaborated_clang_type.GetChildClangTypeAtIndex (exe_ctx,
|
return elaborated_clang_type.GetChildClangTypeAtIndex (exe_ctx,
|
||||||
parent_name,
|
|
||||||
idx,
|
idx,
|
||||||
transparent_pointers,
|
transparent_pointers,
|
||||||
omit_empty_base_classes,
|
omit_empty_base_classes,
|
||||||
|
@ -3522,14 +3592,14 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
child_bitfield_bit_size,
|
child_bitfield_bit_size,
|
||||||
child_bitfield_bit_offset,
|
child_bitfield_bit_offset,
|
||||||
child_is_base_class,
|
child_is_base_class,
|
||||||
child_is_deref_of_parent);
|
child_is_deref_of_parent,
|
||||||
|
valobj);
|
||||||
}
|
}
|
||||||
|
|
||||||
case clang::Type::Paren:
|
case clang::Type::Paren:
|
||||||
{
|
{
|
||||||
ClangASTType paren_clang_type (m_ast, llvm::cast<clang::ParenType>(parent_qual_type)->desugar());
|
ClangASTType paren_clang_type (m_ast, llvm::cast<clang::ParenType>(parent_qual_type)->desugar());
|
||||||
return paren_clang_type.GetChildClangTypeAtIndex (exe_ctx,
|
return paren_clang_type.GetChildClangTypeAtIndex (exe_ctx,
|
||||||
parent_name,
|
|
||||||
idx,
|
idx,
|
||||||
transparent_pointers,
|
transparent_pointers,
|
||||||
omit_empty_base_classes,
|
omit_empty_base_classes,
|
||||||
|
@ -3540,7 +3610,8 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
|
||||||
child_bitfield_bit_size,
|
child_bitfield_bit_size,
|
||||||
child_bitfield_bit_offset,
|
child_bitfield_bit_offset,
|
||||||
child_is_base_class,
|
child_is_base_class,
|
||||||
child_is_deref_of_parent);
|
child_is_deref_of_parent,
|
||||||
|
valobj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
LEVEL = ../../../make
|
||||||
|
|
||||||
|
CXX_SOURCES := main.cpp
|
||||||
|
|
||||||
|
include $(LEVEL)/Makefile.rules
|
|
@ -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()
|
|
@ -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
|
||||||
|
}
|
Loading…
Reference in New Issue