CodeMachine Kernel Debugger Extension


CMKD.dll is an extension DLL for the "Debugging Tools for Windows Package. It implements the commands !stack, !kvas, !ptelist and !packet. CodeMachine plans to add commands useful to developers and support engineers to CMKD.dll over time. CMKD.dll automatically checks for updates and informs the user when updates are available. The user is responsible for downloading and installing the updates.

This document lists all the commands currently implemented in CMKD.dll.

Download CMKD.dll for X86 Debugger [90 KB]

Download CMKD.dll for X64 Debugger [104 KB]


!packet

The !packet command decodes and displays a network packet stored in memory.

Syntax

!packet [-v] <Address>

Description

!packet decodes the contents of a network packet in memory and displays the Ethernet, ARP, IPv4, IPv6, TCP and UDP headers. !packet requires the packet to start with the Ethernet header and expects the Ethernet, ARP/IPv4/IPv6, TCP/UDP headers to be stored contiguously in memory. !packet only processes the first contiguous part of a fragmented packet (a packet described by multiple MDLs). !packet does not process tunneled packets like IPv4 in IPv6.

The following output shows an ARP packet.

kd> !cmkd.packet fffffa800293400a
 PKT : 70-1a-04-93-f7-5d -> ff-ff-ff-ff-ff-ff arp-req 192.168.100.118 -> 192.168.100.110

kd> !cmkd.packet -v fffffa800293400a
 ETH : smac=70-1a-04-93-f7-5d dmac=ff-ff-ff-ff-ff-ff type=0806
 ARP : hwtype=Ethernet ptype=IP hwalen=6 palen=4 arp-req shwa=70-1a-04-93-f7-5d thwa=00-00-00-00-00-00 spa=192.168.100.118 tpa=192.168.100.110
The following output shows an IPv4/UDP packet.
kd> !cmkd.packet fffffa8002da6dc6
 PKT : 08-00-27-8d-2b-27 -> 00-23-69-ef-4a-28 udp 119.100.168.192:59007 -> 68.105.28.12:53 (71)(51) {85d9} 

kd> !cmkd.packet -v fffffa8002da6dc6
 ETH : smac=08-00-27-8d-2b-27 dmac=00-23-69-ef-4a-28 type=0800
 IP4 : len=71 id=332 -- off=0 UDP src=119.100.168.192 dst=68.105.28.12
 UDP : sport=59007 dport=53 len=51 sum=34265
The following output shows an IPv4/TCP packet.
kd> !packet 8508a00a  
 PKT : 52-54-00-12-35-02 -> 08-00-27-47-c6-cc tcp 70.37.131.41:80 -> 10.0.2.15:49257 (44)  --- SYN --- --- ACK --- {68ab}

kd> !packet -v 8508a00a  
 ETH : smac=52-54-00-12-35-02 dmac=08-00-27-47-c6-cc type=0800
 IP4 : len=44 id=42157 -- off=0 TCP src=70.37.131.41 dst=10.0.2.15
 TCP : sport=80 dport=49257 seq=4293419521 ack=2884144001 flags= --- SYN --- --- ACK --- win=65535 sum=26795 urp=0
The following output is truncated (does not show the UDP header), since the packet is fragmented.
kd> !cmkd.packet -v 859af816  
 ETH : smac=08-00-27-47-c6-cc dmac=33-33-00-01-00-03 type=86dd
 IP6 : trc=6 flw=0 len=30 nxt=UDP hop=1 src=fe80::a5e2:2fe9:fb12:c11f dst=ff02::1:3

Parameters

The following parameters can be passed to the "!packet" command.

<Address> <Address> is the virtual address of the packet.
-v Displays the packet headers in verbose format. Each of the layer 2, 3, 4 header information is printed on separate lines. Without the -v option all packet headers are displayed on a single lines, similar to the output generated by tcpdump.

!ptelist

The !ptelist command displays the page table entry (PTE) information for a given virtual address.

Syntax

