[Lldb-commits] [lldb] r346669 - [ClangASTContext] Extract VTable pointers from C++ objects

Aleksandr Urakov via lldb-commits lldb-commits at lists.llvm.org
Mon Nov 12 08:23:50 PST 2018


Author: aleksandr.urakov
Date: Mon Nov 12 08:23:50 2018
New Revision: 346669

URL: http://llvm.org/viewvc/llvm-project?rev=346669&view=rev
Log:
[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

Added:
    lldb/trunk/lit/SymbolFile/PDB/Inputs/VBases.cpp
    lldb/trunk/lit/SymbolFile/PDB/Inputs/VBases.script
    lldb/trunk/lit/SymbolFile/PDB/vbases.test
Modified:
    lldb/trunk/include/lldb/Core/ValueObject.h
    lldb/trunk/source/Core/ValueObject.cpp
    lldb/trunk/source/Symbol/ClangASTContext.cpp

Modified: lldb/trunk/include/lldb/Core/ValueObject.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObject.h?rev=346669&r1=346668&r2=346669&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/ValueObject.h (original)
+++ lldb/trunk/include/lldb/Core/ValueObject.h Mon Nov 12 08:23:50 2018
@@ -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,

Added: lldb/trunk/lit/SymbolFile/PDB/Inputs/VBases.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/PDB/Inputs/VBases.cpp?rev=346669&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/PDB/Inputs/VBases.cpp (added)
+++ lldb/trunk/lit/SymbolFile/PDB/Inputs/VBases.cpp Mon Nov 12 08:23:50 2018
@@ -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;
+}

Added: lldb/trunk/lit/SymbolFile/PDB/Inputs/VBases.script
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/PDB/Inputs/VBases.script?rev=346669&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/PDB/Inputs/VBases.script (added)
+++ lldb/trunk/lit/SymbolFile/PDB/Inputs/VBases.script Mon Nov 12 08:23:50 2018
@@ -0,0 +1,7 @@
+breakpoint set --file VBases.cpp --line 15
+
+run
+
+print c
+
+frame variable c
\ No newline at end of file

Added: lldb/trunk/lit/SymbolFile/PDB/vbases.test
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/PDB/vbases.test?rev=346669&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/PDB/vbases.test (added)
+++ lldb/trunk/lit/SymbolFile/PDB/vbases.test Mon Nov 12 08:23:50 2018
@@ -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: }

Modified: lldb/trunk/source/Core/ValueObject.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObject.cpp?rev=346669&r1=346668&r2=346669&view=diff
==============================================================================
--- lldb/trunk/source/Core/ValueObject.cpp (original)
+++ lldb/trunk/source/Core/ValueObject.cpp Mon Nov 12 08:23:50 2018
@@ -2804,31 +2804,6 @@ ValueObjectSP ValueObject::GetQualifiedR
   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();

Modified: lldb/trunk/source/Symbol/ClangASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangASTContext.cpp?rev=346669&r1=346668&r2=346669&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/ClangASTContext.cpp (original)
+++ lldb/trunk/source/Symbol/ClangASTContext.cpp Mon Nov 12 08:23:50 2018
@@ -201,6 +201,122 @@ void addOverridesForMethod(clang::CXXMet
 }
 }
 
+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::GetChildCo
             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)




More information about the lldb-commits mailing list