[Lldb-commits] [PATCH] D53506: [ClangASTContext] Extract VTable pointers from C++ objects

Aleksandr Urakov via Phabricator via lldb-commits lldb-commits at lists.llvm.org
Tue Oct 23 06:13:03 PDT 2018


aleksandr.urakov added a reviewer: zturner.
aleksandr.urakov added a comment.

In https://reviews.llvm.org/D53506#1270933, @zturner wrote:

> So, the point is, just because we don't have access to the info via DIA doesn't mean we won't have access to the info once the native pdb plugin is complete.  Just something to think about.


Yes, I also try to see low-level PDB dumps now (since the case with FPO :) ), but in this case it seems that we still have no required info to retrieve VBase offsets. Consider the following example:

  struct A { int a = 1; };
  struct B : virtual A { int b = 2; };
  struct C : virtual A { int c = 3; };
  struct D : virtual B, virtual C { int d = 4; };
  
  int main() {
    D d{};
    return 0;
  }

Here for `D` we have the next `LF_FIELDLIST` (assume that the application is MSVC compiled):

  0x1016 | LF_FIELDLIST [size = 96, hash = 0x415A]
           - LF_VBCLASS
             base = 0x1002, vbptr = 0x1004, vbptr offset = 0, vtable index = 2
             attrs = public
           - LF_VBCLASS
             base = 0x1005, vbptr = 0x1004, vbptr offset = 0, vtable index = 3
             attrs = public
           - LF_IVBCLASS
             base = 0x1006, vbptr = 0x1004, vbptr offset = 0, vtable index = 1
             attrs = public
           - LF_MEMBER [name = `d`, Type = 0x0074 (int), offset = 4, attrs = public]
           - LF_METHOD [name = `D`, # overloads = 3, overload list = 0x1011]
           - LF_METHOD [name = `operator=`, # overloads = 2, overload list = 0x1015]
  0x1017 | LF_STRUCTURE [size = 32, hash = 0xC4D] `D`
           unique name: `.?AUD@@`
           vtable: <no type>, base list: <no type>, field list: 0x1016
           options: has ctor / dtor | has unique name | overloaded operator | overloaded operator=, sizeof 28

`vbptr offset` here is an offset to VBTable pointer, not to VBase. `MicrosoftRecordLayoutBuilder` requires exactly offsets to VBases as if they were non-virtual base classes. In general it is wrong, but it works ok if we know a real full type of the variable. `ClangASTContext` when retrieving a virtual base offset tries at first to retrieve it in the "fair" way:

- retrieve the pointer to VTable;
- read the offset to the VBase from VTable.

If it fails somewhere, then it gets the VBase offset from the record layout. It is an "unfair" VBase offset, which was put there by `MicrosoftRecordLayoutBuilder`. And what I mean is that we have no info about it in PDB (to give it to `MicrosoftRecordLayoutBuilder`).

What this patch makes is it allows the "fair" way to work in the case, when an object is already read from the debuggee. Then we will have `eAddressTypeHost` as an address type of `ValueObject`, and it used to lead to the situation when the "fair" way is failing and the "unfair" way is used. This patch allows to still process it by the "fair" way.

To make things more clear consider the structures layout:

  class A	size(4):
  	+---
   0	| a
  	+---
  
  class B	size(12):
  	+---
   0	| {vbptr}
   4	| b
  	+---
  	+--- (virtual base A)
   8	| a
  	+---
  
  class C	size(12):
  	+---
   0	| {vbptr}
   4	| c
  	+---
  	+--- (virtual base A)
   8	| a
  	+---
  
  class D	size(28):
  	+---
   0	| {vbptr}
   4	| d
  	+---
  	+--- (virtual base A)
   8	| a
  	+---
  	+--- (virtual base B)
  12	| {vbptr}
  16	| b
  	+---
  	+--- (virtual base C)
  20	| {vbptr}
  24	| c
  	+---

`MicrosoftRecordsLayoutBuilder` waits that we will give it 8 as the VBase offset for `A` in `B`, `C` and `D`. In `D` for `B` it wants 12, and for `C` it wants 20. It's an info we are missing in PDB.

Also this example can show how this patch should improve behavior on non-Windows too. If you will stand on `return 0` and call `print d`, then an invalid value should be printed for `A` inside `B` or `C`. If you call `frame variable d` then the value printed should be ok. It's because in the first case an object is already fully read from the debuggee, and without the patch the "unfair" way works, and it uses the offset to `A` from `B` (or `C`) as if `B` (or `C`) would be a real type of the variable (for the layout above it would use 8). But the real type is `D`, so offsets to `A` from `B` (or `C`) inside `D` are different (for the layout above it would be -4 from `B` and -12 from `C`). That's why "unfair" way doesn't work in this case. This patch should also fix it.


Repository:
  rLLDB LLDB

https://reviews.llvm.org/D53506





More information about the lldb-commits mailing list