Recently I had very not-interesting problem with a small server that was dumping a core in some strange situations. In order to find a root cause I needed to know state of a some object that was stored in process memory. I faced interesting problem - how to find specific object in core file. It has to be possible as a core file consists of the recorded state of the working memory of a processat a specific time.

My object was a class with virtual method. It means that such an object contains virtual pointer to the V-table of a class. My plan to find an object had 3 steps:

  1. Check what's the address of the V-table in binary file
  2. Do the hexdump of program binary file and find offset to the place which stores address to the V-table. This offset will help me to find address to the object file of a class that I'm looking for
  3. Calculate object address in a core file and use gdb to examine it's state

For the following part of the article I’ll use code below, so that it will be easy to understand steps that I took:

class test {
public:
  virtual ~test(){}
};

int main() {
  test t;
  abort();
  return 0;
}

After compiling this code we can use nm command to find address of the V-table to test class.

$ nm -C myapp | grep "vtable for test"
0000000000400980 V vtable for test

Ok, so the V-table adress is 0x400980. Now I need to find a V-pointer in compiled binary. Value of a V-pointer is an address to the V-table + 16 (on 64-bit system). To understand where this +16 comes from we need to understand how layout of the V-table looks like. This layout is pictured at the graph below:

vtable layout

On the graph we can see 5 segments - each is 8 bytes long on 64-bit system and 4 bytes long on 32-bit system (in typical case - length of a pointer is may vary depending on a system you are working with or compiler settings). V-table starts with empty segment (it stores 0x0 value there) this is segment is followed by an address to typeinfo object of the class ( used by typeid function). Next segment is an address to first virtual function declared in the class - for our case it will be address to the destructor of test class. Address of this segment is stored by V-pointer, that’s why value of V-pointer is an address of V-table+16 (on 64-bit system, as each segment is 8 bytes long there).

Next step in my investigation is to determine an address of V-pointer in program binary for an object that I’m looking for. Address of a V-table is 0x400980, so we are looking for value 0x00400980+0x10=0x00400990

$ hexdump -C myapp | grep "90 09 40 00"
00001860  48 c7 00 90 09 40 00 5d  c3 90 90 90 90 90 90 90  |H....@.]........|
00002860  48 c7 00 90 09 40 00 5d  c3 90 90 90 90 90 90 90  |H....@.]........|
0005e410  90 09 40 00 00 00 00 00  00 00 00 00 00 00 00 00  |..@.............|

We have got 3 possible places where object may be located. I’ll use 3-rd for further description (as I know that it is good one, normally you should check all possibilities). Address of this object is 0x005e410.

Now we need to find out what’s the address of this object in a core file. To do it you need to do some calculation, because:

object address in a core file = offset to the V-pointer from program binary + VMA address - VMA offset

VMA addres and VMA offset we can get by using objdump or readelf commands.

$ objdump -h corefile
Sections:
Idx Name          Size      VMA               LMA               File off  Algn
...
36 load26        00001000  00007f7fbc5c5000  0000000000000000  0003e000  2**12
                 CONTENTS, ALLOC, LOAD
37 load27        00022000  00007fff4f143000  0000000000000000  0003f000  2**12
                 CONTENTS, ALLOC, LOAD
38 load28        00001000  00007fff4f1f9000  0000000000000000  00061000  2**12
                 CONTENTS, ALLOC, LOAD, READONLY, CODE
...

Section 37 "load 27" is the one which is interesting for us. It's because V-pointer offset value from program binary is 0x005e410. This value is between 0x3f000 ("File off" column for section 37) and 0x61000 ("File off" column for section 38). VMA address value for this section is 00007fff4f143000, VMA offset value is 0003f000. According to formula above address of the object will be:

0x5e410 + 0x7fff4f143000 - 0x3f000 = 0x7FFF4F162410

Let’s now check with GDB if described procedure is correct:

$gdb myapp core
(gdb) p &t
$1 = (test *) 0x7fff4f162410

As we see address of the t variable is exactly the same as what I have got from the calculation so the procedure is correct.