diff options
author | Aleksandr Urakov <aleksandr.urakov@jetbrains.com> | 2018-11-12 16:23:50 +0000 |
---|---|---|
committer | Aleksandr Urakov <aleksandr.urakov@jetbrains.com> | 2018-11-12 16:23:50 +0000 |
commit | 1dc51db75764d427189a16332131f76d4f21c9e8 (patch) | |
tree | 399eca66ca518aabdf923790375f52dc14cce9f1 | |
parent | de62b76c5105215d4e14cc869e07ad423c6a3a98 (diff) | |
download | bcm5719-llvm-1dc51db75764d427189a16332131f76d4f21c9e8.tar.gz bcm5719-llvm-1dc51db75764d427189a16332131f76d4f21c9e8.zip |
[ClangASTContext] Extract VTable pointers from C++ objects
This patch processes the case of retrieving a virtual base when the object is
already read from the debuggee memory.
To achieve that ValueObject::GetCPPVTableAddress was removed and was
reimplemented in ClangASTContext (because access to the process is needed to
retrieve the VTable pointer in general, and because this is the only place that
used old version of ValueObject::GetCPPVTableAddress).
This patch allows to use real object's VTable instead of searching virtual bases
by offsets restored by MicrosoftRecordLayoutBuilder. PDB has no enough info to
restore VBase offsets properly, so we have to read real VTable instead.
Differential revision: https://reviews.llvm.org/D53506
llvm-svn: 346669
-rw-r--r-- | lldb/include/lldb/Core/ValueObject.h | 3 | ||||
-rw-r--r-- | lldb/lit/SymbolFile/PDB/Inputs/VBases.cpp | 16 | ||||
-rw-r--r-- | lldb/lit/SymbolFile/PDB/Inputs/VBases.script | 7 | ||||
-rw-r--r-- | lldb/lit/SymbolFile/PDB/vbases.test | 15 | ||||
-rw-r--r-- | lldb/source/Core/ValueObject.cpp | 25 | ||||
-rw-r--r-- | lldb/source/Symbol/ClangASTContext.cpp | 196 |
6 files changed, 160 insertions, 102 deletions
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index 856156a75f2..cb6de7b4180 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -635,9 +635,6 @@ public: virtual void SetLiveAddress(lldb::addr_t addr = LLDB_INVALID_ADDRESS, AddressType address_type = eAddressTypeLoad) {} - // Find the address of the C++ vtable pointer - virtual lldb::addr_t GetCPPVTableAddress(AddressType &address_type); - virtual lldb::ValueObjectSP Cast(const CompilerType &compiler_type); virtual lldb::ValueObjectSP CastPointerType(const char *name, diff --git a/lldb/lit/SymbolFile/PDB/Inputs/VBases.cpp b/lldb/lit/SymbolFile/PDB/Inputs/VBases.cpp new file mode 100644 index 00000000000..a5e84bd3657 --- /dev/null +++ b/lldb/lit/SymbolFile/PDB/Inputs/VBases.cpp @@ -0,0 +1,16 @@ +struct A { + char a = 1; +}; + +struct B { + int b = 2; +}; + +struct C : virtual A, virtual B { + short c = 3; +}; + +int main() { + C c{}; + return 0; +} diff --git a/lldb/lit/SymbolFile/PDB/Inputs/VBases.script b/lldb/lit/SymbolFile/PDB/Inputs/VBases.script new file mode 100644 index 00000000000..8675890b76e --- /dev/null +++ b/lldb/lit/SymbolFile/PDB/Inputs/VBases.script @@ -0,0 +1,7 @@ +breakpoint set --file VBases.cpp --line 15 + +run + +print c + +frame variable c
\ No newline at end of file diff --git a/lldb/lit/SymbolFile/PDB/vbases.test b/lldb/lit/SymbolFile/PDB/vbases.test new file mode 100644 index 00000000000..d54a873b8c6 --- /dev/null +++ b/lldb/lit/SymbolFile/PDB/vbases.test @@ -0,0 +1,15 @@ +REQUIRES: windows +RUN: clang-cl /Zi %S/Inputs/VBases.cpp /o %t.exe +RUN: %lldb -b -s %S/Inputs/VBases.script -- %t.exe | FileCheck %s + +CHECK: { +CHECK: A = (a = '\x01') +CHECK: B = (b = 2) +CHECK: c = 3 +CHECK: } + +CHECK: { +CHECK: A = (a = '\x01') +CHECK: B = (b = 2) +CHECK: c = 3 +CHECK: } diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 3fcd68e15fd..96a171688c9 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -2804,31 +2804,6 @@ ValueObjectSP ValueObject::GetQualifiedRepresentationIfAvailable( return result_sp; } -lldb::addr_t ValueObject::GetCPPVTableAddress(AddressType &address_type) { - CompilerType pointee_type; - CompilerType this_type(GetCompilerType()); - uint32_t type_info = this_type.GetTypeInfo(&pointee_type); - if (type_info) { - bool ptr_or_ref = false; - if (type_info & (eTypeIsPointer | eTypeIsReference)) { - ptr_or_ref = true; - type_info = pointee_type.GetTypeInfo(); - } - - const uint32_t cpp_class = eTypeIsClass | 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(Status &error) { if (m_deref_valobj) return m_deref_valobj->GetSP(); diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp index 47c5e144b13..4a33143cfcc 100644 --- a/lldb/source/Symbol/ClangASTContext.cpp +++ b/lldb/source/Symbol/ClangASTContext.cpp @@ -201,6 +201,122 @@ void addOverridesForMethod(clang::CXXMethodDecl *decl) { } } +static lldb::addr_t GetVTableAddress(Process &process, + VTableContextBase &vtable_ctx, + ValueObject &valobj, + const ASTRecordLayout &record_layout) { + // Retrieve type info + CompilerType pointee_type; + CompilerType this_type(valobj.GetCompilerType()); + uint32_t type_info = this_type.GetTypeInfo(&pointee_type); + if (!type_info) + return LLDB_INVALID_ADDRESS; + + // Check if it's a pointer or reference + bool ptr_or_ref = false; + if (type_info & (eTypeIsPointer | eTypeIsReference)) { + ptr_or_ref = true; + type_info = pointee_type.GetTypeInfo(); + } + + // We process only C++ classes + const uint32_t cpp_class = eTypeIsClass | eTypeIsCPlusPlus; + if ((type_info & cpp_class) != cpp_class) + return LLDB_INVALID_ADDRESS; + + // Calculate offset to VTable pointer + lldb::offset_t vbtable_ptr_offset = + vtable_ctx.isMicrosoft() ? record_layout.getVBPtrOffset().getQuantity() + : 0; + + if (ptr_or_ref) { + // We have a pointer / ref to object, so read + // VTable pointer from process memory + + if (valobj.GetAddressTypeOfChildren() != eAddressTypeLoad) + return LLDB_INVALID_ADDRESS; + + auto vbtable_ptr_addr = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); + if (vbtable_ptr_addr == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + vbtable_ptr_addr += vbtable_ptr_offset; + + Status err; + return process.ReadPointerFromMemory(vbtable_ptr_addr, err); + } + + // We have an object already read from process memory, + // so just extract VTable pointer from it + + DataExtractor data; + Status err; + auto size = valobj.GetData(data, err); + if (err.Fail() || vbtable_ptr_offset + data.GetAddressByteSize() > size) + return LLDB_INVALID_ADDRESS; + + return data.GetPointer(&vbtable_ptr_offset); +} + +static int64_t ReadVBaseOffsetFromVTable(Process &process, + VTableContextBase &vtable_ctx, + lldb::addr_t vtable_ptr, + const CXXRecordDecl *cxx_record_decl, + const CXXRecordDecl *base_class_decl) { + if (vtable_ctx.isMicrosoft()) { + clang::MicrosoftVTableContext &msoft_vtable_ctx = + static_cast<clang::MicrosoftVTableContext &>(vtable_ctx); + + // 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 = vtable_ptr + vbtable_index * 4; + Status err; + return process.ReadSignedIntegerFromMemory(base_offset_addr, 4, INT64_MAX, + err); + } + + clang::ItaniumVTableContext &itanium_vtable_ctx = + static_cast<clang::ItaniumVTableContext &>(vtable_ctx); + + 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_size = process.GetAddressByteSize(); + Status err; + return process.ReadSignedIntegerFromMemory(base_offset_addr, base_offset_size, + INT64_MAX, err); +} + +static bool GetVBaseBitOffset(VTableContextBase &vtable_ctx, + ValueObject &valobj, + const ASTRecordLayout &record_layout, + const CXXRecordDecl *cxx_record_decl, + const CXXRecordDecl *base_class_decl, + int32_t &bit_offset) { + ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); + Process *process = exe_ctx.GetProcessPtr(); + if (!process) + return false; + + lldb::addr_t vtable_ptr = + GetVTableAddress(*process, vtable_ctx, valobj, record_layout); + if (vtable_ptr == LLDB_INVALID_ADDRESS) + return false; + + auto base_offset = ReadVBaseOffsetFromVTable( + *process, vtable_ctx, vtable_ptr, cxx_record_decl, base_class_decl); + if (base_offset == INT64_MAX) + return false; + + bit_offset = base_offset * 8; + + return true; +} + typedef lldb_private::ThreadSafeDenseMap<clang::ASTContext *, ClangASTContext *> ClangASTMap; @@ -6545,80 +6661,12 @@ CompilerType ClangASTContext::GetChildCompilerTypeAtIndex( if (base_class->isVirtual()) { bool handled = false; if (valobj) { - Status 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 = - getASTContext()->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 int32_t base_offset = - process->ReadSignedIntegerFromMemory( - base_offset_addr, 4, INT32_MAX, err); - if (base_offset != INT32_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_size = - process->GetAddressByteSize(); - const int64_t base_offset = - process->ReadSignedIntegerFromMemory( - base_offset_addr, base_offset_size, - UINT32_MAX, err); - if (base_offset < UINT32_MAX) { - handled = true; - bit_offset = base_offset * 8; - } - } - } - } - } - } - } + clang::VTableContextBase *vtable_ctx = + getASTContext()->getVTableContext(); + if (vtable_ctx) + handled = GetVBaseBitOffset(*vtable_ctx, *valobj, + record_layout, cxx_record_decl, + base_class_decl, bit_offset); } if (!handled) bit_offset = record_layout.getVBaseClassOffset(base_class_decl) |