FW: Search C++ "virtual" objects

On Linux, given a core dump file, an executable and its symbols, is it possible to do the following in LLDB (maybe with a LLDB extension)?

  1. Get the list of all C++ virtual types (classes with virtual function table)

  2. Search the whole address space to find all instances of such objects? (false positives are okay)

If #1 is not possible, then how about getting virtual function table address of a given type (without an object)?

Thanks much.

On Linux, given a core dump file, an executable and its symbols, is it possible to do the following in LLDB (maybe with a LLDB extension)?

1. Get the list of all C++ virtual types (classes with virtual function table)

You will be able to find all vtable symbols in the symbol tables of the executable and shared libraries that you have. Not sure if the system libraries on linux have the vtable symbols in the symbol tables of the shared libraries. If you can download the separate debug info for the shared libraries that might help.

If you made a core file on your current machine and you are trying to look at this core file on the same machine without any shared libraries having been updated, then you might if the vtable symbols are in your executables in the symbol tables as you said.

So the answer is maybe. Depends on how good your symbol tables are for the executables and sharerd libraries that contain virtual classes that you care about.

2. Search the whole address space to find all instances of such objects? (false positives are okay)

You should be able to iterate through all of the memory segments using:

    lldb::SBMemoryRegionInfoList
    GetMemoryRegions();

This is a relatively new thing that was added to LLDB in the last few months so you will need a pretty recent LLDB. But this will give you all of the memory regions in your current process. You can then look at the permissions of each regions to make sure the regions is writable. So you can try this in python:

(lldb)
regions = lldb.process.GetMemoryRegions();
num_regions = regions.GetSize()
region = lldb.SBMemoryRegionInfo()
error = lldb.SBError()
for i in range(num_regions):
  if regions.GetMemoryRegionAtIndex(i, region):
    if region.IsWritable():
      addr = region.GetRegionBase()
      end_addr = region.GetRegionEnd()
      bytes = process.ReadMemory(addr, end_addr - addr, error)
      // Bytes is a binary python string so you can search it for the vtable pointer of your choosing

If #1 is not possible, then how about getting virtual function table address of a given type (without an object)?

There should be symbols in the symbol tables that are the vtable symbols and you can look them up by name. For example, on MacOSX, if you compile the following:

class A
{
public:
    A(int a) : m_a(a) {}
    virtual ~A() {}
protected:
    int m_a;
};
int main (int argc, char const *argv, char const *envp)
{
    A *a_ptr= new A(123);
    return 0;
}

You get a symbol table of:

(lldb) image dump symtab a.out
Symtab, file = /private/tmp/a.out, num_symbols = 19:
               Debug symbol
               >Synthetic symbol
               >>Externally Visible
               >>>
Index UserID DSX Type File Address/Value Load Address Size Flags Name
------- ------ --- --------------- ------------------ ------------------ ------------------ ---------- ----------------------------------
[ 0] 0 D SourceFile 0x0000000000000000 Sibling -> [ 12] 0x00640000 /tmp/main.cpp
[ 1] 2 D ObjectFile 0x0000000057ae67f1 0x0000000000000000 0x00660001 /var/folders/2y/y20b92093flcz2qdwwpf5b6c0007k2/T/main-fb7ae1.o
[ 2] 4 D X Code 0x0000000100000e00 0x0000000100000e00 0x0000000000000080 0x000f0000 main
[ 3] 8 D Code 0x0000000100000e80 0x0000000100000e80 0x0000000000000030 0x001e0080 A::A(int)
[ 4] 12 D Code 0x0000000100000eb0 0x0000000100000eb0 0x0000000000000030 0x001e0080 A::A(int)
[ 5] 16 D Code 0x0000000100000ee0 0x0000000100000ee0 0x0000000000000020 0x001e0080 A::~A()
[ 6] 20 D Code 0x0000000100000f00 0x0000000100000f00 0x0000000000000030 0x001e0080 A::~A()
[ 7] 24 D Code 0x0000000100000f30 0x0000000100000f30 0x000000000000000a 0x001e0080 A::~A()
[ 8] 27 D Data 0x0000000100000f68 0x0000000100000f68 0x000000000000002c 0x000e0000 GCC_except_table0
[ 9] 28 D X Data 0x0000000100000f94 0x0000000100000f94 0x0000000000000003 0x000f0080 typeinfo name for A
[ 10] 29 D X Data 0x0000000100001038 0x0000000100001038 0x0000000000000020 0x001e0080 vtable for A
[ 11] 30 D X Data 0x0000000100001058 0x0000000100001058 0x0000000000000010 0x000f0080 typeinfo for A
[ 12] 41 X Data 0x0000000100000000 0x0000000100000000 0x0000000000000e00 0x000f0010 _mh_execute_header
[ 13] 43 Trampoline 0x0000000100000f46 0x0000000100000f46 0x0000000000000006 0x00010200 _Unwind_Resume
[ 14] 44 X Undefined 0x0000000000000000 0x0000000000000000 0x00010100 vtable for __cxxabiv1::__class_type_info
[ 15] 45 Trampoline 0x0000000100000f3a 0x0000000100000f3a 0x0000000000000006 0x00010180 operator delete(void*)
[ 16] 46 Trampoline 0x0000000100000f40 0x0000000100000f40 0x0000000000000006 0x00010180 operator new(unsigned long)
[ 17] 47 X Undefined 0x0000000000000000 0x0000000000000000 0x00010100 __gxx_personality_v0
[ 18] 48 X Undefined 0x0000000000000000 0x0000000000000000 0x00010200 dyld_stub_binder

Note the entry for the vtable:

[ 10] 29 D X Data 0x0000000100001038 0x0000000100001038 0x0000000000000020 0x001e0080 vtable for A

We can see that the load address is 0x0000000100001038 and we would look for memory regions that contains this pointer.

I am not sure if linux has a way to iterate over all of the malloc blocks in the heap. MacOSX does, but I am not sure if linux does. If it does, you might be able to replicate this block iteration from python if you can see how they do it. Barring that, you are limited to looking through all memory regions in your process for this the vtable pointer (0x0000000100001038).

Greg