!ptelist <StartVa> [<EndVa>] [-l <Count>] [-f Hard|Trns|Prot|PgFl|DmZr] [-c] [-p] [-v]

Description

The debugger extension command "!pte" (in kdexts.dll) does display page table entry information for a virtual address but has a few shortcomings. It does not allow changing the display format and it works on an individual virtual address instead of a range of virtual addresses. The "!ptelist" provides functionality similar to "!pte" but addresses some of the shortcomings of the !pte command.

Following is the output of the "!pte" command on the X86.

kd> !pte 478F7000  
                    VA 478f7000
PDE at C06011E0            PTE at C023C7B8
contains 0000000026FFA867  contains 000000002F6A5005
pfn 26ffa     ---DA--UWEV   pfn 2f6a5     -------UREV

Following is the output of the "!ptelist" command on X86

kd> !ptelist 478F7000  
ptelist : Using 478f7000 as VA
VA       |PPE                                 |PDE                                 |PTE                                
478F7000 |Hard Pfn=24A49 Attr=-------KREV     |Hard Pfn=26FFA Attr=---DA--UWEV     |Hard Pfn=2F6A5 Attr=-------UREV

Here are some of the features provided by the "!ptelist" command :

The !ptelist command uses abbreviations to display the states of the PTEs. Hardware PTEs are shown as Hard, Page File PTEs are displayed as PgFl, Demand Zero PTEs are displayed as DmZr, Transition PTEs are displayed as Trns and Invalid PTEs for shared pages are displayed as Prot. For such PTES the contents of the prototype PTEs are decoded and displayed automatically. When the PTE for a page has its contents zeroed out, it is displayed as Invl. If the entry at a certain translation level is invalid then all subsequent level entries are displayed as -NA-.

Parameters

The following parameters can be passed to the "!ptelist" command.

<StartVa> <StartVa> is the Virtual Address (VA) for which the !ptelist command will display PTE information. A range of VAs can be specified using <StartVa> along with the <EndVa> as well as <StartVa> along with the -l <Count> options. When used with the -c option <StartVa> is interpreted as the contents of the PTE.
<EndVa> <EndVa> is an optional parameter. When used along with <StartVa> it specifies the Virtual Address range for which "!ptelist will display PTE information. When used with the -p option <StartVa> along with the <EndVa> are interpreted as <StartPTEVa> and <EndPTEVa> respectively and is used to specify the address range from which PTE contents will be displayed. <EndVa> cannot be used with the -l flag.
    kd> !ptelist 478F7000  478FD000 
    ptelist : Using 478f7000 as VA
    VA       |PPE                                 |PDE                                 |PTE                                
    478F7000 |Hard Pfn=24A49 Attr=-------KREV     |Hard Pfn=26FFA Attr=---DA--UWEV     |Hard Pfn=2F6A5 Attr=-------UREV
    478F8000 |Hard Pfn=24A49 Attr=-------KREV     |Hard Pfn=26FFA Attr=---DA--UWEV     |Hard Pfn=1D97E Attr=-------UREV
    478F9000 |Hard Pfn=24A49 Attr=-------KREV     |Hard Pfn=26FFA Attr=---DA--UWEV     |Hard Pfn=1E5BF Attr=-------UREV
    478FA000 |Hard Pfn=24A49 Attr=-------KREV     |Hard Pfn=26FFA Attr=---DA--UWEV     |Hard Pfn=05400 Attr=-------UREV
    478FB000 |Hard Pfn=24A49 Attr=-------KREV     |Hard Pfn=26FFA Attr=---DA--UWEV     |Hard Pfn=3BA81 Attr=----A--UREV
    478FC000 |Hard Pfn=24A49 Attr=-------KREV     |Hard Pfn=26FFA Attr=---DA--UWEV     |Hard Pfn=28BC2 Attr=----A--UREV
    478FD000 |Hard Pfn=24A49 Attr=-------KREV     |Hard Pfn=26FFA Attr=---DA--UWEV     |Hard Pfn=335C3 Attr=----A--UREV
    
