aleksandr.urakov created this revision.
aleksandr.urakov added reviewers: clayborg, labath, granata.enrico.
aleksandr.urakov added a project: LLDB.
Herald added subscribers: lldb-commits, teemperor, abidh.
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 (btw, it really
returned not a C++ VTable address but an object's address, which is a C++
VTable **pointer** address for Itanium, but have nothing to do with VTable
address for MSVC) 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.
This patch depends on https://reviews.llvm.org/D53497
Repository:
rLLDB LLDB
https://reviews.llvm.org/D53506
Files:
include/lldb/Core/ValueObject.h
lit/SymbolFile/PDB/Inputs/VBases.cpp
lit/SymbolFile/PDB/Inputs/VBases.script
lit/SymbolFile/PDB/vbases.test
source/Core/ValueObject.cpp
source/Symbol/ClangASTContext.cpp
Index: source/Symbol/ClangASTContext.cpp
===================================================================
--- source/Symbol/ClangASTContext.cpp
+++ source/Symbol/ClangASTContext.cpp
@@ -204,6 +204,122 @@
}
}
+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;
@@ -6513,80 +6629,12 @@
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)
Index: source/Core/ValueObject.cpp
===================================================================
--- source/Core/ValueObject.cpp
+++ source/Core/ValueObject.cpp
@@ -2804,31 +2804,6 @@
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();
Index: lit/SymbolFile/PDB/vbases.test
===================================================================
--- /dev/null
+++ 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: }
Index: lit/SymbolFile/PDB/Inputs/VBases.script
===================================================================
--- /dev/null
+++ 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
Index: lit/SymbolFile/PDB/Inputs/VBases.cpp
===================================================================
--- /dev/null
+++ 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;
+}
Index: include/lldb/Core/ValueObject.h
===================================================================
--- include/lldb/Core/ValueObject.h
+++ include/lldb/Core/ValueObject.h
@@ -635,9 +635,6 @@
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,
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits