Good morning AskPerf!  2009 is moving fast – it’s hard to believe we’re already into August!  Today, we’re continuing on with our debugging focus.  Over the next few posts, we’ll be looking at different command types within the debugger.  Today’s post is brought to you by the letter … k.  I know, I couldn’t resist the Sesame Street reference!  Anyways …

The different k* commands in the debugger are used to display stack information of a thread.  The k* commands work in both user-mode and kernel-mode debugging scenarios.  Let’s take a look at the different flavors of the common k* commands and then some examples:

Parameter Explanation
Thread Specifies the thread for which you want to display the stack.  If you do not specify a thread, the current thread’s stack is shown.  You can specify threads in user-mode only
Processor Specifies the processor for which you want to display the stack.  You can specify processors in kernel-mode only
b Display the first three parameters passed to each function in the stack
c Shows a clean stack trace – showing only the module and function name
p Shows all of the parameters for each function called in the stack.  The parameter list includes each parameters data, type, name and value.  Please note that this parameter is cases sensitive and does require full symbol information
P Essentially performs the same function as p except that the function parameters are printed on a second line of the display
v Displays frame pointer Omission (FPO) information
n Shows frame numbers
f Shows the number of bytes that separate the frames on the stack
L Hides the source lines in the display – this is a case sensitive parameter

Now that we have an idea of what our options are, what does this look like in a debugger?  I went ahead and created a manual dump of NOTEPAD.EXE via Task Manager on a 32-bit Windows Vista system and opened the dump file on a system with a debugger configured with the public symbols …

First of all, let’s list out the threads available in this dump file.  To list out the threads, run the ~ command as shown below:

0:000> ~
.  0  Id: 3dc.61c Suspend: 0 Teb: 7ffde000 Unfrozen

Since there was only one thread running, there’s not too much I have to do in terms of looking at different threads.  For the moment, let’s take a look at what each of our commands does, beginning with a simple k

0:000> k
ChildEBP RetAddr  
0019f7a0 7757f837 ntdll!KiFastSystemCallRet
0019f7a4 7757f86a user32!NtUserGetMessage+0xc
0019f7c0 00a71418 user32!GetMessageW+0x33
0019f800 00a7195d notepad!WinMain+0xec
0019f890 774c4911 notepad!_initterm_e+0x1a1
0019f89c 7763e4b6 kernel32!BaseThreadInitThunk+0xe
0019f8dc 7763e489 ntdll!__RtlUserThreadStart+0x23
0019f8f4 00000000 ntdll!_RtlUserThreadStart+0x1b

As we can see, from this stack we have some basic information concerning the modules and the functions.  Now let’s add some of our other parameters, such as kb, kc, kp and kP:

0:000> kb
ChildEBP RetAddr  Args to Child              
0019f7a0 7757f837 7757f86a 0019f7e4 00000000 ntdll!KiFastSystemCallRet
0019f7a4 7757f86a 0019f7e4 00000000 00000000 user32!NtUserGetMessage+0xc
0019f7c0 00a71418 0019f7e4 00000000 00000000 user32!GetMessageW+0x33
0019f800 00a7195d 00a70000 00000000 002d1e92 notepad!WinMain+0xec
0019f890 774c4911 7ffdf000 0019f8dc 7763e4b6 notepad!_initterm_e+0x1a1
0019f89c 7763e4b6 7ffdf000 77707155 00000000 kernel32!BaseThreadInitThunk+0xe
0019f8dc 7763e489 00a731ed 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x23
0019f8f4 00000000 00a731ed 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> kc

ntdll!KiFastSystemCallRet
user32!NtUserGetMessage
user32!GetMessageW
notepad!WinMain
notepad!_initterm_e
kernel32!BaseThreadInitThunk
ntdll!__RtlUserThreadStart
ntdll!_RtlUserThreadStart