-v Causes !ptelist to display verbose PTE information. Index, PTE VA, PTE contents and decoded PTE contents are displayed.
    kd> !ptelist -v 478F7000  
    ptelist : Using 478f7000 as VA
    VA=478F7000
      PPE Idx=001 Va=84CBC028 Contents=0000000024A49801 Hard Pfn=24A49 Attr=-------KREV
      PDE Idx=03C Va=C06011E0 Contents=0000000026FFA867 Hard Pfn=26FFA Attr=---DA--UWEV
      PTE Idx=0F7 Va=C023C7B8 Contents=000000002F6A5005 Hard Pfn=2F6A5 Attr=-------UREV
    
-l <Count> !ptelist displays PTE information for <Count> pages starting at <StartVa>. When used with the -p option, !ptelist reads <Count> PTE contents starting at the PTE address in <StartVa>. <Count> must be a hexadecimal number.
    kd> !ptelist 0028D000  -l 3
    ptelist : Using 28d000 as VA
    VA       |PPE                                 |PDE                                 |PTE                                
    0028D000 |Hard Pfn=24AC8 Attr=-------KREV     |Hard Pfn=24A85 Attr=---DA--UWEV     |DmZr Protect=4(--W--)
    0028E000 |Hard Pfn=24AC8 Attr=-------KREV     |Hard Pfn=24A85 Attr=---DA--UWEV     |PgFl PageFile=0 Offset=624A
    0028F000 |Hard Pfn=24AC8 Attr=-------KREV     |Hard Pfn=24A85 Attr=---DA--UWEV     |Hard Pfn=00769 Attr=---DA--UWEV
    
-c Interpret <StartVa> as content of PTE, instead of a virtual address. Note that the -v, -l, -p, -f options cannot be used with the -c.
    kd> !ptelist -c 8000000024A85867
    ptelist : Using 8000000024a85867 as Contents of PTE
    Hard Pfn=24A85 Attr=---DA--UW-V    
    
-p Interpret <StartVa> as pointer to list PTEs. If Use -l option to specify count. Note that the -v, -c, -f options cannot be used with the -p.
    kd> !ptelist -p C0001468 -l 3
    ptelist : Using c0001468 as Address of PTE
    PteAddr=00000000C0001468 PteContents=0000000000000080 DmZr Protect=4(--W--)              
    PteAddr=00000000C0001470 PteContents=0000624A00000080 PgFl PageFile=0 Offset=624A        
    PteAddr=00000000C0001478 PteContents=8000000000769867 Hard Pfn=00769 Attr=---DA--UW-V
    
When used along with <EndVa>, the range <StartVa> to <EndVa> is interpreted as an address range containing PTEs.
    kd> !ptelist -p C0001468 C0001478
    ptelist : Using c0001468 as Address of PTE
    PteAddr=00000000C0001468 PteContents=0000000000000080 DmZr Protect=4(--W--)              
    PteAddr=00000000C0001470 PteContents=0000624A00000080 PgFl PageFile=0 Offset=624A        
    PteAddr=00000000C0001478 PteContents=8000000000769867 Hard Pfn=00769 Attr=---DA--UW-V
    
-f <Filter> Allows display filtering by PTE type i.e. Hardware, Transition, Prototype, PageFile, Demand Zero.
    kd> !ptelist 48340000 48352fff -f Prot
    ptelist : Using 48340000 as VA, filter as Prot
    VA       |PPE                                 |PDE                                 |PTE                                
    48344000 |Hard Pfn=278D7 Attr=-------KREV     |Hard Pfn=277D2 Attr=---DA--UWEV     |Prot Pte=879FB458 Trns Pfn=27754 Protect=3(--REC)
    48346000 |Hard Pfn=278D7 Attr=-------KREV     |Hard Pfn=277D2 Attr=---DA--UWEV     |Prot Pte=879FB468 Trns Pfn=27896 Protect=3(--REC)
    48351000 |Hard Pfn=278D7 Attr=-------KREV     |Hard Pfn=277D2 Attr=---DA--UWEV     |Prot Pte=879FB4C0 Trns Pfn=0AEF6 Protect=1(--R-C)
    48352000 |Hard Pfn=278D7 Attr=-------KREV     |Hard Pfn=277D2 Attr=---DA--UWEV     |Prot Pte=879FB4C8 Trns Pfn=276FA Protect=1(--R-C)
    

