find "this" ptr within a callstack
When you’re inspecting a dump file using Windbg, you may want to know the states of an object, to be specific, the members of a C++ object in the context. In order to do that, you need to find out the location of the object ie. the ‘this’ ptr. but how?
Before we go any further, let’s take a brief look of C++ ABI. In the Microsoft implementation of x86 C++ ABI, usually register ECX serves as the ‘this’ ptr. So the following C++ code will be translated to something like:
foo = get_foo();
foo.test()
lea ecx, [ebp-10h] ; load the address of foo
call Foo::test
inside Foo::test(), when it in turn calls another function Bar::test2:
Foo::test(){
Bar bar = get_bar();
bar.test2();
...
}
ecx will be loaded with the address of bar and then make the call. As the ‘this’ ptr to foo will still be used later on, it’s necessary to save ecx before loading bar. The assembly code might be:
mov esi, ecx ; save ecx to esi
lea ecx, [ebp-20h] ; load the address of bar
call Bar::test2
the same goes to test2 which needs to save registers before using them, so the assembly of which may look like:
push esi ; save to stack
push edi
push ebx
...
As we can see in the following callstack, the address of foo was saved into ecx (in main), then copied to esi (in test), and then stored to the stack (in test2), where we’re going to find the ‘this’ ptr.
1. Bar::test2
2. Foo::test
3. main
So the steps to locate the ‘this’ ptr to foo could be summarized as:
- Unassemble the code of Foo::test, to find out which register holds the ‘this’ ptr. (esi in previous example)
- Unassemble the code of function in next frame, that is, Bar::test2, to find out the offset where the register (esi) gets stored in the stack
- Once we get the offset, add it to the ChildEBP in frame 2, dereference the address. done.
The process seems straightforward if you know some assembly. But if you don’t, or you need to deal with dump files everyday, it soon becomes a bit challenging and/or tedious. That’s where the script findthis.py (https://gist.github.com/nicoster/7195565) comes to rescue.
Basically this script does step 2 and 3 for you. As it hasn’t got that far to figure out in which register the ‘this’ ptr stores, it enumerates all the registers stored in the stack for each frame. And using the DML hyperlinks, you can click the links to view them as specific objects. The script is written in python. An extension pykd(http://pykd.codeplex.com/) needs to be installed and loaded before running the script in Windbg.
Some known issues with the script:
- cannot handle function override.
- the value might not be 100% correct.
- may have duplicate registers. Could be enhanced.
- apart from
_EH_prolog3
/_EH_prolog3_GS
, doesn’t handle other prologs (as they’re uncommon in user code). Could be enhanced. reversed frames in the outputEnhanced.
If you would like to improve the script, fork it on github. Below is a screenshot of the output by the script: