Execution and stack¶
- !apc¶
List the kernel and user APCs of the selected thread, a process, or all threads.
!apc [.|*|thread|process]
Also:
apcWith no argument, the command uses the current Windows thread. With *, it lists the APCs of all threads, in a walk that has a limit.
- !findstack¶
List the threads with a stack frame that matches a symbol or module.
!findstack <symbol|module> [0|1|2]
Also:
findstackThe command walks the stack of each Windows thread, up to 64 frames, as !stacks 2 does.
module!namematches frames in that module whose function starts with name, as in WinDbg, sont!KeWaitmatches KeWaitForSingleObject and KeWaitForMultipleObjects, andnt!matches all frames in nt. A bare word matches a module by name or a function by prefix. With * or ?, the module and function are globs (nt!*Wait*). Matches ignore case. Display level 0 lists the matching threads and the number of frames that match, level 1 (the default) adds the matching frames, and level 2 shows the whole stack and marks the matching frames with *. The command cannot search a thread whose stack does not walk, such as a thread that runs on a processor while the target runs, and lists these threads after the matches.
- !for_each_frame¶
Run commands once for each frame of the current stack, with that frame selected.
!for_each_frame ["<command-string>"]
The loop uses the stack that
kshows, up to 256 frames. For each frame, ntoseye shows the frame as.framedoes and makes it the local context, as.frame Ndoes, sor,dv, and@$frameuse that frame. Then CommandString runs. To use several commands, separate them with;and put the string in quotes. After the loop, the local context is the same as before. Without CommandString, the command lists the frames and their indexes. Ctrl+C stops the loop. If the session does not permit a command (for example, a resume in a breakpoint action), the loop stops and the rest of the command line does not run. If a command only shows an error, the loop continues.
- !stacks¶
Show the state, wait reason, and top stack symbol of each thread.
!stacks [0|1|2] [filter]
Also:
stacksLevel 0 shows one frame. Levels 1 and 2 add the full stacks, with a frame limit. The optional filter matches process or stack symbols.
- !uniqstack¶
Group the threads by identical call stacks and show each unique stack once.
!uniqstack [-v] [-n] [*|process]
Also:
uniqstackWinDbg’s !uniqstack groups the user-mode stacks of the threads of the current process. This command groups the threads that the kernel schedules, using their stacks as !stacks 2 walks them: up to 64 frames, with the kernel frames first and then the user-mode frames below a system call. With no argument, the command uses the threads of the .process selection or, if no process is selected, the threads of all processes, which is the default in a kernel session. * selects all threads, and a PID, EPROCESS address, or name selects one process. Threads share a group when their frames have the same instruction pointers and the same truncation. The command shows each unique stack once, from its first thread, with the number of threads that share it and their thread IDs by process. The totals come after the groups. -n numbers the frames. -v shows how ntoseye recovered each frame (current, seed, unwind, or scan), as kv does, and this output replaces the x86 FPO data that WinDbg shows. The command does not accept the -b and -p options of WinDbg, because on x64 the first arguments go in registers, which a saved stack does not keep, and -p also needs private-symbol parameters for each frame. For one thread, use .thread and kp. Some stacks do not walk, such as the stack of a thread that runs on a processor while the target runs, and the command shows these threads in a separate list.
- .cxr¶
Select a CONTEXT record, or reset the selected context.
.cxr [address]
Without an address, .cxr goes back to the vCPU’s own registers. At a stop in the Windows hypervisor, these are the registers of the hypervisor, which do not show where NT left off.
- .ecxr¶
Select the current exception context.
.ecxr
- .exr¶
Show an EXCEPTION_RECORD64.
.exr <address|-1>
- .fnent¶
Show the function table entry and unwind info of the function that contains an address.
.fnent <address>
Shows the RUNTIME_FUNCTION that covers the address (the begin, end, and unwind info RVAs), then its unwind data. On AMD64, the unwind data is the UNWIND_INFO version, flags, prolog size, frame register, and frame offset, each unwind code with its operands, and the exception or termination handler. After a chained entry, .fnent shows the entry of each parent. On ARM64, it shows the fields of packed unwind data (flag, RegF, RegI, H, CR, frame size) and the prolog codes that they represent. For an .xdata record, it shows the header, the epilog scopes, each unwind code with the instruction that it undoes, and the exception handler. If a function table is paged out, .fnent reads it from the image file on disk.
- .frame¶
Select or show a stack frame.
.frame [/r] [frame-number]
Also:
frameN is a zero-based frame number that counts inline frames, as k does, and is decimal as k prints it, whatever the radix. /r also shows the recovered registers of the frame. When you select an inline frame, dv, ls, lsa, and local names in expressions use the function that the compiler inlined there, and the registers are those of the frame that contains it.
- .thread¶
Switch the register and stack context to a Windows thread.
.thread [ethread|tid]
For a running thread, the command switches to its vCPU. If that vCPU is halted in the Windows hypervisor (VBS), the context is the VTL0 state that the hypervisor saved, at the point where NT stopped, which
.vtlcxralso selects. If this state is not available (no hv-evmcs), the context is the registers of the vCPU. For a thread that is not running, the command selects the stack only. The memory scope is the address space of the thread’s process, sok,.frame, androf a selected frame walk the saved stack of the thread, and.trapand.cxron the thread read and walk that process. While the target runs, and always on the memory backend, the command selects the stack only for all threads, and each walk reads the thread as it is at that time. With no argument, the command goes back to the context of the current vCPU, which is the vCPU registers or, if the vCPU is halted in the Windows hypervisor, the point where NT stopped.
- .trap¶
Decode and show a _KTRAP_FRAME.
.trap [address]
Also:
trapWithout an address, .trap uses the saved trap frame of the current thread. Because a trap frame does not identify a process, ntoseye resolves a user-mode frame in the selected process, and shows a warning if the frame address is outside all modules of that process. Before you use .trap, select the thread or process that owns the frame (
.thread,.process /p).
- .vtlcxr¶
Select the VTL0 or VTL1 context that the Windows hypervisor saved for a vCPU halted in the hypervisor.
.vtlcxr [0|1]
Use this command for a vCPU that stopped in the Windows hypervisor (VBS). It reads the saved state of each VTL of the virtual processor from the Enlightened VMCS page of that VTL, lists these states, and selects the VTL0 state, so that r, k, and u show where NT left off. The VM must expose hv-evmcs, and at the first use in each boot, the command scans host RAM for the pages. The context has RIP, RSP, flags, control registers, and segment registers from the Enlightened VMCS. For the current VTL it also has the other general-purpose registers, read where the hypervisor’s VM-exit entry code saved them (experimental), and the command says why when they are missing. .vtlcxr 1 selects the saved VTL1 state instead, in the secure kernel’s address space with its symbols, which it loads first as .vtl 1 does: k walks the secure kernel’s stack from where VTL1 left off, usually its VTL return, and the context is read-only, as at a VTL1 stop: .vtlcxr goes back to the VTL0 state. Its general-purpose registers are known only when VTL1 made the hypervisor’s last exit. A stop in the hypervisor selects the VTL0 state automatically. .cxr goes back to the registers of the hypervisor, and .vtlcxr then selects the VTL0 state again. See ‘Where NT left off under the hypervisor’ in the VBS guide.
- break¶
Break in and pause VM execution.
break
- g¶
Resume VM execution.
g [address]
Also:
continueWith an address, g runs to a temporary breakpoint at that address. ntoseye checks that an instruction starts there as bp does: it refuses an address inside an instruction and warns when it cannot check. In secure-kernel code, this breakpoint uses a debug register, and ntoseye never patches the code. The .vtl 1 memory view accepts only g without an address, which leaves the view before it resumes the VM. To stop in VTL1, use
ba e1.
- gh¶
Resume and mark the current exception handled.
gh [address]
- gn¶
Resume and pass the current exception to Windows (KD only).
gn [address]
- gu¶
Run until the current function returns.
gu
Also:
finishgu stops at the return address only when the thread that you step returns from this call. Other threads that get to the address, and deeper calls of the same function, continue to run.
- kd¶
Show raw stack words from the stack pointer, with the symbol of each value that resolves to one.
kd [count]
kd is the same as
dps @$csp L<count>and shows one pointer-sized word on each line, starting at the stack pointer of the selected frame. The default count is 20 words. Use kd to find return addresses when the unwinder cannot find them.
- kn¶
Show a stack.
kn [count]
Also:
k,kb,kp,kv,kfkp adds the PDB parameter locations, kv adds the provenance of each frame, and kf adds the frame sizes. A call that the compiler inlined is a separate frame with the tag [inline], which is above the frame that contains it and shows the addresses of that frame. The inline frame has the name of the inlined function and shows the source line in that function, and its caller shows the line of the call. Frame numbers include inline frames, in decimal. After .frame, k lists the same stack and marks the selected frame with *. In kf output, the column after the frame number is the stack memory between the frame and the physical frame before it, in hex. This column is blank for the first frame, for inline frames, and where the walk moves to a different stack.
- p¶
Step over the current instruction.
p
Also:
niIf the instruction is a call, p runs to the instruction after the call and stops there only when the thread that you step returns from that call. Other threads that get to the address, and deeper calls of the same code, continue to run.
- pa¶
Step over repeatedly until execution gets to an address.
pa <address>
- pc¶
Step over until the next call instruction.
pc
- ph¶
Step over until the next branch instruction.
ph
- pt¶
Step over until the next return instruction.
pt
- r¶
Show the CPU registers, or set the value of one register.
r [register[,register]...] r <register>=<expression>
Also:
registersAs in WinDbg, r rcx, rdx, r8 shows several registers on one line. r shows a 128-bit register (xmm0, ARM64 v0) at full width, and you set it through its 64-bit halves (xmm0l/xmm0h, v0l/v0h). For a vCPU stopped in VTL1, r shows the VTL1 registers as read-only. The .vtl 1 memory view has no registers.
- t¶
Step one instruction (step into).
t
Also:
si
- ta¶
Step into repeatedly until execution gets to an address.
ta <address>
- tc¶
Step into until the next call instruction.
tc
- th¶
Step into until the next branch instruction.
th
- tt¶
Step into until the next return instruction.
tt
- wt¶
Watch and trace calls until the current function returns.
wt [count]