!kvas

The !kvas command displays the kernel virtual address space layout on Vista and later versions of Windows.

Syntax

!kvas [<Address>] [-t <VaTypeFilter>]

Description

The debugger extension command "!address" does not work on Vista and later versions of Windows for kernel mode targets. "!kvas" provides functionality similar to the "!address" command on both X86 and X64 targets. !kvas does not work on Windows XP, Windows 2003 or Windows 2000.

When run without any parameters "!kvas" displays the complete layout of the kernel virtual address space (KVAS). Since the layout of the KVAS is significantly different on X86 and X64 systems, the output of this command looks very different on these two CPU architectures.

Due to the static nature of KVAS on x64 the output is as follows:
0: kd> !cmkd.kvas
### Start            End                                  Length Type    
000 ffff080000000000 fffff67fffffffff     ee8000000000 ( 238 TB) SystemSpace
001 fffff68000000000 fffff6ffffffffff       8000000000 ( 512 GB) PageTables
002 fffff70000000000 fffff77fffffffff       8000000000 ( 512 GB) HyperSpace
003 fffff78000000000 fffff78000000fff             1000 (   4 KB) SharedSystemPage
004 fffff78000001000 fffff7ffffffffff       7ffffff000 ( 511 GB) CacheWorkingSet
005 fffff80000000000 fffff87fffffffff       8000000000 ( 512 GB) LoaderMappings
006 fffff88000000000 fffff89fffffffff       2000000000 ( 128 GB) SystemPTEs
007 fffff8a000000000 fffff8bfffffffff       2000000000 ( 128 GB) PagedPool
008 fffff90000000000 fffff97fffffffff       8000000000 ( 512 GB) SessionSpace
009 fffff98000000000 fffffa7fffffffff      10000000000 (   1 TB) DynamicKernelVa
010 fffffa8000000000 fffffa80035fffff          3600000 (  54 MB) PfnDatabase
011 fffffa8003600000 fffffa80c03fffff         bce00000 (   2 GB) NonPagedPool
012 ffffffffffc00000 ffffffffffffffff           400000 (   4 MB) HalReserved
The memory manager on Windows Vista and later versions of Windows on the X86 uses dynamic memory allocation in the kernel virtual address space. The address space is divided into fixed sized regions (4MB/2MB in size) and each region is used for a certain type of allocation. The following output shows regions of the kernel virtual address space being allocated for various uses:
kd> !cmkd.kvas
### Start    End        Length (  MB)    Count Type    
000 80000000 803fffff   400000 (   4)        2 BootLoaded
001 80400000 807fffff   600000 (   6)        2 SystemPtes
002 80800000 81dfffff  1800000 (  24)       11 BootLoaded
003 81e00000 821fffff   600000 (   6)        2 PagedPool
004 82200000 823fffff   400000 (   4)        1 SystemCache
005 82400000 82ffffff   e00000 (  14)        6 BootLoaded
006 83000000 833fffff   600000 (   6)        2 DriverImages
007 83400000 839fffff   800000 (   8)        3 BootLoaded
008 83a00000 845fffff   e00000 (  14)        6 PfnDatabase
009 84600000 885fffff  4200000 (  66)       32 NonPagedPool
.
.
.
077 9be00000 bfffffff 24400000 ( 580)      289 Unused
078 c0000000 c0ffffff  1200000 (  18)        8 ProcessSpace
079 c1000000 fcdfffff 3c000000 ( 960)      479 Unused
080 fce00000 fd1fffff   600000 (   6)        2 SessionSpace
081 fd200000 fd5fffff   600000 (   6)        2 Unused
082 fd600000 fddfffff   a00000 (  10)        4 SessionSpace
083 fde00000 fdffffff   400000 (   4)        1 Unused
084 fe000000 ffbfffff  1e00000 (  30)       14 SessionSpace

