Debugger commands (stack frame navigation) that makes my life easier
One thing that I have always found clunky is stack frame navigation in windbg/kd.
Previously, I thought you had only a couple of options.
The first option, if you are using WinDBG, is that
you can bring up the call stack window. I have found that this is not a great
thing to do b/c WinDBG will try to update the call stack window while the target
is running and not just when you are broken in (perhaps it does this only for
module loads, I don't know). Of course, since this is WinDBG dependent, this does
not work in kd. As the final straw, this requires moving my hands off the keyboard,
losing valuable time navigating with the mouse ;).
The second option is to use the kn
command. This will dump the stack with frame numbers, the output looks like this:
1: kd> kn
# ChildEBP RetAddr
00 81e33c6c 81898d7c nt!RtlpBreakWithStatusInstruction
01 81e33c74 81898d2e nt!KdCheckForDebugBreak+0x22
02 81e33d20 8183ddd5 nt!KeUpdateRunTime+0x270
03 81e33d50 8187dba2 nt!PopIdleDefaultHandler+0x239
04 81e33d54 00000000 nt!KiIdleLoop+0xa
And then you can issue the .frame N command,
where N is the frame number to navigate to that frame and start debugging
1: kd> .frame 3
03 81e33d50 8187dba2 nt!PopIdleDefaultHandler+0x239
1: kd> dv
[...]
My problem is that I didn't know how to do frame relative jumps, so every time
I wanted to move to a new frame I ran kn again
(since I forget the frame numbers), found the new frame and ran
.frame N with the new frame number. Well today I
saw 2 new ways how to navigate the frames.
The first way will work with the previous debugger releases. You use the pseudo register
$frame. Pretty nice trick IMO.
1: kd> .frame @$frame-1
02 81e33d20 8183ddd5 nt!KeUpdateRunTime+0x270
1: kd> .frame @$frame+1
03 81e33d50 8187dba2 nt!PopIdleDefaultHandler+0x239
The second way to navigate frames requires the debugger package that was just
released and is a little less cumbersome to use. There are 2 new debugger commands,
.f+ and .f-.
These are definitely easier to use in my book because I don't have to remember
the register deref syntax.
1: kd> .f-
02 81e33d20 8183ddd5 nt!KeUpdateRunTime+0x270
1: kd> .f+
03 81e33d50 8187dba2 nt!PopIdleDefaultHandler+0x239
With these new commands, I think I get now get by without having to lift my
hands off the keyboard ;).
Comments
Anonymous
August 29, 2006
It is nice to read this blog topic.
When I go up and down the stack using ".f-" or ".f+" the register values should
change from a frame to frame right. It does not change. It always shows
the top stack frame register values. Is this a windbg bug or is there a different command to get the local frame register values.
Where are the register information saved?
Is it saved in the stacka and if so at what location it is saved and how do I get the register values.
Thanks,
SwamyAnonymous
August 29, 2006
registers are not saved per call (unless there is a trap, in which case the 'kv' & '.trap' commands can restore the context). the calling standard dictates which registers are volatile and which are restored during a function call. walking the stack and finding the individual files that were pushed onto the stack is an upcoming topic (a little too complicated for a comment).
dAnonymous
August 29, 2006
Thanks for your quick reply.
Good thing here is at least we can get the context of trap frame. But I tried the
the .trap <address> and it throws syntax error (on windows amd64). I do not understand why. The address I used was the SP of trap frame.
On unix the we can navigate the frames using "up" or "down" commands
and get the local frame registers. I thought it is possible here also.
swamyAnonymous
August 29, 2006
where did you get the address for .trap? from the 'kv' command?
are the registers that important b/c you want to see where your locals/parameters are stored? if so, the 'dv' does a pretty job of displaying those values. On an optimized build you might have a harder time finding the locals/parameters, but it is not too hard to find them with a little disassembly
dAnonymous
August 30, 2006
I used the first field which is Child SP and also tried the second one which is
return address. May be something wrong. It is not taking any address value.
ex:
.trap 05234fc0
Yes the register values are important because to see all the local variables and also you can see from the reg values you can see what code has executed.
It is hard but it helps to diagnose a problem.
I tried dv and it just dumped one symbol and not very useful in the crash I am
looking at.
Anyway thanks for your help.Anonymous
August 30, 2006
The comment has been removedAnonymous
September 01, 2006
Yes I know the frame where trap occured and I see that frame
below KiUserExceptionDispatcher and also the TrapFrame pointer
next to it. I tried that address too. I also tried different
possible formats and it just reports a SyntaxError. This is on
windbg on amd64. I have not tried it on other platform. This
might work on other there. Instead of just printing an SyntaxError
it should print more meaning full error would help.
Yes, I am using optimized build.Anonymous
March 08, 2009
With regards to register contents at each stack frame..... When you are debugging x64 code, you can use the ".frame /r" variant to show what the non-volatile register contents were at that stack frame. This is essential for figuring out values of locals in optimized code since x64 has so many registers and uses them liberally. Additionally, there is the ".frame /c" variant which is similar to ".frame /r" except that it changes the register context similar to the .cxr command. To me, ".frame /c" this is of limited use. More details at the following link: http://blogs.msdn.com/ntdebugging/archive/2009/01/09/challenges-of-debugging-optimized-x64-code.aspx -TreyAnonymous
June 08, 2009
PingBack from http://hairgrowthproducts.info/story.php?id=6983