Analysis

!analyze

Show a first-pass crash triage report.

!analyze [-v] [-show <bugcheck-code> [p1 p2 p3 p4]] [-hang]

Also: analyze

Without -v, the command shows the short verdict: the bugcheck line, the failure signature, the culprit, the verifier and WHEA findings, and the relevant modules. -v adds the full bugcheck arguments, the faulting context, the stack, and all modules. For a DRIVER_POWER_STATE_FAILURE (0x9F), the report names what is stuck: for subtype 0x3, the blocked IRP, the driver whose stack location it is pending in, which becomes the culprit, the device stack of the PDO, and the power IRP worker threads with their stacks; for 0x4, the thread that holds the PnP lock and its stack; for 0x1, 0x2, and 0x500, the driver of the device or driver object in the parameters. -show decodes a bugcheck code when there is no crash, and for a 0x9F reads what its parameters point to in the target. -hang triages the waits on each processor. On a user-mode minidump, the report is the exception the dump was written for: its code, flags, and decoded parameters, the faulting thread and module, the stack from the exception’s context, and the first frame outside the system modules (ntdll, kernelbase, the C++ and .NET runtimes), which the signature and the culprit name; -v adds the whole stack, the exception’s registers, the faulting and culprit modules’ details, and all modules. -show and -hang need a kernel.

!blackboxbsd

Show the boot status data (bootstat.dat) the crash dump recorded.

!blackboxbsd

Whether the last boot succeeded and shut down, the boot IDs of the last successful and abnormal shutdowns, the power transition and power button state, and the feature configuration state, as WinDbg’s !blackboxbsd shows them.

!blackboxntfs

Show the NTFS slow I/O and oplock break timeouts the crash dump recorded.

!blackboxntfs

Each record shows its type and length; a slow I/O timeout its IRP, SCB, and waiting thread, and an oplock break timeout its reason (the NTFS routine), IRP, SCB, and the owning and breaking processes, as WinDbg’s !blackboxntfs shows them.

!blackboxpci

List the PCI functions pci.sys recorded in the crash dump, with their command and status.

!blackboxpci

Each function shows its bus, device, and function, its vendor and device IDs and revision, and its command and status registers with their flags as WinDbg’s !blackboxpci shows them: i (I/O), m (memory), b (bus master), v (VGA palette snoop), p (parity), s (SERR) for the command, and c (capability list), 6 (66 MHz), P (master data parity error), A (signaled target abort), S (signaled system error) for the status. WinDbg prints the command register’s value as the status value; ntoseye prints the status register’s.

!blackboxpnp

Show the PnP event the crash dump recorded.

!blackboxpnp

The PnP activity, its time, the event, whether it was in progress, the device’s problem code, the veto, and the device instance ID, as WinDbg’s !blackboxpnp shows them.

!blackboxwinlogon

Show what winlogon was doing when the crash dump was written.

!blackboxwinlogon
!chkimg

Compare the executable sections of a module with the cached on-disk image.

!chkimg [-d] [-v] [-nospec] <module>

Also: chkimg

Compares the .text, PAGE*, and INIT executable sections after applying the DIR64/HIGHLOW relocations, and skips discardable and paged-out sections. The command counts known kernel self-patches separately: import optimization, retpoline, KiPatchSelf retargets, and the addresses of the kernel VA regions that the kernel moves at boot, and, by the image’s data directories and the kernel’s symbols, the import address table the loader fills, nt!KiServiceTable, which the kernel packs at boot, and the instructions at its patch labels (SwapContext_PatchXSave) that it rewrites for the processor. With -nospec, the command does not show this breakdown and reports the self-patches as ordinary mismatches. -d prints byte diffs, up to a limit, and -v prints the results for each section.

!error

Decode an NTSTATUS, Win32, or HRESULT error code.

!error <code>

Also: !ntstatus

!gflag

Show or change nt!NtGlobalFlag, and show the PEB flags of the current process.

!gflag [-?] [[+|-]value|+abbreviation|-abbreviation]

Also: gflag

Without an argument, the command decodes nt!NtGlobalFlag and the _PEB.NtGlobalFlag of the current process and shows the bits by their GFlags names. + sets bits and - clears bits, from a value or from one flag that you name by its three-letter abbreviation (!gflag +ust). A value without + or - replaces nt!NtGlobalFlag. Each change is one 4-byte write to nt!NtGlobalFlag, the same write that ed makes, and the command does not change the PEB copy. -? lists the flags and their abbreviations.

!verifier

Show the Driver Verifier status, statistics, and verified drivers.

!verifier [module]

Also: verifier

Without a module, shows the verifier level and its decoded options, the aggregate (global) counters, and the configured driver list. The list contains the verified drivers from ViTargetDriversAvl and the configured drivers that are not loaded, from VfSuspectDriversList. With a module, shows the verified-driver counters and the image details of that driver: image, signing level, and load counts.

!wmitrace.logdump

Show the events that are still in the buffers of an ETW trace session, oldest first.

!wmitrace.logdump <logger-id|logger-name|context-address> [-t <count>]

Also: wmitrace.logdump

