Debugger commands (dps, dpp) that make my life easier (part 5)
Today's debugger command is "dps" (display pointers and symbols). You might be familiar with the "dds" command. While dds will always dump a DWORD, dps will dump pointers, where the pointer size is determined by the target. (I used to use dds because I only debugged 32 bit machines, but after debugging a 64 machine for an hour, I forced myself to always dps.)
dps can be used the following tasks:
- Dumping a vtable
- Dumping a jump table (which is essentially the same as a vtable, just constructed differently
- Dumping a call stack
Have you ever had to debug a function which took an abstract base class as a parameter and wanted to know which derived object you were dealing with without stepping into one of its functions? I know I have. You can use dps to dump the table. Let's take the following sample program and set a breakpoint on DoIt() to see the command in action.
#include <windows.h>
class IBase {
public:
virtual ULONG FuncOne(VOID) =0;
virtual ULONG FuncTwo(VOID) =0;
};
class DerivedOne : public IBase {
public:
virtual ULONG FuncOne(VOID) { return 1; };
virtual ULONG FuncTwo(VOID) { return 2; };
};
class DerivedTwo : public IBase {
public:
virtual ULONG FuncOne(VOID) { return 101; };
virtual ULONG FuncTwo(VOID) { return 102; };
};
VOID DoIt(IBase* Base)
{
Base->FuncOne();
}
int _cdecl main(int argc, char *argv[])
{
DerivedOne d1;
DerivedTwo d2;
DoIt(&d1);
DoIt(&d2);
return 0;
}
This is the invocation of DoIt(&d1).
0:000> g DoIt
foo!DoIt:
01001180 8bff mov edi,edi
0:000> dt Base
Local var @ 0x6ff70 Type IBase*
0x0006ff74
+0x000 __VFN_table : 0x010010bc
0:000> dps 0x010010bc l2
010010bc 01001210 foo!DerivedOne::FuncOne [d:\work\foo\main.cpp @ 11]
010010c0 01001230 foo!DerivedOne::FuncTwo [d:\work\foo\main.cpp @ 12]
And we see that the vtable contains function pointers from the class DerivedOne. This is the invocation of DoIt(&d2):
0:000> g DoIt
foo!DoIt:
01001180 8bff mov edi,edi
0:000> dt Base
Local var @ 0x6ff70 Type IBase*
0x0006ff78
+0x000 __VFN_table : 0x010010c4
0:000> dps 0x010010c4 l2
010010c4 01001280 foo!DerivedTwo::FuncOne [d:\work\foo\main.cpp @ 17]
010010c8 010012a0 foo!DerivedTwo::FuncTwo [d:\work\foo\main.cpp @ 18]
NOTE: While using this technique, you have to be aware that the compiler can fold functions from different classes into one function in the image and have the different vtables point to the shared function. This can lead to false positives since you can see ne class's symbols intermixed with another class's in the same vtable.
Now let's look at a jump table, which is exactly like a vtable except it is typically setup programattically at runtime or initialized at compile time explicitly by the provider of the table. KMDF drivers call into the KMDF runtime through a jump table, a variable named WdfFunctions [1]. Let's also look at a particular call to a function (WdfWmiInstanceGetDevice()) and see the function being invoked [2].
[1] 0: kd> dps wmiunittest!WdfFunctions
f83840a8 f1da0440 Wdf01000!imp_WdfChildListCreate
f83840ac f1da07d0 Wdf01000!imp_WdfChildListGetDevice
f83840b0 f1da1e40 Wdf01000!imp_WdfChildListRetrievePdo
[...]
[2] 0: kd> u wmiunittest!WdfWmiInstanceGetDevice
WmiUnitTest!WdfWmiInstanceGetDevice:
f8380bd0 8bff mov edi,edi
f8380bd2 55 push ebp
f8380bd3 8bec mov ebp,esp
f8380bd5 8b4508 mov eax,[ebp+0x8]
f8380bd8 50 push eax
f8380bd9 8b0db84638f8 mov ecx,[WmiUnitTest!WdfDriverGlobals (f83846b8)]
f8380bdf 51 push ecx
f8380be0 ff15884638f8 call dword ptr [WmiUnitTest!WdfFunctions+0x5e0 (f8384688)]
0: kd> dps WmiUnitTest!WdfFunctions+0x5e0 l1
f8384688 f1dec0c0 Wdf01000!imp_WdfWmiInstanceGetDevice
Finally, you can use dps to try to reconstruct a call stack. Let's say that you had a buffer overflow bug and you overwrote the return value on the stack and bugchecked on the return, obliterating any evidence of the faulty function. You can sometimes use dps to recover the remaining stack by dumping esp (on x86). Note that dps @esp is the same as kb if the stack is not corrupted ;).
In this callstack [1], I broke into kd by hitting PrintScreen/SysRq on the target machine. Then I dumped ChildEBP [2] and esp [3] to see what callstack looked like when using dps.
[1] 0: kd> k
ChildEBP RetAddr
8055635c f85b90ce nt!RtlpBreakWithStatusInstruction
8055639c 804db90f i8042prt!I8042KeyboardInterruptService+0x30d
8055639c f85a9062 nt!KiInterruptDispatch+0x45
80556450 804dcbef intelppm!AcpiC1Idle+0x12
80556454 00000000 nt!KiIdleLoop+0x10
[2] 0: kd> dps 8055635c
8055635c 00000202
80556360 f85b90ce i8042prt!I8042KeyboardInterruptService+0x30d
80556364 00000002
80556368 820c5490
8055636c 8212fa58
80556370 80556450 nt!_KiDoubleFaultStack+0x2d50
80556374 8212fc5c
80556378 151870e0
8055637c 371870e0
80556380 00000000
80556384 80556368 nt!_KiDoubleFaultStack+0x2c68
80556388 805563b0 nt!_KiDoubleFaultStack+0x2cb0
8055638c ffffffff
80556390 f85ba274 i8042prt!except_handler3
80556394 f85ba7a8 i8042prt!`string'+0x154
80556398 00000000
8055639c 805563c0 nt!_KiDoubleFaultStack+0x2cc0
805563a0 804db90f nt!KiInterruptDispatch+0x45
805563a4 820c5490
805563a8 8212f998
805563ac 00010009
805563b0 00000193
805563b4 00000000
805563b8 82187002
805563bc 00000193
805563c0 80556450 nt!_KiDoubleFaultStack+0x2d50
805563c4 f85a9062 intelppm!AcpiC1Idle+0x12
[...]
[3] 0: kd> dps @esp
80556360 f85b90ce i8042prt!I8042KeyboardInterruptService+0x30d
80556364 00000002
80556368 820c5490
8055636c 8212fa58
80556370 80556450 nt!_KiDoubleFaultStack+0x2d50
80556374 8212fc5c
80556378 151870e0
8055637c 371870e0
80556380 00000000
80556384 80556368 nt!_KiDoubleFaultStack+0x2c68
80556388 805563b0 nt!_KiDoubleFaultStack+0x2cb0
8055638c ffffffff
80556390 f85ba274 i8042prt!except_handler3
80556394 f85ba7a8 i8042prt!`string'+0x154
80556398 00000000
8055639c 805563c0 nt!_KiDoubleFaultStack+0x2cc0
805563a0 804db90f nt!KiInterruptDispatch+0x45
805563a4 820c5490
805563a8 8212f998
805563ac 00010009
805563b0 00000193
805563b4 00000000
805563b8 82187002
805563bc 00000193
805563c0 80556450 nt!_KiDoubleFaultStack+0x2d50
805563c4 f85a9062 intelppm!AcpiC1Idle+0x12
[...]
Comments
Anonymous
March 28, 2006
Another related command is dpp. It's useful for looking up C++ objects with vtables on the stack (in case debugger cannot find locals or parameters automatically, which is very common in optmized builds).
It's basically dps with an extra dereference, so if you have a C++ object pointer (a pointer to a vtable) on the stack, you can find it with dpp @esp.Anonymous
March 29, 2006
The comment has been removedAnonymous
January 21, 2009
PingBack from http://www.keyongtech.com/2319278-crash-dump-analysis-to-obtainAnonymous
May 27, 2014
good article