Parameters

The following optional parameters can be passed to the "!kvas" command to display only specific regions of the KVAS.
<Address> "!kvas <Address>" only displays the kernel virtual address region that contains <Address>. If <Address> points within an executable image, the name of the executable file is displayed. If <Address> points to the kernel mode stack of a thread, the details of the thread are displayed.
Following are some example of the "!kvas <Address>" command.
    kd> !cmkd.kvas 9b053bfc 
    kvas : Show region containing 9b053bfc
    ### Start    End        Length (  MB)    Count Type    
    000 9b000000 9b1fffff   400000 (   4)        1 SystemPtes
    Thread 84EEB6F0 [09a8.09bc] Stack 9b054000 - 9b051000

    kd> !cmkd.kvas 8285ed11
    kvas : Show region containing 8285ed11
    ### Start    End        Length (  MB)    Count Type    
    000 82400000 82ffffff   e00000 (  14)        6 BootLoaded
    Module \SystemRoot\system32\ntkrnlpa.exe 0x82604000 - 0x82a14000

    0: kd> !cmkd.kvas fffff960`002c3b40
    kvas : Show region containing fffff960002c3b40
    ### Start            End                                  Length Type    
    008 fffff90000000000 fffff97fffffffff       8000000000 ( 512 GB) SessionSpace
    Module \SystemRoot\System32\win32k.sys 0xfffff96000070000 - 0xfffff9600037f000

    0: kd> !cmkd.kvas fffff880`00f412a7
    kvas : Show region containing fffff88000f412a7
    ### Start            End                                  Length Type    
    006 fffff88000000000 fffff89fffffffff       2000000000 ( 128 GB) SystemPTEs
    Module \SystemRoot\system32\drivers\Wdf01000.sys 0xfffff88000f09000 - 0xfffff88000fad000
    
-t The "-t" option displays only those regions of KVAS that contain the VA type identified by . Note that command only works on X86 targets.
Following are some example of the "!kvas <Address>" command.

    kd> !cmkd.kvas -t SessionSpace
    kvas : Show regions containing SessionSpace
    ### Start    End        Length (  MB)    Count Type    
    000 fce00000 fd1fffff   600000 (   6)        2 SessionSpace
    001 fd600000 fddfffff   a00000 (  10)        4 SessionSpace
    002 fe000000 ffbfffff  1e00000 (  30)       14 SessionSpace

    kd> !cmkd.kvas -t PfnDatabase
    kvas : Show regions containing PfnDatabase
    ### Start    End        Length (  MB)    Count Type    
    000 83a00000 845fffff   e00000 (  14)        6 PfnDatabase
    

!stack

The !stack command displays registers based parameters passed to x64 functions.

Syntax

!stack [-u] [-r] [-p [-t]]

Description

x64 'C/C++' compiler optimization causes the first 4 parameters to functions to be passed via registers as opposed to being passed on the stack. This poses a challenge when debugging as one cannot read the values of these parameters from the call stack as one would on x86. Moreover as parameters are passed in volatile registers (P1=rcx, P2=rdx, P3=r8 and P4=r9) their values get overwritten as the function executes making it hard or sometimes impossible to retrieve the values they contained at the start of a function. It is, however, quite commonplace for these parameter registers (rcx, rdx, r8, r9) to be saved in non-volatile registers and for these non-volatile registers to be saved on the stack across function calls. The "!stack" command leverages this fact and detects the availability of parameters on the stack and accordingly attempts to retrieve them on behalf of the user. This command works both in user and kernel mode but on x64 targets only.

By default this command displays the following information similar to that displayed by debugger's native "kn" command.
Stack-PointerValue of the RSP register right after the function's prolog has finished execution.
Return-AddressAddress, the function will return to, after it completes execution.
Call SiteFunction Name and Instruction Offset. The marker (perf) indicates that function body has been subject to Basic Block Tools (BBT) optimization. For such functions the offset would be often negative (-) if the call site happens to be located at an address that is numerically lower than the start of the function