Reads each buffer on the GlobalList of the session: the current buffer of each processor, the buffers that wait for a flush, and the free buffers, whose events ETW delivered but did not overwrite yet. The command decodes each event record by its trace header. EVENT_HEADER is for manifest and TraceLogging providers and gives the provider GUID, event id, version, opcode, task, level, and keyword. EVENT_TRACE_HEADER is for classic providers. SYSTEM_TRACE_HEADER and PERFINFO_TRACE_HEADER are for kernel events and give the group and hook id. MESSAGE_TRACE_HEADER is for WPP and gives the message GUID and number. The command prints each event as [cpu]pid.tid::time, with its payload in hex (the first 256 bytes). The ids are hex, and the time is UTC, converted from the clock of the session. When a loaded PDB declares the trace message format (TMF) of a WPP message, the command prints the message formatted: the provider, the function, and the rendered text. If the payload does not fit its TMF, it prints the message raw, with the reason. The public Microsoft Wdf01000.pdb contains the TMF of KMDF, but for other providers the TMF is only in the private PDB of the provider, so add the PDB directory of the driver with .sympath+ and then use .reload for the driver. -t count keeps the most recent count events. If the records in a buffer stop being valid, the command reports the buffer with the offset and does not resynchronize. In a minidump, the command decodes the buffers that Windows saved in the tagged data of the dump (see !wmitrace.strdump), which hold the same events as the buffers in memory.

!wmitrace.logger

Show the configuration and counters of one ETW trace session.

!wmitrace.logger <logger-id|logger-name|context-address>

Also: wmitrace.logger

Decodes the WMI_LOGGER_CONTEXT of the session. The command shows the logger mode with its EVENT_TRACE*_MODE names, and the context flags that are set (from the PDB bitfields). It shows the buffer size, the buffer counts (minimum, maximum, allocated, free, peak), and the buffers written, then the events and buffers lost, the real-time delivery, the clock type, the start time, and the flush timer. Last come the logger thread, the consumers, and the log file. The command does not show events. To see them, use !wmitrace.logdump. In a minidump, the command shows the few fields that the tagged data of the dump records for the session: the logger mode, the buffer size, the number of buffers, the clock type, and the start time.

!wmitrace.logsave

Save the in-memory buffers of an ETW trace session as an .etl file on the host.

!wmitrace.logsave <logger-id|logger-name|context-address> <file>

Also: wmitrace.logsave

Writes an .etl file that ETW consumers such as tracerpt can open. The file starts with a header buffer that holds the logfile header event (TRACE_LOGFILE_HEADER). This event records the buffer size, the OS version and build, the processor count, the timer resolution, and the CPU speed, and also the boot time, the QPC frequency, the start reference and clock type of the session, and the session names. After the header buffer comes each buffer on the GlobalList of the session that holds events. The command seals each buffer as the logger does when it flushes a buffer, by setting the valid length and filling the rest of the buffer with 0xff. Each buffer ends after its last record that decodes, so the file holds the events that !wmitrace.logdump shows. The current buffer of a processor can end in a record that is not fully written yet. The file also includes buffers that the logger already flushed to the log file of the session, if their events are still in memory. The command leaves out an unreadable buffer, and after it writes the file, it lists each unreadable buffer and each buffer that it cut short. The time zone data records only the current bias. If a buffer is compressed, the command gives an error. In a minidump, the command saves the buffers of the tagged data of the dump (see !wmitrace.strdump), with the boot time, the QPC frequency, the timer resolution, and the CPU speed that the tagged data records.

!wmitrace.strdump

List the active ETW trace sessions, or the trace buffers of one session.

!wmitrace.strdump [logger-id|logger-name|context-address]

Also: wmitrace.strdump

Without an argument, lists all active loggers of the host silo from the EtwpLoggerContext array of nt!EtwpHostSiloState. For each logger, it shows the id, the _WMI_LOGGER_CONTEXT, the name, the logger mode, and the buffer size, and also the buffers allocated/in use/free, the buffers written, the events lost, and the log file. With a logger argument, it lists each _WMI_BUFFER_HEADER on the GlobalList of the logger. The argument is the logger id, the session name, or the _WMI_LOGGER_CONTEXT address, and the session name match ignores case. For each buffer, the command shows the state (free, logging, flush, …), the processor of the buffer, the sequence number, and the number of bytes that hold events. The command also lists the sessions that logman query -ets does not show (secure and private sessions). A minidump holds no kernel pool, so in a minidump the command lists instead the sessions that Windows saved in the tagged data of the dump (nt!EtwSecondaryDumpDataGuid, see .enumtag): those started with EVENT_TRACE_ADDTO_TRIAGE_DUMP. For each session, it shows the id, the name, the logger mode, the buffer size, the clock, the start time, and the buffers saved, which are all the buffers on the GlobalList of the session. With a logger argument, it lists these buffers, each at its offset in the tagged data.

.bugcheck

Show the bugcheck code and its four parameters.

.bugcheck

Uses the bugcheck that the stop reported. If there is none, it uses the bugcheck in nt!KiBugCheckData, as $bug_code and $bug_param1-4 do, and if there is none there, the bugcheck in the crash dump header. !analyze uses the same order.

.enumtag

List the tagged data blocks that bugcheck callbacks added to the crash dump.

.enumtag [tag]

Each block shows its GUID tag, its size, who writes it, and its first bytes; with a tag, every byte of that block. A tag that Windows writes names its global and what it holds, such as nt!PopBlackBoxPnpGuid, the PnP blackbox that !blackboxpnp decodes. For another tag, such as a driver’s KBUGCHECK_REASON_CALLBACK data, ntoseye looks for its bytes in the kernel modules’ images and names the global that holds it, when the dump has the image and its symbols are loaded. The SDK reads a block with Debugger.read_tagged.