title: vtable information gdb vs readelf/objdump
body: <p>Using in gdb (e.g. for <em>this</em> pointing to some MyClass instance)</p>
  
  <blockquote>
    <p>info vtbl this</p>
  </blockquote>
  
  <p>on linux sometimes shows a high address somewhere below 0x800000000000.<br>
  But asking </p>
  
  <blockquote>
    <p>readelf --symbols --wide /usr/bin/my-binary|c++filt|grep "vtable.*MyClass"</p>
  </blockquote>
  
  <p>shows a different - very much lower - value.<br>
  I guess this is due to code relocation.<br>
  How can i correlate these values?<br>
  Where is "documented" which sections/area are relocated?<br>
  <br>
  I am asking because if have a dangling instance, with memory area already re-used for some other object. As a consequence my this ptr has a "wrong" vtable entry.<br>
  How can i find out, which class the vtable is now referencing to?
  <br>
  <br>
  Exercising with a <strong>simple</strong> (small) test program does <strong>not</strong> have this problem:</p>
  
  <pre><code>frank@frank-PC:~/TEST$ cat test.cpp
  
  #include &lt;iostream&gt;
  
  class Base 
  {
  public:
      virtual ~Base()
      {
      }
  
      virtual void DoIt(void)
      {
          std::cout &lt;&lt; "Base::DoIt()" &lt;&lt; std::endl;
      }
  };
  
  class Derived : public Base
  {
  public:
      void DoIt(void)
      {
          std::cout &lt;&lt; "Derived::DoIt()" &lt;&lt; std::endl;
      }
  };
  
  int
  main(
      int,
      char**)
  {
      Derived d;
      d.DoIt();
      return 0;
  }
  </code></pre>
  
  <p>compile:</p>
  
  <pre><code>g++ -fPIC -o test -g3 test.cpp
  </code></pre>
  
  <p>gdb:</p>
  
  <pre><code>frank@frank-PC:~/TEST$ gdb --batch -ex "break 22" -ex "r" -ex "info vtbl this" ./test
  
  warning: /home/frank/.gdbinit: Success
  Breakpoint 1 at 0x400c13: file test.cpp, line 22.
  Derived::DoIt()
  
  Breakpoint 1, Derived::DoIt (this=0x7fffffffdad0) at test.cpp:22
  22      }
  vtable for 'Derived' @ 0x601d88 (subobject @ 0x7fffffffdad0):
  [0]: 0x400c62 &lt;Derived::~Derived()&gt;
  [1]: 0x400ca4 &lt;Derived::~Derived()&gt;
  [2]: 0x400bdc &lt;Derived::DoIt()&gt;
  </code></pre>
  
  <p>symbol from readelf:</p>
  
  <pre><code>frank@frank-PC:~/TEST$ readelf --symbols --wide ./test|c++filt |grep vtable
      11: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  UND vtable for __cxxabiv1::__class_type_info@CXXABI_1.3 (4)
      13: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  UND vtable for __cxxabiv1::__si_class_type_info@CXXABI_1.3 (4)
      85: 0000000000601d78    40 OBJECT  WEAK   DEFAULT   23 vtable for Derived
      86: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  UND vtable for __cxxabiv1::__class_type_info@@CXXABI_1.3
      97: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  UND vtable for __cxxabiv1::__si_class_type_info@@CXXABI_1.3
     104: 0000000000601da0    40 OBJECT  WEAK   DEFAULT   23 vtable for Base
  </code></pre>
  
  <p>So vtable for Derived is at 0x0000000000601d78.</p>
  
  <p>sections from readelf:</p>
  
  <pre><code>frank@frank-PC:~/TEST$ readelf --sections --wide ./test
  There are 40 section headers, starting at offset 0x11a38:
  
  Section Headers:
    [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
    [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
    [ 1] .interp           PROGBITS        0000000000400238 000238 00001c 00   A  0   0  1
    [ 2] .note.ABI-tag     NOTE            0000000000400254 000254 000020 00   A  0   0  4
    [ 3] .note.gnu.build-id NOTE            0000000000400274 000274 000024 00   A  0   0  4
    [ 4] .gnu.hash         GNU_HASH        0000000000400298 000298 00001c 00   A  5   0  8
    [ 5] .dynsym           DYNSYM          00000000004002b8 0002b8 0001c8 18   A  6   1  8
    [ 6] .dynstr           STRTAB          0000000000400480 000480 00021e 00   A  0   0  1
    [ 7] .gnu.version      VERSYM          000000000040069e 00069e 000026 02   A  5   0  2
    [ 8] .gnu.version_r    VERNEED         00000000004006c8 0006c8 000080 00   A  6   3  8
    [ 9] .rela.dyn         RELA            0000000000400748 000748 0000a8 18   A  5   0  8
    [10] .rela.plt         RELA            00000000004007f0 0007f0 0000c0 18  AI  5  26  8
    [11] .init             PROGBITS        00000000004008b0 0008b0 00001a 00  AX  0   0  4
    [12] .plt              PROGBITS        00000000004008d0 0008d0 000090 10  AX  0   0 16
    [13] .plt.got          PROGBITS        0000000000400960 000960 000008 00  AX  0   0  8
    [14] .text             PROGBITS        0000000000400970 000970 0003d2 00  AX  0   0 16
    [15] .fini             PROGBITS        0000000000400d44 000d44 000009 00  AX  0   0  4
    [16] .rodata           PROGBITS        0000000000400d50 000d50 000037 00   A  0   0  8
    [17] .eh_frame_hdr     PROGBITS        0000000000400d88 000d88 000084 00   A  0   0  4
    [18] .eh_frame         PROGBITS        0000000000400e10 000e10 00025c 00   A  0   0  8
    [19] .gcc_except_table PROGBITS        000000000040106c 00106c 00000c 00   A  0   0  1
    [20] .init_array       INIT_ARRAY      0000000000601d58 001d58 000010 00  WA  0   0  8
    [21] .fini_array       FINI_ARRAY      0000000000601d68 001d68 000008 00  WA  0   0  8
    [22] .jcr              PROGBITS        0000000000601d70 001d70 000008 00  WA  0   0  8
    [23] .data.rel.ro      PROGBITS        0000000000601d78 001d78 000078 00  WA  0   0  8
    [24] .dynamic          DYNAMIC         0000000000601df0 001df0 0001f0 10  WA  6   0  8
    [25] .got              PROGBITS        0000000000601fe0 001fe0 000020 08  WA  0   0  8
    [26] .got.plt          PROGBITS        0000000000602000 002000 000058 08  WA  0   0  8
    [27] .data             PROGBITS        0000000000602058 002058 000018 00  WA  0   0  8
    [28] .bss              NOBITS          0000000000602070 002070 000008 00  WA  0   0  1
    [29] .comment          PROGBITS        0000000000000000 002070 000034 01  MS  0   0  1
    [30] .debug_aranges    PROGBITS        0000000000000000 0020a4 0000b0 00      0   0  1
    [31] .debug_info       PROGBITS        0000000000000000 002154 001925 00      0   0  1
    [32] .debug_abbrev     PROGBITS        0000000000000000 003a79 000516 00      0   0  1
    [33] .debug_line       PROGBITS        0000000000000000 003f8f 00080f 00      0   0  1
    [34] .debug_str        PROGBITS        0000000000000000 00479e 009ba4 01  MS  0   0  1
    [35] .debug_ranges     PROGBITS        0000000000000000 00e342 0000a0 00      0   0  1
    [36] .debug_macro      PROGBITS        0000000000000000 00e3e2 00251e 00      0   0  1
    [37] .shstrtab         STRTAB          0000000000000000 0118ac 000186 00      0   0  1
    [38] .symtab           SYMTAB          0000000000000000 010900 000a50 18     39  59  8
    [39] .strtab           STRTAB          0000000000000000 011350 00055c 00      0   0  1
  Key to Flags:
    W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
    I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
    O (extra OS processing required) o (OS specific), p (processor specific)
  </code></pre>
  
  <p>So relevant section is .data.rel.ro</p>
  
  <p>objdump:</p>
  
  <pre><code>frank@frank-PC:~/TEST$ objdump -s -j .data.rel.ro ./test
  
  ./test:     file format elf64-x86-64
  
  Contents of section .data.rel.ro:
   601d78 00000000 00000000 c81d6000 00000000  ..........`.....
   601d88 620c4000 00000000 a40c4000 00000000  b.@.......@.....
   601d98 dc0b4000 00000000 00000000 00000000  ..@.............
   601da8 e01d6000 00000000 460b4000 00000000  ..`.....F.@.....
   601db8 7c0b4000 00000000 a20b4000 00000000  |.@.......@.....
   601dc8 00000000 00000000 780d4000 00000000  ........x.@.....
   601dd8 e01d6000 00000000 00000000 00000000  ..`.............
   601de8 810d4000 00000000                    ..@.....        
  </code></pre>
  
  <p><strong>Note</strong><br>
  There is an offset of 0x10 (#16) between the "vtable for Derived" information of readelf (0x0000000000601d78) and gdb (0x0000000000601d88).
  The reason for that is described here: <a href="https://www.rpi.edu/dept/cis/software/g77-mingw32/info-html/g++int.html#Vtables" rel="nofollow noreferrer">https://www.rpi.edu/dept/cis/software/g77-mingw32/info-html/g++int.html#Vtables</a>, chapter "Specification of thunked vtables".</p>
  
  <p>"For vtable thunks, each slot only consists of a pointer to the virtual function, which might be a thunk function. The <strong>first slot</strong> in the vtable is an offset of the this pointer to the complete object, which is needed as a parameter to __dynamic_cast. The <strong>second slot</strong> is the virtual typeinfo function. All other slots are allocated with the same procedure as in the non-thunked case. Allocation of vfields also uses the same procedure as described above."</p>
  
  <p>Looking again at those leading #16 octets in my example we have</p>
  
  <pre><code>601d78 00000000 00000000 c81d6000 00000000  ..........`.....
  </code></pre>
  
  <p><strong>1st slot</strong>  0x0000000000000000<br>
  <strong>2nd slot</strong>  0x0000000000601dc8 (octets re-ordered for a valid address)<br>
  <br>
  Cross-check for <strong>2nd slot</strong>:<br></p>
  
  <pre><code>&gt; objdump -z -D -j .data.rel.ro test|c++filt
  
  0000000000601dc8 &lt;typeinfo for Derived&gt;:
    601dc8:       00 00                   add    %al,(%rax)
    601dca:       00 00                   add    %al,(%rax)
    601dcc:       00 00                   add    %al,(%rax)
    601dce:       00 00                   add    %al,(%rax)
    601dd0:       78 0d                   js     601ddf &lt;typeinfo for Derived+0x17&gt;
    601dd2:       40 00 00                add    %al,(%rax)
    601dd5:       00 00                   add    %al,(%rax)
    601dd7:       00 e0                   add    %ah,%al
    601dd9:       1d 60 00 00 00          sbb    $0x60,%eax
    601dde:       00 00                   add    %al,(%rax)
  </code></pre>