0:000> kp
ChildEBP RetAddr  
0019f7a0 7757f837 ntdll!KiFastSystemCallRet
0019f7a4 7757f86a user32!NtUserGetMessage+0xc
0019f7c0 00a71418 user32!GetMessageW+0x33
0019f800 00a7195d notepad!WinMain+0xec
0019f890 774c4911 notepad!_initterm_e+0x1a1
0019f89c 7763e4b6 kernel32!BaseThreadInitThunk+0xe
0019f8dc 7763e489 ntdll!__RtlUserThreadStart+0x23
0019f8f4 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> kP
ChildEBP RetAddr  
0019f7a0 7757f837 ntdll!KiFastSystemCallRet
0019f7a4 7757f86a user32!NtUserGetMessage+0xc
0019f7c0 00a71418 user32!GetMessageW+0x33
0019f800 00a7195d notepad!WinMain+0xec
0019f890 774c4911 notepad!_initterm_e+0x1a1
0019f89c 7763e4b6 kernel32!BaseThreadInitThunk+0xe
0019f8dc 7763e489 ntdll!__RtlUserThreadStart+0x23
0019f8f4 00000000 ntdll!_RtlUserThreadStart+0x1b

As we can see in the last two commands, since we only have the public symbols we cannot see all of the parameter information that we would if we had access to the private symbols.  Let’s continue on with our examples – kv, kn, kf  and some combinations of commands using the n parameter:

0:000> kv
ChildEBP RetAddr  Args to Child              
0019f7a0 7757f837 7757f86a 0019f7e4 00000000 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
0019f7a4 7757f86a 0019f7e4 00000000 00000000 user32!NtUserGetMessage+0xc (FPO: [4,0,0])
0019f7c0 00a71418 0019f7e4 00000000 00000000 user32!GetMessageW+0x33 (FPO: [4,0,4])
0019f800 00a7195d 00a70000 00000000 002d1e92 notepad!WinMain+0xec (FPO: [4,7,4])
0019f890 774c4911 7ffdf000 0019f8dc 7763e4b6 notepad!_initterm_e+0x1a1 (FPO: [SEH])
0019f89c 7763e4b6 7ffdf000 77707155 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
0019f8dc 7763e489 00a731ed 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x23 (FPO: [SEH])
0019f8f4 00000000 00a731ed 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])
0:000> kn
 # ChildEBP RetAddr  
00 0019f7a0 7757f837 ntdll!KiFastSystemCallRet
01 0019f7a4 7757f86a user32!NtUserGetMessage+0xc
02 0019f7c0 00a71418 user32!GetMessageW+0x33
03 0019f800 00a7195d notepad!WinMain+0xec
04 0019f890 774c4911 notepad!_initterm_e+0x1a1
05 0019f89c 7763e4b6 kernel32!BaseThreadInitThunk+0xe
06 0019f8dc 7763e489 ntdll!__RtlUserThreadStart+0x23
07 0019f8f4 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> kf
  Memory  ChildEBP RetAddr  
          0019f7a0 7757f837 ntdll!KiFastSystemCallRet
        4 0019f7a4 7757f86a user32!NtUserGetMessage+0xc
       1c 0019f7c0 00a71418 user32!GetMessageW+0x33
       40 0019f800 00a7195d notepad!WinMain+0xec
       90 0019f890 774c4911 notepad!_initterm_e+0x1a1
        c 0019f89c 7763e4b6 kernel32!BaseThreadInitThunk+0xe
       40 0019f8dc 7763e489 ntdll!__RtlUserThreadStart+0x23
       18 0019f8f4 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> kn 3
 # ChildEBP RetAddr  
00 0019f7a0 7757f837 ntdll!KiFastSystemCallRet
01 0019f7a4 7757f86a user32!NtUserGetMessage+0xc
02 0019f7c0 00a71418 user32!GetMessageW+0x33
0:000> kcn 3
 # 
00 ntdll!KiFastSystemCallRet
01 user32!NtUserGetMessage
02 user32!GetMessageW
0:000> kvn 3
 # ChildEBP RetAddr  Args to Child              
00 0019f7a0 7757f837 7757f86a 0019f7e4 00000000 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
01 0019f7a4 7757f86a 0019f7e4 00000000 00000000 user32!NtUserGetMessage+0xc (FPO: [4,0,0])
02 0019f7c0 00a71418 0019f7e4 00000000 00000000 user32!GetMessageW+0x33 (FPO: [4,0,4])

As we can see in our last three examples, it is possible to combine parameters to get the top 3 frames on a stack trace (in this example) but we can always specify more.  With that, we’ve come to the end of this post.  We’ll be taking a look at some more commands in our next post.  Until next time …

Additional Resources:

- CC Hameed

Share this post :