CodeMachine Debugger Extension DLL (CMKD.dll)


CMKD.dll is an extension DLL for the "Debugging Tools for Windows Package. 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]


!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.