Unlike the "kvn" command the "!stack" command displays the names of BBT'd functions correctly, as shown below.
kd> !stack
.
.
1b fffffa60017181f0 fffffa6000826825 NDIS!ndisMDispatchReceiveNetBufferLists+395 (perf)
1c fffffa6001718670 fffffa60009b0fd8 NDIS!ndisMTopReceiveNetBufferLists+a085 (perf)
1d fffffa60017186b0 fffffa600084bb8d NDIS!ndisDoLoopbackNetBufferList+2b8 
1e fffffa6001718720 fffffa60009adc92 NDIS!ndisMLoopbackNetBufferLists+ed 
1f fffffa60017187a0 fffffa60009ac27a NDIS!ndisMSendNBLToMiniport-5ee (perf)
20 fffffa60017187f0 fffffa6003409fba NDIS!NdisSendNetBufferLists+9a 
.
.
.
kd> kn
. 
. 
.
1b fffffa60`017181f0 fffffa60`00826825 NDIS!ndisMDispatchReceiveNetBufferLists+0x395
1c fffffa60`01718670 fffffa60`009b0fd8 NDIS! ?? ::FNODOBFM::`string'+0xc057
1d fffffa60`017186b0 fffffa60`0084bb8d NDIS!ndisDoLoopbackNetBufferList+0x2b8
1e fffffa60`01718720 fffffa60`009adc92 NDIS!ndisMLoopbackNetBufferLists+0xed
1f fffffa60`017187a0 fffffa60`009ac27a NDIS! ?? ::FJGMBFAB::`string'+0x585
20 fffffa60`017187f0 fffffa60`03409fba NDIS!NdisSendNetBufferLists+0x9a
.
.
.

Parameters

The following optional parameters can be passed to the "!stack" command to control the information it displays. Multiple options can be specified together. These parameters affect the display of this command but not the actual execution path.
-u The "-u" option displays function unwind information. The contents displayed above are retrieved from the RUNTIME_FUNCTION, UNWIND_INFO and UNWIND_CODE structures that correspond to functions inside x64 executables. This option additionally parses the UNWIND_CODEs, locates values of the non-volatile registers saved on the stack, retrieves them and displays them.
    kd> !stack -u
    .
    .
    .
    48 fffffa600171b5c0 fffffa60009751e8 NDIS!ndisMIndicateNetBufferListsToOpen+ac (perf)
        UnwindInfo : ver=1 flag=0x0 prolog=25 codes=10 freg=none foff=0x0
        UnwindCodes     :
            [ 0] @ 19:     UWOP_SAVE_NONVOL rdi @ 0x68 (0xfffffa600171b628) = 0xfffffa8007877680
            [ 1] @ 19:     UWOP_SAVE_NONVOL rsi @ 0x60 (0xfffffa600171b620) = 0x0000000000000001
            [ 2] @ 19:     UWOP_SAVE_NONVOL rbp @ 0x58 (0xfffffa600171b618) = 0xfffffa600171b730
            [ 3] @ 19:     UWOP_ALLOC_SMALL 0x30
            [ 4] @ 15:     UWOP_PUSH_NONVOL r14 @ (0xfffffa600171b5f0) = 0x0000000000000000
            [ 5] @ 13:     UWOP_PUSH_NONVOL r13 @ (0xfffffa600171b5f8) = 0x0000000000000001
            [ 6] @ 11:     UWOP_PUSH_NONVOL r12 @ (0xfffffa600171b600) = 0x0000000000000000
    .
    .
    .
    
-r The "-r" option displays saved non-volatile registers for each stack frame. The values of only those non-volatile registers that are saved in a particular frame are displayed.
Note that debuggers ".frame /r" command also attempts to display this information but sometimes the non-volatile register information displayed by this command is incorrect.

    kd> !stack -r
    .
    .
    .
    48 fffffa600171b5c0 fffffa60009751e8 NDIS!ndisMIndicateNetBufferListsToOpen+ac (perf)
        NvRegs: rdi=0xfffffa8007877680 rsi=0x0000000000000001 rbp=0xfffffa600171b730 r14=0x0000000000000000 r13=0x0000000000000001 r12=0x0000000000000000 
    .
    .
    .
    
-p The "-p" option displays function parameters. In many situations specific parameters cannot be located, in such cases the parameter is displayed as "(unknown)".
    kd> !stack -p
    .
    .
    .
    48 fffffa600171b5c0 fffffa60009751e8 NDIS!ndisMIndicateNetBufferListsToOpen+ac (perf)
        Parameter[0] = fffffa8007877680
        Parameter[1] = fffffa8007877c00
        Parameter[2] = 0000000000000000
        Parameter[3] = 0000000000000000
    .
    .
    .
    
-t Adding the "-t" option to "-p" displays parameter tracking information. It displays how the parameters are retrieved and the source of the parameter values. This information is useful when CMKD heuristics incorrectly determine the parameter values. The user can use this information to validate the parameter values displayed by CMKD and retrieve the correct values manually.
    kd> !stack -p -t
    .
    .
    .
    48 fffffa600171b5c0 fffffa60009751e8 NDIS!ndisMIndicateNetBufferListsToOpen+ac (perf)
        Parameter[0] = fffffa8007877680 : rcx setup in parent frame by mov instruction @ fffffa60009751db from NvReg rdi which is saved by current frame
        Parameter[1] = fffffa8007877c00 : rdx saved in current frame into NvReg rsi which is saved by child frames
        Parameter[2] = 0000000000000000 : r8  saved in current frame into NvReg r13 which is saved by child frames
        Parameter[3] = 0000000000000000 : r9  saved in current frame into NvReg r12 which is saved by child frames
    .
    .
    .
    

Comments

This "!stack" command uses the following 4 methods to determine parameter values:
For more information on the mechanisms used by this extension please refer the presentation x64 Deep Dive. The implementation of this command comprises of a custom x64 disassembler, function call graph generator, function block parser, register modification tracker, stack frame and unwind information parser. Quite frequently, the x64 compiler optimizations make it hard or even impossible to retrieve parameters passed to functions either because they are not loaded from or saved into non-volatile registers or because the non-volatile registers containing their values are overwritten. In all such cases the individual parameters that cannot be determined are listed as "(unknown)". CodeMachine endeavors to improve the success rate of finding parameters by enhancing the above retrieval techniques.

!help

Displays the various commands and their respective command line parameters currently implemented in CMKD.dll.
kd> !cmkd.help
CodeMachine Debugger Extension v1.2.0.0
(c) 1999-2010 CodeMachine Inc. http://www.codemachine.com

help            : Prints this help

stack [-u] [-r] [-p [-t]] : Display Stack Trace
  -u          : Display function unwind information
  -r          : Display saved non-volatile register for each frame
  -p          : Display function parameters
  -t          : Display function parameters tracking information

kvas [<Address>] [-t <Filter>] : Display Kernel Virtual Address Space
  <Address>   : Displays only the KVA region that contains <Address>
  -t <Filter> : Displays only the KVA regions that match <Filter> (X86 only)

ptelist <StartVa> [<EndVa>] [-l <Count>] [-f <Filter>] [-c] [-p] [-v] : Display PTEs
  <StartVa>   : Display PTE for virtual address in <StartVa>
  <EndVa>     : Display PTEs for virtual addresses from <StartVa> to <EndVa>
  -l <Count>  : Display PTEs for <Count> virtual address starting at <StartVa>
  -f <Filter> : Display PTEs that match <Filter>. Where <Filter> is Hard, Trns, PgFl, DmZr, Prot or Invl
  -c          : Interpret <StartVa> as PTE content, instead of virtual address
  -p          : Interpret <StartVa> as pointer to list PTEs. Use -l option to specify count
  -v          : Display verbose PTE contents i.e. PTE Index, PTE VA, PTE contents and PTE decode

Source code for all of CodeMachine's tools is available for commercial licensing.