Legal Information

Debugging Tools for Windows

This is a preliminary document and may be changed substantially prior to final commercial release. This document is provided for informational purposes only and Microsoft makes no warranties, either express or implied, in this document. Information in this document, including URL and other Internet Web site references, is subject to change without notice. The entire risk of the use or the results of the use of this document remains with the user. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation.

Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

© 1999-2002 Microsoft Corporation. All rights reserved.

Microsoft, Microsoft Press, MSN, MS-DOS, Windows, Windows NT, CodeView, MSDN, Visual C++, Visual Studio, Win32, Win64, are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries.

Intel is a registered trademark of Intel Corporation.

Itanium is a registered trademark of Intel Corporation.

The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

Built on Friday, September 27, 2002


Introduction to Debugging

[This is preliminary documentation and subject to change.]

This documentation describes the use of four Microsoft debuggers: CDB, NTSD, KD, and WinDbg. It also describes the use of several related debugging tools, including AutoDump+, DbgRpc, DbgSrv, Dr. Watson, KDbgCtrl, Logger, LogViewer, SymChk, SymStore, and SymSrv.

These debugging tools are fully capable of running on all NT-based operating systems (Microsoft® Windows NT® 4.0, Windows 2000, Windows XP, and Windows .NET Server 2003), and running on an x86, IA-64 (Itanium), or AMD64 processor. These tools are also fully capable of debugging these Windows operating systems and processors, as well as all applications, services, and drivers that run on these systems.

All of these debugging tools are installed as part of the Debugging Tools for Windows package. Note that an additional copy of NTSD resides in the system32 directory of Windows. The version of the documentation you are reading matches the version of NTSD that was installed with the Debugging Tools for Windows package — it might not match the version of NTSD installed with Windows.

Note CDB and NTSD are virtually identical. In this documentation, whenever a reference is made to "CDB", it applies to both CDB and NTSD. When these two debuggers differ, it is noted. (See the CDB and NTSD sections for details.)

This package comes in two versions: the 32-bit version (x86 binaries) and the 64-bit version (IA-64 binaries). Since debugging always involves multiple applications or multiple operating systems, choosing between these packages is not as straightforward as it is with other applications. See Choosing Between the 32-bit and 64-bit Packages for details.

For debugging on Windows 95, Windows 98, and Windows Millennium, you should use the WDeb family of debuggers (for example, wdeb386.exe), or the Microsoft Windows System Debugger (debugger.exe). See the Windows Millennium Edition DDK for more information on these tools.

The Microsoft Visual Studio® debugger is also capable of debugging user-mode programs on all Windows operating systems. Refer to the Visual Studio documentation for details on this debugger.

This section includes:

Types of Debuggers

Terminology

Security Considerations


Types of Debuggers

This documentation describes the workings of four Microsoft® debuggers:

CDB and NTSD

KD

WinDbg


CDB and NTSD

CDB and NTSD are console applications which can debug user-mode programs. These two debuggers are nearly identical, except in the manner in which they are launched.

This documentation will use "CDB" when referring to the capabilities of both CDB and NTSD. Except as noted, all references to CDB in this documentation apply equally to NTSD. There are a few techniques that can only work properly with CDB, or can only work properly with NTSD. These differences are documented in the appropriate sections.

CDB

Microsoft Console Debugger (CDB) is a character-based console program that enables low-level analysis of Windows® user-mode memory and constructs.

CDB is extremely powerful for debugging a program that is currently running or has recently crashed ("live analysis"), yet simple to set up. It can be used to investigate the behavior of a working application. In the case of a failing application, CDB can be used to obtain a stack trace or to look at the guilty parameters. It works well across a network (using a remote access server), as it is character-based.

With CDB, you can display and execute program code, set breakpoints, and examine and change values in memory. CDB can analyze binary code by "disassembling" it and displaying assembly instructions. It can also analyze source code directly.

Because CDB can access memory locations through addresses or global symbols, you can refer to data and instructions by name rather than by address, making it easy to locate and debug specific sections of code. You can also display disassembled machine code. CDB supports debugging multiple threads and processes. It is extensible, and can read and write both paged and non-paged memory.

If the target application is itself a console application, the target will share the console window with CDB. To spawn a separate console window for a target console application, use the -2 command-line option.

NTSD

There is a variation of the CDB debugger named Microsoft NT Symbolic Debugger (NTSD). It is identical to CDB in every way, except that it spawns a new text window when it is started, whereas CDB inherits the Microsoft MS-DOS® Command Prompt window from which it was invoked.

Like CDB, NTSD is fully capable of debugging both console applications and graphical Windows programs. (The name "Console Debugger" is used to indicate the fact that CDB is classified as a console application; it does not imply that the target application must be a console application.)

Since the start command can also be used to spawn a new console window, the following two constructions will give the same results:

start cdb parameters
ntsd parameters

NTSD in the System32 Directory

Whereas CDB is only available as part of the Debugging Tools for Windows package, NTSD is available both in this package and as part of the Windows system itself. It can be found in the system32 directory of Windows.

If you are planning on using the NTSD that appears in the system32 directory, there are two important facts you should be aware of:

  • This version of NTSD cannot be used for Remote Debugging Through the Debugger.
  • This version of NTSD may not match the version of the documentation you are currently reading.

To avoid these issues, it is recommended that you use only the version of NTSD or CDB that was installed as part of the Debugging Tools for Windows package.

Controlling CDB or NTSD from the Kernel Debugger

It is possible to redirect the input and output from CDB or NTSD so that it can be controlled from a kernel debugger (either KD or WinDbg).

If this technique is used with CDB, the CDB window will appear but will not be useable for input and output. If this is used with NTSD, no console window will appear at all.

Controlling NTSD from the kernel debugger is therefore especially useful, since it results in an extremely light-weight debugger that places almost no burden on the computer containing the target application. This combination can be used to debug system processes, shutdown, and the later stages of boot up. See Controlling the User-Mode Debugger from the Kernel Debugger for details.


KD

Microsoft Kernel Debugger (KD) is a character-based console program that enables in-depth analysis of kernel-mode activity on all NT-based operating systems.

KD can be used to debug kernel-mode programs and drivers, or to monitor the behavior of the operating system itself. KD also supports multiprocessor debugging.

Typically, the KD tool will not be run on the computer being debugged. Two machines (the host computer and the target computer) are needed for kernel-mode debugging.

Most KD commands cannot be targeted to specific processes or threads, as they can in CDB, NTSD, and WinDbg.

Debugging different target platforms

KD is capable of debugging a target computer which is running on an x86, IA-64, or AMD64 platform.

The debugger will automatically detect the platform on which the target is running. You do not need to specify the target on the KD command line. The older syntax (using the name I386KD or IA64KD) is obsolete.


WinDbg

Microsoft Windows Debugger (WinDbg) is a powerful Windows-based debugging tool. It is capable of both user-mode and kernel-mode debugging.

WinDbg provides full source-level debugging for the Windows kernel, kernel-mode drivers, and system services, as well as user-mode applications and drivers.

WinDbg uses the Microsoft® Visual Studio® debug symbol formats for source-level debugging. It can access any symbol or variable from a module that has PDB symbol files, and can access any public function's name that is exposed by modules that were compiled with COFF symbol files (such as Windows .dbg files).

WinDbg can view source code, set breakpoints, view variables (including C++ objects), stack traces, and memory. Its Debugger Command window allows the user to issue a wide variety of commands.

For kernel-mode debugging, WinDbg requires two machines (the host computer and the target computer). Kernel debugging is only supported on NT-based Windows operating systems.

WinDbg also supports various remote debugging options for both user-mode and kernel-mode targets.

WinDbg is the graphical-interface counterpart to CDB / NTSD and KD.


Terminology

This section includes:

General Terms

Debugging Terms


General Terms

The following is a list of frequently-used Windows terms:

Call Stack
A fundamental data structure which is used to hold volatile data. The most common use of the call stack is to keep track of function calls and the parameters passed into these functions. The call stack can simply be referred to as the stack when there is no danger of confusion with other stack objects.
Checked Build
The debug version of the operating system. See Free and Checked Build .
Debug Build
See Checked Build .
Exception
An error condition resulting from the execution of a particular machine instruction. Exceptions can be hardware or software-related errors.
Free Build
The retail version of the operating system. See Free and Checked Build .
I/O Request Packet (IRP)
A data structure used to represent an I/O request and control its processing. The IRP structure consists of a header and one or more stack locations.
Interrupt
A condition that disrupts normal command execution and transfers control to an interrupt handler. I/O devices requiring service from the processor usually initiate interrupts.
Interrupt Request Level (IRQL)
The priority ranking of an interrupt. A processor has an IRQL setting that threads can raise or lower. Interrupts that occur at or below the processor's IRQL setting are masked and will not interfere with the current operation. Interrupts that occur above the processor's IRQL setting take precedence over the current operation.
Kernel
The kernel is the portion of the operating system that manages and controls access to hardware resources. It performs thread scheduling and dispatching, interrupt and exception handling, and multiprocessor synchronization.
Kernel Mode
The processor access mode in which the operating system and privileged programs run. See details .
Nonpaged Pool
A portion of system memory that will not be paged to disk.
Page Table
A process-specific table that maps virtual memory addresses to physical memory addresses.
Page Table Entry (PTE)
An item in the page table.
Paged Pool
A portion of system memory that can be paged to disk. (Note that this term does not only refer to memory that actually has been paged out to the disk — it includes any memory that the operating system is permitted to page.)
Paging
A virtual memory operation in which the memory manager transfers pages from memory to disk when physical memory becomes full. A page fault occurs when a thread accesses a page that is not in memory.
Retail Build
See Free Build .
Register
A very fast temporary memory location in the CPU.
Stack
A data structure, consisting of a series of memory locations and a pointer to the initial location (also referred to as top of the stack). An x86 processor provides instructions for pushing and popping values on to and off the stack. The stack used most often in debugging is the call stack, which is sometimes referred to as "the stack." See call stack.
Thread
An executable entity that belongs to only one process. A thread is composed of a CPU state, user and kernel-mode stacks.
User Mode
The processor access mode in which applications run. See details .

Free Build and Checked Build

Two different builds of each NT-based operating system exist:

  • The free build (or retail build) of Windows is the end-user version of the operating system. The system and drivers are built with full optimization, debugging asserts are disabled, and debugging information is stripped from the binaries. A free system and driver are smaller and faster, and it uses less memory.
  • The checked build (or debug build) of Windows serves as a testing and debugging aid in the developing of the operating system and kernel-mode drivers. The checked build contains extra error checking, argument verification, and debugging information that is not available in the free build. A checked system or driver can help isolate and track down driver problems that can cause unpredictable behavior, result in memory leaks, or result in improper device configuration.

Although the checked build provides extra protection, it consumes more memory and disk space than the free build. System and driver performance is slower for the following reasons:

  • The executables contain symbolic debugging information.
  • Additional code paths are executed due to parameter checking and output of diagnostic messages for debugging purposes.

User Mode

Applications and subsystems run on the computer in user mode. Processes that run in user mode do so within their own virtual address spaces. They are restricted from gaining direct access to many parts of the system, including system hardware, memory that was not allocated for their use, and other portions of the system that might compromise system integrity. Because processes that run in user mode are effectively isolated from the system and other user-mode processes, they cannot interfere with these resources.

User-mode processes can be grouped in the following categories:

  • System Processes.

    These perform important functions and are integral part of the operating system. System processes include such items as the logon process and the session manager process.

  • Server Processes.

    These are operating system services such as the Event Log and the Scheduler. They can be configured to start automatically at boot time.

  • Environment Subsystems.

    These are used to create a complete operating system environment for the applications. Windows provides the following three environments: Win32, POSIX, and OS/2.

  • User Applications.

    There are five types: Win32®, Windows 3.1, MS-DOS®, POSIX, and OS/2.

Kernel Mode

Kernel-mode code has permission to access any part of the system, and ise not restricted like user-mode code. It can gain access to any part of any other process running in either user mode or kernel mode.

Performance-sensitive operating system components run in kernel mode. In this way they can interact with the hardware and with each other without the overhead of context switch. All the kernel-mode components are fully protected from applications running in user mode. They can be grouped as follows:

  • Executive.

    This contains the base operating system components such as memory management, process and thread management, security, I/O, interprocess communication.

  • Kernel.

    This performs low-level functions such as thread scheduling, interrupt and exception dispatching, and multiprocessor synchronization. It also provides a set of routines and basic objects used by the Executive to implement higher-level semantics.

  • Hardware Abstraction Layer (HAL).

    This handles all direct interface to hardware. It thus isolates the Kernel, device drivers, and Executive from platform-specific hardware differences.

  • Window and Graphics Subsystem.

    This implements the graphical user interface (GUI) functions.

The possibility of data corruption or system damage is much greater with kernel-mode process errors. When a process erroneously accesses a portion of memory that is in use by another application or by the system, the lack of restrictions on kernel-mode processes forces Windows to stop the entire system. This is referred to as a blue screen or bug check.

Malfunctioning hardware devices or device drivers with bugs, which reside in kernel mode, are often the culprits in bug checks. A bad SCSI adapter, a malfunctioning drive controller, or defective memory chips can corrupt memory contents, altering program pointers so they attempt to access an incorrect address in memory.


Debugging Terms

The following is a list of frequently-used debugging terms:

Blue Screens, Bug Checks, and Bug Check Codes

When Windows® encounters hardware problems, inconsistencies within data necessary for its operation, or other severe errors, the operating system shuts down and displays error information on a blue-character screen.

This shutdown is known variously as a bug check, kernel error, system crash, stop error, or, occasionally, trap. The screen display itself is referred to as a blue screen or stop screen. The most important information on the screen is a message code which gives information about the crash; this is known as a bug check code or stop code.

WinDbg or KD can configure the system so that a debugger is automatically contacted when such an error occurs. Alternatively, the system can be instructed to automatically reboot in case of such an error.

boot.ini

On x86 computers, the boot.ini file enables you to set debugging options when the system boots.

Crash Dump File

You can configure the system to write information to a crash dump file on your hard disk whenever a bug check occurs. The file contains information the debugger can use to analyze the error. There are several different types of crash dump files. For details, see Crash Dump Files.

Debugging Session

The debugging session is the actual act of running a software debugging program, such as WinDbg, KD, or CDB, against a computer that has a crashed software component, system service, application, or operating system. The debugging session can also be run against a saved memory dump file for analysis.

Host Computer

The host computer is the machine that runs the debugging session. In a typical two-system debugging session, the host can be any computer which can be connected to the target computer.

Kernel Error

See Bug Check.

Local Debugging

This refers to a debugging session in which the debugger and the application to be debugged reside on the same computer.

Remote Debugging

Remote debugging is the practice of using a remote connection to perform debugging.

Since user-mode debugging is usually done on one machine, remote user-mode debugging requires two machines. The server is the computer with the application being debugged and the debugger. The client is the computer which is controlling the debugging session remotely.

Since kernel-mode debugging is usually done on two machines, remote kernel-mode debugging requires three machines. The target computer is the computer being debugged. The server is attached to the target; it contains the kernel-mode debugger. The client is the computer which is controlling the session remotely.

There are two ways to perform remote debugging:

  1. Remote debugging through the debugger is extremely powerful, but requires that both the client and the host have matching debugger binaries.
  2. Remote debugging through the remote.exe tool is more lightweight, but less powerful. See Remote Debugging for full details.

Stop Code

See Bug Check Code.

Stop Error

See Bug Check.

Stop Screen

See Blue Screen.

Symbol Files and Symbol Trees

Usually, when code is compiled, one of two versions of the executable file can be created: a debug (also known as checked) version, or a non-debug (also known as free) version. The checked version contains extra programming code that enables a developer to debug problems, but this means a larger and possibly slower executable file. The free version of the executable file is smaller and runs at a normal speed, but cannot be debugged.

Windows combines the speed and smaller size of free versions with the debugging capabilities of the checked versions. All executable files, drivers, dynamic-link libraries, and other program files in Windows are the free versions. However, each program file has a corresponding symbol file, which contains the debug code that is normally part of the checked file. These symbol files are on the Windows product CD. The directory tree containing these symbol files is referred to as a symbol tree.

All of the tools used to debug Windows or interpret memory dump files require access to the symbol tree containing the symbol files for the version of Windows running at the time of the error.

System Crash

See Bug Check.

Target Application

The application that is failing and will be analyzed using the debugger. Sometimes referred to as the debuggee.

Target Computer

The target computer is the machine that has experienced the failure of a software component, system service, an application, or of the operating system. This is the computer that needs to be debugged and is the focus of the debugging session. This can be a computer located within a few feet of the computer on which you run the debugging session, or it can be in a completely different location. Sometimes referred to as the debuggee.

Transport Layer

This controls communication between the host and target computers during remote debugging.

Trap

See Bug Check.


Installation and Setup

This section includes:

Debugger Installation

Kernel-Mode Setup

User-Mode Setup


Debugger Installation

Debugging Tools for Microsoft® Windows® can be installed from the Customer Support Diagnostics CD, the Platform SDK, the Windows DDK, or the Web.

Each of these sources supplies the same package, including the debuggers WinDbg, KD, CDB, and NTSD, associated modules such as DbgHelp and SymSrv, and the dump file tool Autodump+. Several extension libraries are also available.

This package also contains several additional tools, including remote.exe, SymStore, SymChk, DbgRpc, Logger, LogViewer, and KDbgCtrl. If you do not wish to install these tools, you should choose Custom Install and then deselect Helpful Tools.

NTSD is also installed from these sources. Note that another copy of NTSD resides in the system32 directory of Windows NT 4.0, Windows 2000, Windows XP, and Windows .NET Server 2003. This documentation matches the version of NTSD included in this package — it might not match the version of NTSD that was installed with Windows.

This section includes:

Choosing Between the 32-bit and 64-bit Packages

Installing from the Customer Support Diagnostics CD

Installing from the Platform SDK

Installing from the Windows DDK

Installing from the Web


Choosing Between the 32-bit and 64-bit Packages

The Debugging Tools for Windows package is available in two different versions: 32-bit and 64-bit.

Use the following rules to determine which version you need to use.

If your host computer uses an x86 processor, always use the 32-bit package.

If your host computer uses an IA-64 processor, then the following rules apply:

  • If you are analyzing a dump file, and the dump file was made on a Windows XP or Windows .NET Server 2003 operating system, you can use either package. (It doesn't matter whether the dump file is a user-mode dump file or a kernel-mode dump file, and it doesn't matter whether it was made on an x86 or an IA-64 platform.)
  • If you are analyzing a dump file, and the dump file was made on a Windows NT® or Windows 2000 operating system, you should use the 32-bit package. (It doesn't matter whether the dump file is a user-mode dump file or a kernel-mode dump file)
  • If you are performing live kernel-mode debugging, and the target computer is running Windows XP or Windows .NET Server 2003, you can use either package. (This applies to both x86 and IA-64 targets.)
  • If you are performing live kernel-mode debugging, and the target computer is running Windows NT or Windows 2000, you should use the 32-bit package.
  • If you are performing live user-mode debugging, always use the 64-bit package. (It doesn't matter whether the target is a 64-bit application or a 32-bit application.)

Debugging an Alpha Target

Debugging Tools for Windows no longer runs on or debugs the Alpha (RISC) processor. If you need to debug an Alpha computer running Windows NT 4.0, you should use Debugging Tools for Windows version 2.0.16.0 — released January 2001 — or any earlier version.


Installing from the Customer Support Diagnostics CD

To install Debugging Tools for Windows from the Customer Support Diagnostics CD, insert the disk in your CD-ROM drive. You will be presented with a number of items you can install, including the debuggers, checked-build symbols, and free-build symbols.

Follow the links to install the desired debuggers and debugging tools.


Installing from the Platform SDK

To install Debugging Tools for Windows from the Platform SDK, use the Custom Install option. Select the Debugging Tools for Windows item.

When the Platform SDK installation is complete, look in Start | Programs | Microsoft Platform SDK | Install Debugging Tools for Windows. Select this command, and the actual Debugging Tools for Windows installation program will run.

After the installation is complete, the debugger shortcuts can be found in Start | Programs | Debugging Tools for Windows.


Installing from the Windows DDK

To install Debugging Tools for Windows from the Windows DDK, look for the link on the DDK installation splash screen. This will let you install the debuggers to a location of your choice.

After the installation is complete, the debugger shortcuts can be found in Start | Programs | Debugging Tools for Windows.


Installing from the Web

To download the latest version of the Debugging Tools for Windows, go to the Debugging Tools for Windows Web site at http://www.microsoft.com/ddk/debugging and follow the instructions.

The Debugging Tools for Windows package is updated frequently. Updating your tools from the Web site assures that you have the most powerful debugging tools possible.


Kernel-Mode Setup

This section includes:

Configuring Hardware for Kernel-Mode Debugging

Configuring Software for Kernel-Mode Debugging


Configuring Hardware for Kernel-Mode Debugging

This section includes:

Target Computer and Host Computer

Setting Up a Null-modem Cable Connection

Setting Up a 1394 Cable Connection

Testing the Connection


Target Computer and Host Computer

Kernel-mode debugging requires a target computer and a host computer. The target computer is used to run the kernel-mode program. The host computer is used to run the debugger.

The picture below shows the typical Microsoft® Windows® setup used to perform kernel debugging and diagnose system failures.

Typical Windows Debugging Setup

This picture illustrates the typical setup. However, the current versions of KD and WinDbg, which have been installed with this documentation, are extremely flexible:

  • They can debug a target computer that is running Windows NT® 4.0, Windows 2000, Windows XP, or Windows .NET Server 2003.
  • They can debug a target computer that is running on an x86 platform, an IA-64 platform, or an AMD64 platform.
  • They can be launched from a host computer that is running Windows NT 4.0, Windows 2000, Windows XP, or Windows .NET Server 2003.
  • They can be launched from a host computer that is on an x86 platform, an IA-64 platform, or an AMD64 platform.

The target computer and host computer do not have to be using the same platform or the same version of Windows.

Kernel debugging does not require specific combinations of the free or checked builds. It is possible to debug a free system from a free or checked system or to debug a checked system from a free or checked system. However, there is generally no reason for the host computer to run the slower checked build.

Note If you are running the debuggers from an IA-64 host computer, you should make sure you are using the correct version of the binaries. See Choosing Between the 32-bit and 64-bit Packages for details.


Setting Up a Null-modem Cable Connection

When the host computer is at the same location as the target computer, or when you need to put a local host computer with remote access server (RAS) capabilities between the target and a remote host, the two computers must be connected with either debug (null-modem) cables or 1394 (fire-wire) cables.

This section describes how to hook up a debug cable. See Setting Up a 1394 Cable Connection if you are using a 1394 cable.

Null-modem cables are serial cables that have been configured to send data between two serial ports. They are available at most computer stores. Do not confuse null-modem cables with standard serial cables, which do not connect serial ports.

If you are dialing straight into the target system's modem, debugging a failed user-mode process on the same computer, or analyzing a dump file, a null-modem cable is not needed.

The procedure for setting up the null-modem cable is the same on both the host and target computers.

COM Ports

The default serial port for debug output from the target computer is the highest enumerated port (usually COM2). This can be changed by setting the debugport option. For details, see Configuring Software on the Target Computer.

The default serial port for debug input to the host computer is COM1. This can be changed by setting the _NT_DEBUG_PORT environment variable. For details, see Configuring Software on the Host Computer.

Null Modem Cable Construction

If you do not have access to a null-modem cable, or if you prefer to customize your hardware wiring, the following information may be useful.

A standard, commercially available null-modem cable has the following configuration:

  • Transmit Data connected to Receive Data
  • Receive Data connected to Transmit Data
  • Ground connected to Ground

For 9-pin and 25-pin D-subminiature connectors (known as db9 and db25, respectively), the hardware protocol is as follows: the cable must connect Receive Data (RXD) to Transmit Data (TXD), TXD to RXD, and Ground (GND) to GND. In addition, each side of the cable should connect Data Terminal Ready (DTR) to Data Set Ready (DSR), and Request to Send (RTS) to Clear to Send (CTS).

The following table shows the pin numbers of the pins that should be connected:

9-pin Connector | 25-pin Connector
2 (RXD) | 2 (TXD)
3 (TXD) | 3 (RXD)
4 (DTR) | 6 (DSR)
5 (GND) | 7 (GND)
6 (DSR) | 20 (DTR)
7 (RTS) | 5 (CTS)
8 (CTS) | 4 (RTS)

The debugger on the host does not depend on any control pins (such as DTR, DSR, RTS, or CTS). However, you might need to put a jumper in the connectors on both ends of the cable from DTR to DSR and from RTS to CTS, as follows:

Connector | Jumpers
db9 | From pin 4 (DTR) to pin 6 (DSR) From pin 7 (RTS) to pin 8 (CTS)
db25 | From pin 20 (DTR) to pin 6 (DSR) From pin 5 (RTS) to pin 4 (CTS)

Connect the null-modem cable to a serial port on both the host and the target computers.


Setting Up a 1394 Cable Connection

When the host computer is at the same location as the target computer, or when you need to put a local host computer with remote access server (RAS) capabilities between the target and a remote host, the two computers must be connected with either debug (null-modem) cables or 1394 (fire-wire) cables.

Kernel debugging through a 1394 cable is not supported on all systems. The target computer must be running either Windows XP or Windows .NET Server 2003, and the host computer must be running one of these systems as well (not necessarily the same Windows version as the host, however).

The target computer and host computer will each have a 1394 adapter. Plug the 1394 cable into any port on the target computer, and into any port on the host computer. The choice of port does not matter, and it does not affect the channel number that will be used during software setup.

If you are using a debug cable instead of a 1394 cable, see Setting Up a Null-modem Cable Connection.


Testing the Connection

The null-modem connection between the host and target systems should be confirmed as valid prior to starting the debugger.

To test the null-modem connection

  1. On the host computer, click the Start button, point to Programs, then point to Accessories, then point to Communications, then click HyperTerminal. If HyperTerminal is not installed, install it from the product CD-ROM using Add/Remove Programs from Control Panel.
  2. In the Connection Description dialog box, enter a name for the new connection. (The name doesn't matter.)
  3. In the Connect To dialog box, click on the Connect using drop down list. Select the COM port corresponding to the port to which the null-modem cable is connected on this machine.
  4. Accept the defaults for the COM port properties in the next dialog box.
  5. Repeat steps 1 through 4 for the target computer.
  6. HyperTerminal is now open and ready for testing. Type in a string of characters on the host system. If the null-modem cable is properly installed and the correct COM ports were chosen within HyperTerminal on both systems, the string of characters typed in on the host will be displayed in the HyperTerminal window of the target system.

If the keystrokes on the host do not appear on the target system, confirm the cable is snugly plugged into both systems. Also be sure that the cable is a null-modem cable as opposed to a pass-though serial cable.

If the cable checks out, then the likely problem is with the COM ports. Create a new connection in HyperTerminal on the target system using an alternative COM port following steps two through five and retest. If the problem is not resolved, try changing the COM port on the host system. If the problem persists, change the target system's COM port setting back to the original setting and retest. Eventually the correct configuration will be made and the test will succeed.

If after several iterations of reconfiguring COM ports and finally getting it to work, you forget which computer is using which port, click the File menu in HyperTerminal and choose Properties to reveal the current COM port setting for the debug session.


Configuring Software for Kernel-Mode Debugging

This section includes:

Configuring Software on the Target Computer

Configuring Software on the Host Computer


Configuring Software on the Target Computer

The target computer must be configured to enable kernel-mode debugging before any debugging can be done.

Typically, this configuration change is not implemented until a recurring problem arises, as the configuration permanently reserves one COM port for the debugger. However, for systems that must always be available for interactive debugging, this configuration change can be implemented at any time. This configuration should also be made in advance if you wish to be prepared for the eventuality of a bug check.

When kernel debugging is enabled for an operating system on a dual-boot machine, "[debugger enabled]" will be displayed in the description of that operating system on the boot menu.

The target computer's kernel debugging settings can be changed after boot by using the KDbgCtrl utility.

This section includes:

Configuring an x86 Target

Configuring an IA-64 Target

Using KDbgCtrl


Configuring an x86 Target

On an x86 computer, the kernel debugger is enabled through the boot.ini file. You must edit this file to activate the target system for kernel debugging.

If you want to enable kernel debugging and are not interested in other details of the boot.ini file, skip to Editing the boot.ini File for Debugging.

This section includes:

Overview of the boot.ini File

Boot.ini Parameters

Sample boot.ini Files

Editing the boot.ini File for Debugging

Resolving x86 Boot Problems


Overview of the boot.ini File

The boot.ini file is used for all NT-based Microsoft® Windows® operating systems running on x86 processors. It controls the boot options, the debug options, and other features.

A typical boot.ini file looks something like this:

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Microsoft Windows XP Professional" /fastdetect
multi(0)disk(0)rdisk(0)partition(3)\WINDOWS="Microsoft Windows 98"

Under the [operating systems] section, each operating system in your boot options menu will be listed. The parameters following each operating system describe the special features that this Windows version will be started with.

To identify which operating system corresponds to which line, you will have to examine the partition number and the operating system starting directory.

During the boot process, all these operating systems are displayed. If the user does not select one system after a certain amount of time, the default choice is automatically selected. The default choice is listed after the word default=, and the time limit (in seconds) is listed after the word timeout=.

Note The default operating system listing only includes the root directory, not the additional parameters. After the timeout, the boot process will locate the first line in the [operating systems] section that matches this directory, and launch that operating system.

You can modify the boot.ini file in the following ways:

  • Change the parameters for one of the operating systems listed
  • Duplicate a line specifying an operating systems, and change the parameters on the duplicate line
  • Change the quoted string (this string is displayed in the OS loader options during boot, unless there is only one operating system listed)
  • Change the default operating system
  • Change the timeout value


Boot.ini Parameters

The following table lists the parameters that can be used in the boot.ini file.

Parameter | Description
/nodebug | Disables kernel debugging, even if a bug check occurs. This is the default. If you specify nodebug, then debugport, baudrate, and crashdebug are ignored.
/debug | Allows the computer to be debugged. If a kernel debugger attaches to this computer it will be given control over its execution. If a bug check occurs, or if a kernel-mode program attempts to communicate with a debugger, the computer will pause and wait for a response from a kernel debugger. The debug option should be used if you are performing local kernel debugging. If you are debugging over a COM port, you should use debugport and baudrate instead. If you are debugging over a 1394 cable, you should use debugport and channel instead.
/debugport=Port | Specifies the serial port to be used by the kernel debugger. If you are using a debug cable, Port can be COM1, COM2, or any other valid COM port. If you are using a 1394 cable, Port should be 1394. If this parameter is omitted, the debugger defaults to the highest enumerated port (usually COM2). It is best not to select the /debugport parameter on a computer that you do not intend to debug, because this will tie up a COM port unnecessarily.
/channel=Channel | Specifies the 1394 channel number to be used. Valid channel numbers are 1 through 62. Channel must match the channel number used by the host computer, but does not depend on the physical 1394 port chosen on the adapter.
/crashdebug | Causes the code that communicates with a kernel debugger to be loaded during boot but swapped out to the paging file after boot. As a result, a kernel debugger cannot break into this computer unless a bug check occurs.
/baudrate=BaudRate | Sets the speed that the kernel debugger uses, in bits per second (bps). Baud rates of 9600, 19200, 38400, 57600, and 115200 are supported. Your hardware will determine how fast your connection can run, but in most cases there should not be any communication problems at 57600 bps. The default rate is 19,200 bps.
/kernel=KernelFile | Specifies the Windows kernel file to use. This file must be located in the %SystemRoot%\system32 directory. Its filename must conform to 8.3-character format. The default is ntoskrnle.exe for systems with less than 4 GB of memory, or ntkrnlpa.exe for systems with more than 4 GB of memory. This parameter should only be changed if you have deliberately installed a different kernel. (This can be useful if you are testing a kernel patch, or if you have made a partial checked build installation.)
/hal=HALFile | Specifies the hardware abstraction layer (HAL) file to use. This file must be located in the %SystemRoot%\system32 directory. Its filename must conform to 8.3-character format. The default is hal.dll. This parameter should only be changed if you have deliberately installed a different HAL. (This can be useful if you are testing a HAL patch, or if you have made a partial checked build installation.)
/maxmem=SizeInMB | Specifies the amount of memory to be made available to the system. For example, you could restrict a 128 MB computer to 32 MB.
/PAE | Allows the operating system to support Physical Address Extension (PAE).
/basevideo | Causes the system to use VGA video mode.
/sos | Causes the system loader to display the names of the drivers as they load while Windows is booting.

You should use /debugport and /baudrate when debugging over a debug cable, /debugport and /channel when debugging over a 1394 cable, and /debug when performing local kernel debugging.


Sample boot.ini Files

The following boot.ini file can be used to debug the computer with a null-modem cable connection:

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Microsoft Windows XP Professional" /fastdetect /debugport=com1 /baudrate=57600

The following boot.ini file can be used to debug the computer with a 1394 cable connection. Here there has been a triple-boot option created. Windows 2000 is installed on partition one. Windows XP is installed on partition three; it can be selected in debug mode or in standard mode. The default option specifies partition three. Since there are two operating system specifications for this partition, the first of these two lines becomes the default setting (in this case, the non-debug version):

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(3)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(3)\WINNT="Microsoft Windows XP Professional" /fastdetect
multi(0)disk(0)rdisk(0)partition(3)\WINNT="Microsoft Windows XP Professional" /fastdetect /debugport=1394 /channel=44
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Microsoft Windows 2000 Professional" /fastdetect

The following boot.ini file will boot Windows NT 4.0 in a simulated 16 MB environment, with kernel debugging enabled on COM1, and communicating at 19200 baud:

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\NT="Windows NT" /maxmem=16 /debugport=COM1 /baudrate=19200

The following file can be used if you have created a partial checked build. Two operating system lines appear; the first boots the free build, and the second boots the partial checked build. The display string for the checked option has been edited so that the difference will be clear on the OS loader options screen.

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Microsoft Windows XP Professional" /fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Windows XP Checked" /fastdetect /kernel=ntoskrnl.chk /hal=halacpi.chk

The file names used with the /kernel and /hal parameters should match those used when you created the partial checked build. For details, see the Windows DDK.


Editing the boot.ini File for Debugging

Use the following procedure to make changes to a boot.ini file on an x86 computer.

To Set the Startup Options in the boot.ini File

  1. Start Windows Explorer. Go to Tools | Folder Options | View. Make sure that Show Hidden Files and Folders is selected, and Hide File Extension for Known File Types is cleared.
  2. Go to the root directory of the boot volume of your computer (on single-boot machines, usually C:\).Right-click on boot.ini. Select Properties, and remove the read-only attribute of this file. Click OK.
  3. Double-click the file icon to start Notepad with boot.ini loaded.
  4. If you are using an MS-DOS® Command Prompt window, use the following commands instead of steps 1, 2, and 3:
    c:
cd \
attrib -s -h -r boot.ini
notepad boot.ini
  5. The boot.ini file will look similar to this:
    [boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Microsoft Windows 2000 Professional" /fastdetect
  6. Locate the startup option that you normally use. In this example, there is only one startup option (line five). On dual-boot machines, there will be one startup option for each boot option. Make a copy of this line and add it below the existing line.
  7. If you are using a debug cable, add the following text at the end of the new line:
    /debugport=COMX /baudrate=BaudRate

    The value of COMX specifies the COM port being used on the target computer, and BaudRate specifies the baud rate to be used for the kernel connection. Baud rates of 9600, 19200, 38400, 57600, and 115200 are supported. Your hardware will determine how fast your connection can run, but in most cases there should not be any communication problems at 57600 bps.

  8. If you are using a 1394 cable, add the following text at the end of the new line:
    /debugport=1394 /channel=ChannelNumber

    The value of ChannelNumber specifies the 1394 channel to be used. This can be any number between 1 and 62 that is not already in use. It must match the channel number used by the host computer, but does not depend on the physical 1394 port chosen on the adapter.

  9. Save the boot.ini file and quit Notepad. (You do not have to restore the original file attributes.)
  10. Shut down the computer and restart Windows.
  11. When the boot menu appears, the line marked "Debugging Enabled" is the choice which allows kernel debugging.

There are other parameters that can be of use in this file as well. See Boot.ini Parameters for a full list.

Loss of a Port Reserved for Debugging

Once kernel debugging is enabled through a COM port, Windows removes this port from the system device list. Control Panel will either not list this port at all, or will show "Not enough resources to use this port." This does not represent any malfunction.

Therefore, if you wish to test the null-modem connection using Hyperterminal or another communication program, you must do so after connecting the cable but before enabling debugging through the boot.ini file.


Resolving x86 Boot Problems

To enable kernel debugging on an x86 computer, you must first open and edit the boot.ini file. (See Editing the boot.ini File for Debugging.) But if the target computer is unable to complete its boot process, this file cannot be accessed in the normal manner.

If the target computer consistently generates a bug check ("blue screen") during the startup process, or does not keep running long enough for you to edit the boot.ini file to enable the kernel debugger, you can try these options:

  • Early in the process of starting Windows, a character-mode menu displays the operating system choices. Press the F8 key at that time to display the Windows Advanced Options Menu, and choose to start the computer in Safe Mode. Safe Mode loads only the minimum required drivers and system services during the startup of Windows. If the computer does successfully startup in Safe Mode, you can use Notepad to edit boot.ini. For more information about Safe Mode, see General Troubleshooting Tips.
  • If your boot partition is formatted as file allocation table (FAT), you can start MS-DOS® from a bootable floppy disk and use an MS-DOS–based editor to edit boot.ini. You can also copy the file to a floppy disk, take it to another computer to make the edits, and copy the modified version over the original on the target computer.
  • If your boot partition is formatted as FAT32, you can use a Startup floppy disk from Windows 95 or Windows 98 and use an MS-DOS-based editor to edit boot.ini. You can also copy the file to a floppy disk, take it to another computer to make the edits, and copy the modified version over the original on the target computer. (Since the boot.ini file is hidden and read-only, you will have to change these attributes before you can edit it. You can see the file by using the dir /ah command, and change the file's attributes by issuing an attrib -r -s -h boot.ini command.)
  • If your boot partition is formatted as NTFS file system, you have two choices.
    1. Restart your computer from either of the three Windows installation floppy disks or the product CD-ROM. Once you get to the Welcome screen in the Windows setup, press the F10 key to start the Recovery Console tool. The Recovery Console is a troubleshooting tool that enables access to NTFS disks from a command prompt. From the Recovery Console prompt, type SET AllowRemovableMedia = TRUE and press Enter. Use the Copy command to copy the boot.ini to a floppy disk. Take the disk to another computer to make the necessary edit, then use Copy command again to copy the modified version over the original on the target computer.
    2. You can also install a second copy of Windows on a different partition and start the computer from the new installation. (You cannot gain access to files on an NTFS partition from MS-DOS, Windows 95, or Windows 98.) Then you can use Notepad to edit the original installation's boot.ini.
  • If you previously created a Windows boot recovery disk for the computer that has the problem, you can use this disk on another computer to edit the boot.ini file, and then start the target computer.


Configuring an IA-64 Target

On an IA-64 (Itanium-based) computer, the kernel debugger is enabled through certain OsLoadOptions parameters in the non-volatile RAM (NVRAM). You must edit the NVRAM to activate the target system for kernel debugging.

If you want to enable kernel debugging and are not interested in other details of NVRAM, skip to Editing the NVRAM Settings for Debugging.

This section includes:

OsLoadOptions Parameters

Editing the NVRAM Settings for Debugging


OsLoadOptions Parameters

The following table lists the boot options that can be used in the OsLoadOptions line of the NVRAM.

Parameter | Description
/nodebug | Disables kernel debugging, even if a bug check occurs. This is the default. If you specify nodebug, then debugport, baudrate, and crashdebug are ignored.
/debug | Allows the computer to be debugged. If a kernel debugger attaches to this computer it will be given control over its execution. If a bug check occurs, or if a kernel-mode program attempts to communicate with a debugger, the computer will pause and wait for a response from a kernel debugger. The debug option should be used if you are performing local kernel debugging. If you are debugging over a COM port, you should use debugport and baudrate instead. If you are debugging over a 1394 cable, you should use debugport and channel instead.
/debugport=Port | Specifies the serial port to be used by the kernel debugger. If you are using a debug cable, Port can be COM1, COM2, or any other valid COM port. If you are using a 1394 cable, Port should be 1394. If this parameter is omitted, the debugger defaults to the highest enumerated port (usually COM2). It is best not to select the /debugport parameter on a computer that you do not intend to debug, because this will tie up a COM port unnecessarily.
/channel=Channel | Specifies the 1394 channel number to be used. Valid channel numbers are 1 through 62. Channel must match the channel number used by the host computer, but does not depend on the physical 1394 port chosen on the adapter.
/crashdebug | Causes the code that communicates with a kernel debugger to be loaded during boot but swapped out to the paging file after boot. As a result, a kernel debugger cannot break into this computer unless a bug check occurs.
/baudrate=BaudRate | Sets the speed that the kernel debugger uses, in bits per second (bps). Baud rates of 9600, 19200, 38400, 57600, and 115200 are supported. Your hardware will determine how fast your connection can run, but in most cases there should not be any communication problems at 57600 bps. The default rate is 19,200 bps.
/kernel=KernelFile | Specifies the Windows kernel file to use. This file must be located in the %SystemRoot%\system32 directory. Its filename must conform to 8.3-character format. The default is ntoskrnle.exe for systems with less than 4 GB of memory, or ntkrnlpa.exe for systems with more than 4 GB of memory. This parameter should only be changed if you have deliberately installed a different kernel. (This can be useful if you are testing a kernel patch, or if you have made a partial checked build installation.)
/hal=HALFile | Specifies the hardware abstraction layer (HAL) file to use. This file must be located in the %SystemRoot%\system32 directory. Its filename must conform to 8.3-character format. The default is hal.dll. This parameter should only be changed if you have deliberately installed a different HAL. (This can be useful if you are testing a HAL patch, or if you have made a partial checked build installation.)
/maxmem=SizeInMB | Specifies the amount of memory to be made available to the system. For example, you could restrict a 128 MB computer to 32 MB.
/PAE | Allows the operating system to support Physical Address Extension (PAE).
/basevideo | Causes the system to use VGA video mode.
/sos | Causes the system loader to display the names of the drivers as they load while Windows is booting.

You should use /debugport and /baudrate when debugging over a debug cable, /debugport and /channel when debugging over a 1394 cable, and /debug when performing local kernel debugging.


Editing the NVRAM Settings for Debugging

Use the following procedure to access and alter the OsLoadOptions settings on an IA-64 computer.

To Set the OsLoadOptions in NVRAM

  1. At the boot menu, select EFI Shell.
  2. Press any key to stop the auto-load sequence.
  3. When the Shell> prompt appears, type the following lines:
    fs0:
cd msutil
nvrboot.efi

    This will launch the nvrboot.efi tool, which allows you to edit the NVRAM settings.

  4. Read the instructions that explain how to modify a boot entry.
  5. If you are using a debug cable, add the following text at the end of the OsLoadOptions entry:
    /debugport=COMX /baudrate=BaudRate

    The value of COMX specifies the COM port being used on the target computer, and BaudRate specifies the baud rate to be used for the kernel connection. Baud rates of 9600, 19200, 38400, 57600, and 115200 are supported. Your hardware will determine how fast your connection can run, but in most cases there should not be any communication problems at 57600 bps.

  6. If you are using a 1394 cable, add the following text at the end of the OsLoadOptions entry:
    /debugport=1394 /channel=ChannelNumber

    The value of ChannelNumber specifies the 1394 channel to be used. This can be any number between 1 and 62 that is not already in use. It must match the channel number used by the host computer, but does not depend on the physical 1394 port chosen on the adapter.

  7. Save your changes, and exit the NVRAM editor.
  8. Reboot the computer.

There are other NVRAM parameters that can be of use in this file as well. See OsLoadOptions Parameters for a full list.

Loss of a Port Reserved for Debugging

Once kernel debugging is enabled through a COM port, Windows removes this port from the system device list. Control Panel will either not list this port at all, or will show "Not enough resources to use this port." This does not represent any malfunction.

Therefore, if you wish to test the null-modem connection using Hyperterminal or another communication program, you must do so after connecting the cable but before enabling debugging through the boot.ini file.


Using KDbgCtrl

The KDbgCtrl (Kernel Debugging Control, kdbgctrl.exe) tool can be used to control the kernel debugging connection from the target computer.

To use this tool, your target computer must be running Windows .NET Server 2003.

KDbgCtrl can control four different settings: Full Kernel Debugging, Automatic Kernel Debugging, User-Mode Error Handling, and the size of the DbgPrint buffer.

To use KDbgCtrl, you must have already enabled kernel debugging in the boot settings of the target computer before the last boot. KDbgCtrl cannot be used to enable kernel debugging if this was not done. See Configuring Software on the Target Computer for details on these boot settings.

Full Kernel Debugging

When Full Kernel Debugging is enabled, a kernel debugger running on the host computer can break into the target computer. The target computer will break into the kernel debugger if a kernel-mode exception is hit. Messages from the target to the host, such as DbgPrint output, symbol load messages, and redirected user-mode debuggers, are also allowed.

If this setting is disabled, all signals from the host computer will be ignored by the target.

Full Kernel Debugging is enabled by default. To check the current setting value, use kdbgctrl -c. To disable this setting, use kdbgctrl -d. To enable this setting, use kdbgctrl -e.

If you wish to check the current setting and use it to control execution within a batch file, you can use the kdbgctrl -cx command. For details on this command, see KDbgCtrl Command-Line Options.

Automatic Kernel Debugging

If Full Kernel Debugging is enabled, the current setting for Automatic Kernel Debugging is immaterial — all communication is permitted.

When Full Kernel Debugging is disabled and Automatic Kernel Debugging is enabled, only the target computer can initiate a debugging connection.

In this case, only a kernel-mode exception, breakpoint, or other kernel-mode event will cause a connection to be established. The connection will not be established for DbgPrint output, symbol load messages, redirected user-mode debugger input and output, or other similar messages — these will be stored in the DbgPrint buffer instead of being sent to the kernel debugger.

If an exception or event causes the target to break into the kernel debugger, then Full Kernel Debugging will be automatically turned on, just as if you had executed kdbgctrl -e.

Automatic Kernel Debugging is disabled by default (although this is immaterial unless Full Kernel Debugging is disabled as well). To check the current setting value, use kdbgctrl -ca. To disable this setting, use kdbgctrl -da. To enable this setting, use kdbgctrl -ea.

User-Mode Error Handling

When User-Mode Error Handling is enabled, some user-mode events will cause the target computer to break into the kernel debugger.

Specifically, all int 3 interrupts — such as breakpoints inserted into the code by a debugger or calls to DebugBreakPoint — will cause a break into the kernel debugger. However, standard exceptions — such as access violations and division by zero — will usually not be sent to the kernel debugger.

If a user-mode debugger is already attached to the process, this debugger will capture all user-mode errors, and the kernel debugger will not be alterted. For the precedence ranking of the various user-mode error handlers, see Enabling Postmortem Debugging.

For User-Mode Error Handling to function, either Full Kernel Debugging or Automatic Kernel Debugging must be enabled as well.

User-Mode Error Handling is enabled by default. To check the current setting value, use kdbgctrl -cu. To disable this setting, use kdbgctrl -du. To enable this setting, use kdbgctrl -eu.

The DbgPrint Buffer Size

The DbgPrint buffer stores messages that the target computer has sent to the kernel debugger.

If Full Kernel Debugging is enabled, these messages will automatically appear in the kernel debugger. But if this option is disabled, these messages will be stored in the buffer. At a later point in time, you can enable kernel debugging, connect to a kernel debugger, and use the !dbgprint extension to see the contents of this buffer.

The default size of the DbgPrint buffer is 0x1000 bytes. To check the current buffer size, use kdbgctrl -cdb. To change the buffer size, use kdbgctrl -sdb Size, where Size specifies the new buffer size. For syntax details, see KDbgCtrl Command-Line Options.

Examples

To display all the current settings, use the following command:

kdbgctrl -c -ca -cu -cdb

To restore the default settings, use the following command:

kdbgctrl -e -da -eu -sdb 0x1000

To lock out the host computer so that it only is contacted on exceptions, use the following command:

kdbgctrl -d -ea -eu

To disable all kernel debugging, use the following command:

kdbgctrl -d -da

If you are disabling all kernel debugging, you may also wish to increase the size of the DbgPrint buffer. This insures that all messages will be saved in case you need to see them later. If you have a megabyte of memory to spare, you might use the following command:

kdbgctrl -sdb 0x1000000


Configuring Software on the Host Computer

This section includes:

Choosing Kernel Debugging Settings

Installing the 1394 Virtual Driver

Installing Symbol Files


Choosing Kernel Debugging Settings

Before you can begin kernel debugging, you must choose your connection settings.

The debuggers support four different kinds of kernel debugging:

  • Target computer and host computer connected through the COM ports
  • Target computer and host computer connected by a 1394 cable
  • Target computer and host computer communicating through a modem
  • Local kernel debugging on a single computer

Local debugging and debugging over a 1394 cable are only supported on Windows XP and Windows .NET Server 2003. Both the target computer and the host computer must be running one of these Windows versions, but not necessarily the same one.

There are three ways to configure the kernel debugging settings: through environment variables, on the debugger command line, or through the WinDbg graphical interface. If none of these methods are used, the debugger will default to a COM port connection, using COM1 and 19200 baud.

Environment Variables

If you are configuring a COM port connection with environment variables, the following two variables should be used:

set _NT_DEBUG_PORT = ComPort
set _NT_DEBUG_BAUD_RATE = BaudRate

If you are configuring a 1394 connection with environment variables, the following three variables should be used:

set _NT_DEBUG_BUS = 1394
set _NT_DEBUG_1394_CHANNEL = 1394Channel
set _NT_DEBUG_1394_SYMLINK = 1394Protocol

Local kernel debugging and modem debugging cannnot be set up through environment variables.

For a list of other useful variables, see the Environment Variables reference section.

KD Command Line

If you are using the KD command line, you can specify the connection settings after the -k command-line option. The com parameter causes the debugger to connect through a COM port. The 1394 parameter causes the debugger to connect through a 1394 cable. The serial:modem parameter causes the debugger to connect through a modem. The -kl command-line option starts local kernel debugging. If these parameters are omitted, the environment variable settings or the defaults are used.

kd ... -k com:port=ComPort,baud=BaudRate ...
kd ... -k 1394:channel=1394Channel[,symlink=1394Protocol] ...
kd ... -k serial:modem ...
kd ... -kl ...
kd ...

See KD Command-Line Options for details on the other options.

WinDbg Command Line

The WinDbg connection parameters are the same as those for KD. The only difference is that if you wish to use the environment variable settings or the defaults, you still must specify the -k option.

windbg ... -k com:port=ComPort,baud=BaudRate ...
windbg ... -k 1394:channel=1394Channel[,symlink=1394Protocol] ...
windbg ... -k serial:modem ...
windbg ... -kl ...
windbg ... -k ...

See WinDbg Command-Line Options for details on the other options.

WinDbg Dialog Box

If WinDbg is already running and is in dormant mode, you can use the File | Kernel Debug menu option to start a new kernel debugging session. A dialog box will appear with three tabs: COM, 1394, and Local. Each of them specifies a different connection method:

  • The COM tab indicates that the connection will use a COM port. In the Baud Rate text box, enter the BaudRate. In the Port text box, enter the ComPort.
  • The 1394 tab indicates that the connection will use 1394. In the Channel text box, enter the 1394Channel.
  • The Local tab indicates that WinDbg will perform local kernel debugging. Local kernel debugging is only supported on Windows XP and Windows .NET Server 2003.

Explanation of Parameters

The parameters used for these environment variables, command line options, and the WinDbg dialog box have the following possible values:

ComPort
Specifies the name of the COM port. This can be in the format "com2" or in the format "\\.\com2", but should not simply be a number.
BaudRate
Specifies the baud rate. This can be 19200, 38400, 57600, or 115200.
1394Channel
Specifies the 1394 channel number. Valid channel numbers are 1 through 62. 1394Channel must match the number used by the target computer, but does not depend on the physical 1394 port chosen on the adapter.
1394Protocol
Specifies the connection protocol to be used for the 1394 kernel connection. This can almost always be omitted, since the debugger will automatically choose the correct protocol. If you wish to set this manually, and the target computer is running Windows XP, 1394Protocol should be set equal to "channel". If the target computer is running Windows .NET Server 2003, 1394Protocol should be set equal to "instance". If it is omitted, the debugger will default to the protocol appropriate for the current target computer. This can only be specified through the command line or the environment variables, not through the WinDbg graphical interface.
-kl
Causes the debugger to perform local kernel debugging. Only users that have debug privileges can start this process. For local kernel debugging to work, the x86 boot.ini file or the IA-64 OsLoadOptions settings must include the /debug option. See Performing Local Kernel Debugging for features peculiar to this technique.

Examples

The following batch file could be used to set up a COM connection:

set _NT_SYMBOL_PATH=d:\mysymbols
set _NT_DEBUG_PORT=com1
set _NT_DEBUG_BAUD_RATE=19200
set _NT_DEBUG_LOG_FILE_OPEN=d:\debuggers\logfile1.log
kd

The following batch file could be used with a 1394 connection:

set _NT_SYMBOL_PATH=d:\mysymbols
set _NT_DEBUG_BUS=1394
set _NT_DEBUG_1394_CHANNEL=44
set _NT_DEBUG_LOG_FILE_OPEN=d:\debuggers\logfile1.log
windbg -k

The following command lines would each start KD, without any environment variables:

kd -y d:\mysymbols -k serial:modem

kd -y d:\mysymbols -k com:port=com2,baud=57600

kd -y d:\mysymbols -k com:port=\\.\com2,baud=115200

kd -y d:\mysymbols -k 1394:channel=20,symlink=instance


Installing the 1394 Virtual Driver

If you are debugging over a 1394 connection, the debugger will install a 1394 virtual driver that allows the debugger to communicate with the target computer.

There are three stages to this installation:

  1. When the debugger package is installed on your system, it places certain files in the 1394 subdirectory of the debugger installation directory.
  2. The first time you start a kernel debugging session over a 1394 connection, the debugger will perform a pre-installation of the 1394 virtual drivers.
  3. If this pre-installation is successful, the debugger will call the bus driver. The bus driver will then complete the installation process.

During steps 2 and 3, you must be logged in as Administrator on the host computer, since only Administrator can install new drivers.

There are two different 1394 drivers: one for Windows XP target computers, and one for Windows .NET Server 2003 target computers. These correspond to the two different 1394 protocol settings. You should not need to configure the protocol setting; it will be determined automatically. If you have some reason for overriding the protocol choice, see Choosing Kernel Debugging Settings for details on this setting.

If you debug a Windows XP target over 1394, and later debug a Windows .NET Server 2003 target over 1394, or vice-versa, both drivers will be installed on your host computer.

Relocating the Debugger Binaries

Each 1394 virtual driver will only be installed once.

As a result, if you have installed the Debugging Tools for Windows package and then performed 1394 debugging, you should not copy the binaries to a different computer. The copied version will not attempt to reinstall the 1394 driver, which will make it impossible to debug over the 1394 connection.

A similar problem can occur if you have a dual-boot machine with a single copy of the debugger binaries.

To assure that 1394 debugging will work, each computer (or operating system on a dual-boot computer) should install a separate Debugging Tools package. See Debugger Installation for instructions.


Installing Symbol Files

The symbol files matching the operating system installation of the target computer must be installed on the host computer, or must be accessible to the host computer through a symbol server. For more information about the proper installation of symbol files, see Symbols.


User-Mode Setup

This section includes:

Configuring Hardware for User-Mode Debugging

Configuring Software for User-Mode Debugging

Enabling Postmortem Debugging


Configuring Hardware for User-Mode Debugging

User-mode debugging is generally done on a single machine: the debugger is run on the same computer as the application that failed.

In this case, no specific hardware setup is required. Throughout this document, the terms host computer and target computer are interchangeable in this case.

If you choose to perform user-mode debugging on two machines, set up the host computer and target computer in the manner described in Configuring Hardware for Kernel-Mode Debugging.


Configuring Software for User-Mode Debugging

This section includes:

Basic User-Mode Configuration

Configuring tools.ini

Finding the Process ID


Basic User-Mode Configuration

Before you can begin user-mode debugging, you must install the necessary symbol files and set certain environment variables.

Installing the Symbol Files

You must install the symbol files for the user-mode process that is being debugged. If this is an application you have written, it should be built with full symbol files. If it is a commercial application, the symbol files may be on the product disk; if not, contact the manufacturer.

If possible, you should also install the symbol files for the version of Microsoft® Windows® on which the user-mode process is running.

If you are performing remote debugging through the debugger or remote debugging through remote.exe, the symbol files should be on the target computer. If you are performing remote debugging through a process server, the symbol files should be on the host computer. If you are controlling the user-mode debugger from the kernel debugger, the symbol files need to be on both computers.

For more information about the proper installation of symbol files, see Symbols.

Configuring Environment Variables

The debugger uses a variety of environment variables to indicate a number of important settings.

For a complete list of environment variables used in user-mode debugging, see General Environment Variables.


Configuring tools.ini

On startup, CDB (or NTSD) searches for an [NTSD] header in the tools.ini file and extracts initialization information from the entries under the header. The environment variable INIT must point to the directory containing the tools.ini file.

The tools.ini entries for the [NTSD] section are shown in the following table.

Keywords must be separated from the values by white space or a colon. Keywords are not case-sensitive.

For TRUE or FALSE values, "FALSE" is the only false value. Anything else is TRUE.

Entry | Description
$u0: value ... $u9 value | Assign values to fixed-name aliases. You can specify numeric values n or 0xn or any other string. See Using Aliases for details. No command-line equivalent.
DebugChildren: flag | TRUE or FALSE. If TRUE, CDB debugs the specified application as well as any child processes that it might spawn. Command-line equivalent is -o.
DebugOutput: flag | TRUE or FALSE. If TRUE, CDB sends output and receives input through a terminal. If FALSE, output goes to the user screen. The command-line option -d is similar but not identical.
IniFile: file | Specifies the name of the script file that CDB or KD takes commands from at startup. The default is the ntsd.ini file in the current directory. Command-line equivalent is -cf.
LazyLoad: flag | TRUE or FALSE. If TRUE, CDB performs lazy symbol loading; that is, symbols are not loaded until required. Command-line equivalent is -s. For details, and other methods of setting this option, see Deferred Symbol Loading.
SetDll: filename | Set extension DLL. The .dll filename extension should be omitted. Default is userexts.dll. Command-line equivalent is -a. For details, and other methods of setting this default, see Loading Debugger Extension DLLs.
StopFirst: flag | True or false. If true, CDB stops on the breakpoint at the end of the image-loading process. Command-line equivalent is -g.
StopOnProcessExit: flag | TRUE or FALSE. If TRUE, CDB stops when it receives a process termination notification. Command-line equivalent is -G.
sxd: event sxe: event | Sets the debugger response and the handling status for the specified exception or event. Exceptions and events may be specified in the following ways: *: Default exception n: Exception n (decimal) 0xn: Exception 0xn (hexadecimal) (other): Event code See Controlling Exceptions and Events for details of this process and for other methods of controlling these settings.
VerboseOutput: flag | TRUE or FALSE. If TRUE, CDB will display detailed information on symbol handling, event notification, and other run-time occurrences. Command-line equivalent is -v.

A sample [NTSD] section in the tools.ini file follows:

[NTSD]
sxe: 3c
sxe: cc
$u0: VeryLongName
VerboseOutput:true

The tools.ini file does not affect WinDbg or KD.


Finding the Process ID

Each process running in Microsoft® Windows® is assigned a unique decimal number called the process ID, or PID.

There are several ways to determine the PID for a given application: using the Task Manager, using the Task List Viewer, or using the debugger.

Task Manager

The Task Manager may be activated in a number of ways, but the simplest is to press CTRL+ALT+DELETE and then click on Task Manager.

If you select the Processes tab, each process and its PID will be listed, along with other useful information.

Some kernel errors may cause delays in Task Manager's graphical interface.

TList

The Task List Viewer, or TList, is a command-line tool that displays a list of tasks, or user-mode processes, currently running on the local computer. For each process, it shows the PID, process name, and, if the process has a window, the title of that window.

When you run TList from the command prompt, it will display a list of all the user-mode processes in memory with a unique process identification (PID) number. You need the PID number of the process you want to debug in order to start a debugger against that process.

The .tlist Command

If there is already a user-mode debugger running on the system in question, the .tlist (List Process IDs) command will display a list of all PIDs on that system.

CSRSS and User-Mode Drivers

To debug a user-mode driver running on another computer, select the CSRSS process (the Windows subsystem). The process ID for this process is always -1. For more information, see Debugging CSRSS With NTSD.


Enabling Postmortem Debugging

The most common application errors are called exceptions. These include access violations, division-by-zero errors, numerical overflows, and many other kinds of errors.

Applications can also cause breakpoint interrupts. These occur when Windows is unable to run the application (for example, when a necessary module cannot be loaded) or when a breakpoint is encountered. Breakpoints can be inserted into the code by a debugger, or invoked through a function such as DebugBreakPoint. In assembly language, a breakpoint interrupt is generated by an int 3 instruction.

Windows can handle user-mode errors in a variety of ways. The following sequence shows the precedence used for error handling:

  1. If a user-mode debugger is currently attached to the faulting process, all errors will cause the target to break into this debugger.

    As long as the user-mode debugger is attached, no other error-handling methods will be used — even if the GN (Go With Exception Not Handled) command is used.

  2. If no user-mode debugger is attached and the executing code has its own exception handling routines (for example, try - except), this exception handling routine will attempt to deal with the error.
  3. If no user-mode debugger is attached, and Windows has an open kernel-debugging connection, and the error is a breakpoint interrupt, Windows will attempt to contact the kernel debugger.

    Kernel debugging connections must be opened during Windows' boot process. If you are using Windows .NET Server 2003 and wish to prevent a user-mode interrupt from breaking into the kernel debugger, you can use the KDbgCtrl utility with the -du parameter. For details on how to configure kernel-debugging connections and how to use KDbgCtrl, see Configuring Software on the Target Computer.

    If Windows does attempt to contact a kernel debugger but there is no debugger running at the other end of the connection, Windows will freeze until kernel debugger is activated.

    In the kernel debugger, you can use GH (Go With Exception Handled) to disregard the error and continue running the target. You can use GN (Go With Exception Not Handled) to bypass the kernel debugger and go on to step 4.

  4. If the conditions in steps 1, 2, and 3 do not apply, Windows will activate a debugging tool. Any program can be selected in advance as the tool to use in this situation. The chosen program is referred to as the postmortem debugger. This is also known as the just-in-time debugger or the JIT debugger.

    If the postmortem debugger is a standard user-mode debugger (such as CDB, WinDbg, or Microsoft Visual Studio®), this debugger will start up and break into your application.

    If the postmortem debugger is a tool for writing dump files (such as Dr. Watson), a memory dump file will be created, and then the application will be terminated.

Note If Dr. Watson is activated on Windows XP or Windows .NET Server 2003, a message box will appear. This window gives you the option of sending an error report to Microsoft. If you choose Don't Send, a dump file will created and stored on your hard disk. If you choose Send Error Report, a dump file will be created and stored on your hard disk, and will also be transmitted to Microsoft over the internet.

If you have not reconfigured Windows' postmortem settings, Dr. Watson is used as the default postmortem debugger. This setting can be changed programmatically or through the registry; any changes take effect immediately.

  • To change the postmortem debugger to WinDbg, run windbg -I. (The I must be capitalized.) When WinDbg is the postmortem debugger, WinDbg will be activated whenever an application crashes. See WinDbg Command-Line Options for details.
  • To change the postmortem debugger to CDB, you must edit the registry. When CDB is the postmortem debugger, CDB will be activated whenever an application crashes.
  • To change the postmortem debugger back to Dr. Watson, run drwtsn32 -i. When Dr. Watson is the postmortem debugger, a memory dump file will be written to disk if an application crashes. See Dr. Watson Command-Line Options for details.

Only a system administrator can alter the postmortem settings.

If a postmortem debugger has been installed, you can deliberately break into the debugger from a user-mode application by calling the DebugBreak function.

Editing the Registry

The Just-in-Time debugging settings are stored in the registry.

On an x86 computer, the postmortem settings are stored in the \\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AeDebug key.

On an IA-64 computer, there are two registry keys used for postmortem debugging:

  1. A failing 64-bit application will be debugged according to the settings stored in the \\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AeDebug key.
  2. A failing 32-bit application will be debugged according to the settings stored in the \\HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug key. However, if the Debugger value in this key specifies an application in the %windir%\system32 directory, Windows will look in %windir%\syswow64 instead.

When using an IA-64 computer, it is often simplest to place identical values in each of these keys. In particular, if you are using WinDbg, CDB, or NTSD as your postmortem debugger, the same version will work for 32-bit and 64-bit user-mode applications on an IA-64 computer. See Choosing Between the 32-bit and 64-bit Packages for details.

There are two registry values that should appear in these keys:

Debugger
This REG_SZ value specifies the debugger that will handle postmortem debugging. The full path to the debugger must be listed, unless the debugger is located in a directory that is in the default path.
Auto
This REG_SZ value is always either 0 or 1. If Auto is set to 0, a message box will be displayed prior to postmortem debugging.

When an unhandled application error occurs, Windows checks to see if the Debugger and Auto registry values exist.

If the Auto value is 0, a message box will appear.

In Windows NT and Windows 2000, the message box will have one of the following formats:

  • If the Debugger value contains the name of a valid debugger or Dr. Watson, the message box will have two buttons: OK and Cancel. If the OK button is pressed, the application will be terminated. If the Cancel button is pressed, the tool specified in the Debugger value will be started.
  • If the Debugger value is empty, the message box will have only an OK button and no debugger will start.

In Windows XP and Windows .NET Server 2003, the message box will have one of the following formats:

  • If the Debugger value contains the name of a valid debugger or Dr. Watson, the message box will have three buttons: Send Error Report, Don't Send, and Debug. If the Don't Send button is pressed, the application will be terminated. If the Send Error Report button is pressed, a minidump file will be sent to Microsoft and the application will be terminated. If the Debug button is pressed, the tool specified in the Debugger value will be started. (Note that all of these buttons have different effects than the buttons on the message window for Dr. Watson when the Auto value does not equal 0.)
  • If the Debugger value is empty, the message box will have only the Send Error Report and Don't Send buttons.

If the Auto value equals 1, no message box appears. The debugger referred to in the Debugger value is automatically started.

Registry Examples

The following registry values can be used to set Dr. Watson as the postmortem debugger (this is the default):

Debugger = "drwtsn32 -p %ld -e %ld -g"
Auto = 1

The following values can be used to set WinDbg as the postmortem debugger:

Debugger = "Path\WinDbg -p %ld -e %ld"
Auto = 1

The following values can be used to set CDB as the postmortem debugger:

Debugger = "Path\CDB -p %ld -e %ld -g"
Auto = 1

In these examples, Path is the directory where the debugger is located, -p %ld specifies the process ID that will be debugged, -e %ld provides the event that caused the exception, and -g causes the debugger to skip the initial breakpoint. (Dr. Watson ignores the -g option.)

Security Vulnerabilities

If you are considering enabling postmortem debugging on a computer that you share with other people, see Security During Postmortem Debugging.


Debugger Operation

This section includes:

Starting the Debugger

The Debugger Command Window

The WinDbg Graphical Interface

Debugger Configuration

Debugger Operation (General)

Debugger Operation (User Mode)

Debugger Operation (Kernel Mode)

Debugger Extensions

Logger and LogViewer

Remote Debugging


Starting the Debugger

When you start the CDB, KD, or WinDbg programs, there are several ways you can select your debugging target.

KD and CDB each begin the session with a target, and when the session ends, the program exits. On the other hand, WinDbg can be started without specifying a target on the command line, or by double-clicking the WinDbg icon; it is also possible to end a WinDbg session without exiting the WinDbg program. Any of these three actions will place WinDbg in dormant mode. In this state, you can select a new debugging target and begin a new session.

This section covers several different ways to start a debugging session. Each of them can involve starting a new debugger or selecting a target for a dormant WinDbg.

Attaching to a Running Process (User Mode)

Spawning a New Process (User Mode)

Noninvasive Debugging (User Mode)

Attaching to a Target Computer (Kernel Mode)

Controlling the User-Mode Debugger from the Kernel Debugger

Opening a Crash Dump

There are three other ways to begin a debugging session.

  1. You can join a remote debugging session by connecting to a Debugging Server. See Activating the Debugging Client for details.
  2. The debugger can also be automatically activated when a user-mode process fails. See Enabling Postmortem Debugging for details.
  3. Or you can automatically reactivate an old debugging session by loading a named workspace. See Using Workspaces for details.


Attaching to a Running Process (User Mode)

If a user-mode application is already running, the debugger can attach to that process and then debug it. The application is usually specified by a decimal number called the process ID (PID).

The application can also be specified by its name. This is the complete name of the process, including the extension. However, if two processes have identical names, you must use the process ID instead.

See Finding the Process ID for information on how to determine the process ID and the process name.

CDB Command Line

To attach to a running process from the CDB command line, specify the -p option and the process ID:

cdb -p ProcessID

To refer to the process by name, use the following syntax instead:

cdb -pn ProcessName

There are a number of other useful command-line options. See CDB Command-Line Options for the full command-line syntax.

WinDbg Command Line

To attach to a running process from the WinDbg command line, specify the -p option and the process ID:

windbg -p ProcessID

To refer to the process by name, use the following syntax instead:

windbg -pn ProcessName

There are a number of other useful command-line options. See WinDbg Command-Line Options for the full command-line syntax.

WinDbg Menu

When WinDbg is in dormant mode, you can attach to a running process by selecting the File | Attach to a Process menu command or by pressing the F6 shortcut key.

When the Attach to Process dialog box appears, select the line containing the proper process ID and name. Or you can enter the process ID in the Process ID text box. Then press OK.

Debugger Command Window

If the debugger is already active, you can attach to a running process by using the .attach (Attach to Process) command.

This command can be used when CDB is dormant, or if it is already debugging one or more processes. It cannot be used when WinDbg is dormant.

Multiple target processes will always be executed together, unless some of their threads are frozen or suspended.

If the .attach command is successful, the debugger will attach to the specified process the next time it issues an execution command. If this command is used several times in a row, execution will have to be requested as many times as this command is used.

Noninvasive Debugging

If you wish to debug a running process with only a minimal amount of interference in its execution, you may wish to debug it noninvasively. See Noninvasive Debugging (User Mode) for details.

Beginning the Debugging Session

See Debugger Configuration, Symbols, Debugger Operation (General) and Debugger Operation (User Mode) for options on how to proceed.

Processes created by the debugger behave slightly differently than they would under normal conditions. See Behavior of Spawned Processes for details.

In Windows® XP and Windows .NET Server 2003, if the debugger crashes or freezes it is possible to attach a new debugger to the target process. See Re-attaching to the Target Application for details.


Spawning a New Process (User Mode)

The debugger can start a user-mode program and then debug it. The application is specified by name, just as it would be if launched from a Microsoft® MS-DOS® Command Prompt.

The debugger can also automatically attach to child processes (additional processes launched by the original target process).

CDB Command Line

To spawn a user-mode program from the CDB command line, place the program's own command line at the end of the CDB command line:

cdb [-o] ProgramName [Arguments]

The -o option will cause the debugger to attach to child processes. There are a number of other useful command-line options as well. See CDB Command-Line Options for the full command-line syntax.

WinDbg Command Line

To spawn a user-mode program from the WinDbg command line, place the program's own command line at the end of the WinDbg command line:

windbg [-o] ProgramName [Arguments]

The -o option will cause the debugger to attach to child processes. There are a number of other useful command-line options as well. See WinDbg Command-Line Options for the full command-line syntax.

WinDbg Menu

When WinDbg is in dormant mode, you can spawn a new process by selecting the File | Open Executable menu command or by pressing the CTRL+E shortcut key.

When the Open Executable dialog box appears, enter the full path and name of the executable in the File name text box, or use the dialog box to select the proper path and file name. (You need to specify the exact path to this program. Whereas the Windows® Start | Run dialog box and the MS-DOS Command Prompt search the command path for an executable name, the Open Executable dialog box does not.)

If you wish to use any command-line arguments with this application, type them in the Arguments text box. If you wish to change the starting directory from the default, enter the directory path into the Start directory text box. If you wish WinDbg to attach to child processes, select the Debug child processes also check box.

When the proper selections have been made, press Open.

Debugger Command Window

If the debugger is already active, you can create a new process by using the .create (Create Process) command.

This command can be used when CDB is dormant, or if it is already debugging one or more processes. It cannot be used when WinDbg is dormant.

Multiple target processes will always be executed together, unless some of their threads are frozen or suspended.

If the .create command is successful, the debugger will create the specified process the next time it issues an execution command. If this command is used several times in a row, execution will have to be requested as many times as this command is used.

You can control the application's starting directory by using .createdir (Set Created Process Directory) before .create. On Windows XP and Windows .NET Server 2003, the debugging of child processes can also be activated or deactivated by using the .childdbg (Debug Child Processes) command.

Beginning the Debugging Session

See Debugger Configuration, Symbols, Debugger Operation (General) and Debugger Operation (User Mode) for options on how to proceed.

(Windows XP and Windows .NET Server 2003 only) If the debugger crashes or freezes, it is possible to attach a new debugger to the target process. See Re-attaching to the Target Application for details.


Noninvasive Debugging (User Mode)

If a user-mode application is already running, the debugger can debug it noninvasively. Noninvasive debugging does not present you with as broad a repertoire of debugging actions. However, it allows you to keep the debugger's interference with the target application to a minimum.

In noninvasive debugging, the debugger does not actually attach to the target application. The debugger will suspend all of the target's threads and will have access to its memory, registers, and other such information. However, the target cannot be controlled by the debugger, and thus commands such as G (Go) will not work.

Commands that are not allowed during noninvasive debugging will generate the message "The debugger is not attached, so process execution cannot be monitored."

When the debugging session is ended, the target application will be released and will then continue running. You should exit the session by using Q (Quit), .detach (Detach from Process), or the WinDbg Debug | Stop Debugging menu command. (Exiting by killing the debugger window or by using File | Exit in WinDbg will generally freeze your target application.)

Noninvasive debugging is useful if you do not want to terminate the target at the end of the session, and the target is running on Windows NT or Windows 2000. (These operating systems do not support detaching from a target that the debugger has actually attached to.) It is also useful if the target application is completely frozen and cannot launch the break thread necessary for a true attach.

Selecting the Process to Debug

The target application can be specified by the process ID (PID) or by its name.

If the application is specified by name, the complete name of the process should be used, including the extension. If two processes have identical names, you must use the process ID instead.

See Finding the Process ID for information on how to determine the process ID and the process name.

CDB Command Line

To noninvasively debug a running process from the CDB command line, specify the -pv option, the -p option, and the process ID:

cdb -pv -p ProcessID

To refer to the process by name, use the following syntax instead:

cdb -pv -pn ProcessName

There are a number of other useful command-line options. See CDB Command-Line Options for the full command-line syntax.

WinDbg Command Line

To noninvasively debug a running process from the WinDbg command line, specify the -pv option, the -p option, and the process ID:

windbg -pv -p ProcessID

To refer to the process by name, use the following syntax instead:

windbg -pv -pn ProcessName

There are a number of other useful command-line options. See WinDbg Command-Line Options for the full command-line syntax.

WinDbg Menu

When WinDbg is in dormant mode, you can noninvasively debug a running process by selecting the File | Attach to a Process menu command or by pressing the F6 shortcut key.

When the Attach to Process dialog box appears, select the Noninvasive check box. Select the line containing the proper process ID and name, or enter the process ID in the Process ID text box. Then click OK.

Debugger Command Window

If the debugger is already active, you can noninvasively debug a running process by using the .attach -v (Attach to Process) command.

This command can be used if the debugger is already debugging one or more processes invasively. This command can be used in CDB if it is dormant, but not in a dormant WinDbg.

If the .attach -v command is successful, the debugger will debug the specified process the next time the debugger issues an execution command. Since execution is not permitted during noninvasive debugging, the debugger is not able to noninvasively debug more than one process at a time. This also means that using the .attach -v command may render an already-existing invasive debugging session less useful.

Beginning the Debugging Session

See Debugger Configuration, Symbols, Debugger Operation (General) and Debugger Operation (User Mode) for options on how to proceed.


Attaching to a Target Computer (Kernel Mode)

Before you can begin kernel debugging with KD or WinDbg, you must specify exactly how the connection to the target computer is to be made.

KD Command Line

To begin a kernel debugging session from the KD command line, use one of the following options:

kd [-y SymbolPath] -k com:port=ComPort,baud=BaudRate
kd [-y SymbolPath] -k 1394:channel=1394Channel[,symlink=1394Protocol]
kd [-y SymbolPath] -k serial:modem
kd [-y SymbolPath] -kl
kd [-y SymbolPath]

If you do not include the -k command-line option, the connection settings will be based on the values of certain environment variables. For a full description of the kernel connection options, see Choosing Kernel Debugging Settings. For a description of other options, see KD Command-Line Options.

The kernel debugging baud rate can be altered after the session has begun by using the CTRL+A control key.

WinDbg Command Line

Beginning a kernel debugging session from the WinDbg command line is done in a similar manner:

windbg [-y SymbolPath] -k com:port=ComPort,baud=BaudRate
windbg [-y SymbolPath] -k 1394:channel=1394Channel[,symlink=1394Protocol]
windbg [-y SymbolPath] -k serial:modem
windbg [-y SymbolPath] -kl
windbg [-y SymbolPath] -k

If you do not include the -k command-line option, the connection settings will be based on the values of certain environment variables. For a full description of the kernel connection options, see Choosing Kernel Debugging Settings. For a description of other options, see WinDbg Command-Line Options.

The kernel debugging baud rate can be altered after the session has begun by using the Debug | Kernel Connection | Cycle Baud Rate menu command, or the CTRL+ALT+A shortcut key.

WinDbg Menu

When WinDbg is in dormant mode, you can begin a kernel debugging session by selecting the File | Kernel Debug menu command or by pressing the CTRL+K shortcut key.

When the Kernel Debugging dialog box appears, select the COM tab, the 1394 tab, or the Local tab. Each of them specifies a different connection method. For details on the dialog box and its entries, see File | Kernel Debug.

If you leave these boxes blank, the connection settings will be based on the values of certain environment variables. For full details, see Choosing Kernel Debugging Settings.

Beginning the Session

If the target computer has crashed, the target computer is still halted as a result of an earlier kernel debugging action, or the -b command-line option was used, then the debugger will break into the target computer immediately.

Otherwise, the target computer will continue running until the debugger orders it to break.

See Debugger Configuration, Symbols, Debugger Operation (General) and Debugger Operation (Kernel Mode) for options on how to proceed.

1394 Virtual Driver Installation

The first time you start the kernel debugger after enabling debugging over a 1394 connection, a driver will be installed on your host computer. You must be logged in as an Administrator on the host computer during this debugging session. See Installing the 1394 Virtual Driver for details.


Controlling the User-Mode Debugger from the Kernel Debugger

The input and output from a user-mode debugger can be redirected to a kernel debugger. This allows the kernel debugger to have control over a specific user-mode debugging session that is taking place on the target computer.

Either KD or WinDbg can be used as the kernel debugger in this scenario.

Either CDB or NTSD can be used as the user-mode debugger. NTSD is identical to CDB in most ways. The main difference is that when these programs are launched from an MS-DOS® Command Prompt, NTSD is given a new console window while CDB inherits the existing MS-DOS window. However, when NTSD is started under the control of the kernel debugger, no NTSD window is created at all.

This technique makes NTSD an extremely powerful user-mode debugger, since it places a minimal burden on the processor and operating system of the computer whose application is being debugged. User-mode debugging can be performed through the serial port very early in the boot phase and fairly late into shutdown. System processes are usually debugged by using this technique; see Debugging CSRSS with NTSD and Debugging WinLogon with NTSD for examples.

This technique is also useful if you wish to debug the target application in user mode, but might need to use some kernel-mode features to complete your analysis of the problem.

Note In describing this scenario, target application refers to the user-mode application being debugged, target computer refers to the computer containing the target application as well as the CDB or NTSD process itself, and host computer refers to the computer containing the kernel debugger.

Starting the Debugging Session

To begin using this technique, two things must be done. They can be done in either order:

  • Start WinDbg or KD on the host computer, as if you were going to debug the target computer, but do not actually break in to the target computer.
    kd [-y SymbolPath] [-k ConnectionOptions]

    For details, see Attaching to a Target Computer (Kernel Mode).

  • Start CDB or NTSD on the target computer, using the -d command-line option. You can attach to a running process:
    ntsd -d -p PID

    or you can launch a new process as the target:

    ntsd -d ApplicationName

    For details, see either Attaching to a Running Process (User Mode) or Spawning a New Process (User Mode).

If you use CDB, the MS-DOS Command Prompt window associated with CDB will remain locked and unusable for as long as debugging continues. If you use NTSD, no additional window will be created, although NTSD will have a process ID associated with it on the target computer.

If you wish to run the user-mode debugger from the kernel debugger and to use it as a Debugging Server, you must use -ddefer instead of -d. When this option is used, the user-mode debugger will look for input from a Debugging Client. If no such input is available, it will look for input from the kernel debugger. See Remote Debugging Through the Debugger for details on Debugging Clients and Debugging Servers.

Switching Modes

There are four possible modes that will occur during the use of this technique. They are as follows:

User-mode debugging
In this mode, the target computer is frozen, along with target application. The user-mode debugging prompt appears in the Debugger Command window of the kernel debugger In WinDbg, the prompt in the lower panel of this window will read Input>. Commands can be entered at this prompt just as they would be entered during user-mode debugging, to analyze the target application's state or cause it to run or step through its execution. Symbol files, extension DLLs, and other files accessed by the debugger will be those on the target computer, not the host computer.
Target application execution
In this mode, the target computer is running, the target application is running, and the debugger is waiting. This mode is no different than letting the target run in ordinary debugging.
Sleep mode
In this mode, the target computer is running, but the target application is frozen, and both debuggers are frozen. This mode is useful if you need to do something on the target computer but do not want to change the state of the debugging session.
Kernel-mode debugging
In this mode, the target computer is frozen, along with the target application. The kernel-mode debugging prompt appears in the Debugger Command window of the kernel debugger This is just the normal kernel-mode debugging state.

The session will begin in user-mode debugging mode. The following actions and events will cause the mode to change:

  • To switch from user-mode debugging to target application execution, use the G (Go) command.
  • To momentarily switch from user-mode debugging to target application execution, and then return, use a step, trace, or other temporary execution command. See Controlling the Target for a list of these commands.
  • To switch from user-mode debugging to sleep mode, use the .sleep (Pause Debugger) command. This command is timed; when the time expires the system will return to user-mode debugging.
  • To switch from user-mode debugging to kernel-mode debugging, use the .breakin (Break to the Kernel Debugger) command.
  • Switching from target application execution to user-mode debugging is only possible in certain environments. If the target computer is running Windows XP or Windows .NET Server 2003, you can use the !bpid extension command. If you are using CDB (not NTSD), you can make the CDB window on the target computer active and press CTRL+C.
  • The system will also switch from target application execution to user-mode debugging if the target application hits a breakpoint, encounters an exception, runs into some other controlled event, or terminates. Planning such events in advance is useful, especially when using NTSD. See Using Breakpoints and Controlling Exceptions and Events for details.
  • To switch from target application execution to kernel-mode debugging, press CTRL+C in the KD window, press CTRL+BREAK or select Debug | Break in the WinDbg window, or press SYSRQ or ALT+SYSRQ on the target computer keyboard. (If your kernel debugger is KD, and you press CTRL+C at the exact moment that the kernel debugger is communicating with the user-mode debugger, this control key may be captured by the user-mode debugger.)
  • The system will also switch from target application execution to kernel-mode debugging if a kernel error is encountered, or if the breakin.exe tool is used.
  • To switch from sleep mode to user-mode debugging, either wait for the sleep time to expire, start a new CDB process on the target computer with the -wake command-line option, or use the .wake (Wake Debugger) command in a different copy of CDB/NTSD on the target computer.
  • To switch out of kernel-mode debugging, use the G (Go) command. This will return to either user-mode debugging or target application execution (whichever of the two was the most recently-used state).


Opening a Crash Dump

The debugger can read and analyze a crash dump file which was created from a system crash or a user-mode application crash.

For information on opening and analyzing a kernel-mode crash dump file with KD, WinDbg, or KAnalyze, see Analyzing a Kernel-Mode Dump File.

For information on opening and analyzing a user-mode crash dump file with CDB or WinDbg, see Analyzing a User-Mode Dump File.

For information on how dump files are created, and a description of the different types of dump files, see Crash Dump Files.


The Debugger Command Window

This section includes:

Using Debugger Commands

Evaluating Expressions

Using Aliases

Using Shell Commands


Using Debugger Commands

For KD or CDB, the term "Debugger Command window" refers to the entire text window. Commands are entered at the prompt at the bottom of the screen. If they have any text output, this output will be displayed, and then a prompt will appear.

For WinDbg, the term "Debugger Command window" refers to the window labeled "Command" in the title bar. This window is split into two panes. The small bottom pane is used to enter text commands. The large upper pane is used to view command output. This window is always open at the beginning of a debugging session. If it is closed, minimized, or hidden, it can be restored by the View | Command menu command, pressing the ALT+1 shortcut key, or clicking the following toolbar button:

You can use the UP ARROW and DOWN ARROW keys to scroll through the command history. When a previous command appears, it can be edited. Pressing ENTER will cause the old command (or the edited command) to be executed. The cursor does not need to be at the end of the line for this to work correctly.

The Debugger Command Window Prompt

When performing user-mode debugging, the prompt looks like this:

2:005>

If you attach to more than one system, the system number is placed before the process and thread number:

3:2:005>

In this example, the current system number is 3, the current process number is 2, and the current thread number is 005.

When performing kernel-mode debugging on a target computer which only has one processor, the prompt looks like this:

kd>

However, if the target computer has multiple processors, the number of the current processor will appear before the prompt:

0: kd>

If no prompt appears in KD or CDB, or if the entry pane in WinDbg's Debugger Command window is grayed, no command will be accepted. However, control keys can still be used in KD and CDB; menu commands and shortcut keys can still be used in WinDbg.

Varieties of Commands

WinDbg, KD, and CDB support a variety of commands. Some of these are shared between the debuggers, and some are available only on one or two of the debuggers.

Some of these commands are only available in live debugging; others are only available while debugging a dump file. Some are only available during user-mode debugging; others are only available during kernel-mode debugging. Some are only available when the target is running on certain processors. The Debugger Commands reference section describes all the commands and their restrictions.

Editing, Repeating, and Canceling Commands

You can use standard editing keys when you enter a command. Use the UP and DOWN ARROW keys to retrieve previous commands. Edit the current command line with the BACKSPACE, DEL, INS, and LEFT and RIGHT ARROW keys. Press the ESC key to clear the current line.

Right-clicking in the Debugger Command window automatically pastes the contents of the clipboard into the command being typed.

The maximum command line length is 4096 characters. However, if you are controlling the user-mode debugger from the kernel debugger, the maximum line length is 512 characters.

In CDB and KD, pressing the ENTER key by itself will repeat the previous command. In WinDbg, this behavior can be enabled or disabled; see ENTER (Repeat Last Command) for details.

If the last command issued is presenting a lengthy display and you wish to cut it off, use the CTRL+C key in CDB or KD. In WinDbg, use Debug | Break or press the CTRL+BREAK shortcut key.

In kernel-mode debugging, commands can also be canceled from the keyboard of the target computer. This is done with the CTRL+C key.

You can use the .cls (Clear Screen) command to clear all the text from the Debugger Command window, clearing the command history entirely. In WinDbg this can also be done through the Edit | Clear Command Output menu command.

Expression Syntax

Many commands and extension commands accept expressions as their arguments. These expressions are evaluated by the debugger before the command is executed. For details, see Evaluating Expressions.

Aliases

Aliases are text macros that can be used to avoid having to retype complicated phrases. There are two kinds of aliases available. See Using Aliases for details.

Self-Repeating Commands

There are four commands that can be used to repeat an action or conditionally execute other commands:

  • The J (Execute If-Else) conditional command
  • The Z (Execute While) conditional command
  • The ~E (Thread-Specific Command) command qualifier
  • (Windows XP and Windows .NET Server 2003 only) The !list extension command

See the individual command pages for details.

Controlling Scrolling

You can use the scrollbar to view your previous commands and their output.

When using CDB or KD, any keyboard entry will automatically scroll the Debugger Command window back to the bottom.

In WinDbg, the display will automatically scroll to the bottom whenever a command produces output or you press the ENTER key. If you wish to deactivate this automatic scrolling, select View | Options and then clear the Automatically scroll checkbox.

WinDbg Text Features

In WinDbg, you can use the Edit | Add to Command Output menu command to add a comment in the Debugger Command window.

The colors used for the text and the background of the Debugger Command window can also be customized in WinDbg. Different kinds of text can be colored differently. For example, you can display the automatic register output in one color, error messages in another color, and DbgPrint messages in a third color. See View | Options for details.

WinDbg also has a number of features that apply to all its debugging information windows, such as customizable fonts and special editing commands. See Using Debugging Information Windows for additional text editing options.

Remote Debugging

When you are performing remote debugging through the debugger, only a limited number of commands can be accessed by the Debugging Client. To change the number of commands that can be accessed, use the -clines command-line option or the _NT_DEBUG_HISTORY_SIZE environment variable.


Evaluating Expressions

The debugger understands two different forms of expressions: MASM expressions and C++ expressions.

MASM (Microsoft® Macro Assembler) expressions are used in the examples in this help file, except when otherwise noted. The most prominent feature of MASM expressions is that all symbols are treated as addresses.

C++ expressions are the same as those used in actual C++ code. In these expressions, symbols are understood as the appropriate data types.

When Each Syntax is Used

The default expression evaluator can be chosen in three different ways:

  • The _NT_EXPR_EVAL environment variable can be used to choose the expression evaluator before the debugger is launched.
  • The -ee {masm|c++} command-line option can be used to choose the expression evaluator when the debugger is started.
  • The .expr (Choose Expression Evaluator) command can be used to display or change the expression evaluator once the debugger is running.

If neither of these methods are used, the MASM expression evaluator will be used as the default.

If you simply want to evaluate an expression without changing the debugger state, you can use the ? (Evaluate Expression) command.

All commands and debugging information windows interpret their arguments through the default expression evaluator, with the following exceptions:

  • The ?? (Evaluate C++ Expression) command always uses the C++ expression evaluator by default.
  • The Watch window always uses the C++ expression evaluator by default.
  • The Locals window always uses the C++ expression evaluator by default.
  • Some extension commands always use the MASM expression evaluator by default (and others only accept numerical arguments rather than full expressions).
  • If any portion of an expression is enclosed in parentheses and prefixed by a double "at" sign ( @@ ), it will be evaluated by the expression evaluator that would not normally be used in this case.

The double "at" sign allows you to use two different evaluators for different parameters of a single command. It also allows you to evaluate different pieces of a long expression by different methods. It is possible to nest these symbols; each appearance of this symbol switches to the other expression evaluator.

Warning While C++ expression syntax is very useful for manipulating structures and variables, it is not very well-suited as a parser for the parameters of debugger commands. When you are using debugger commands for general purposes, or using debugger extensions, you should set MASM expression syntax as the default. If you need a specific parameter to use C++ expression syntax, use the @@( ) syntax.

For full details on the two different expression types, as well as examples of each, see Expression Syntax.

Numerals in Expressions

Numerals in MASM expressions are interpreted according to the current radix. The N (Set Number Base) command can be used to set the default radix to 16, 10, or 8. All un-prefixed numerals will be interpreted in this base. The default radix can be overridden by specifying the 0x prefix (hexadecimal), the 0n prefix (decimal), the 0t prefix (octal), or the 0y prefix (binary).

Numerals in C++ expressions are interpreted as decimal unless otherwise specified. To specify a hexadecimal integer, prefix it with 0x. To specify an octal integer, prefix it with 0 (zero). However, in the debugger's output, the 0n decimal prefix is sometimes used.

If you wish to display a number in several bases at once, use the .formats (Show Number Formats) command.

Symbols in Expressions

The two types of expressions interpret symbols differently:

  • In MASM expressions, each symbol is interpreted as an address. Depending on what the symbol refers to, this will be the address of a global variable, local variable, function, segment, module, or any other recognized label.
  • In C++ expressions, each symbol is interpreted according to its type. Depending on what the symbol refers to, it may be interpreted as an integer, a data structure, a function pointer, or any other data type. A symbol that does not correspond to a C++ data type (such as an unmodified module name) will result in a syntax error.

If there is a possibility of ambiguity, you can prefix a symbol with a module name and an exclamation point ( ! ), or with an exclamation point alone. For details on symbol recogntion, see Symbol Syntax and Symbol Matching.

Operators in Expressions

Each expression type uses a different collection of operators.

For a description of the operators used in MASM expressions and their precedence rules, see MASM Numbers and Operators.

For a description of the operators used in C++ expressions and their precedence rules, see C++ Numbers and Operators.

The most important point to note is that MASM operations are always byte-based, while C++ operations follow C++ type rules — including the scaling of pointer arithmetic.

For some examples of the different syntaxes, see Expression Examples.


Using Aliases

Aliases are character strings that are automatically replaced with other character strings. They can be used in debugger commands, and are helpful if you wish to avoid retyping certain common phrases.

An alias consists of two parts: the alias name and the alias equivalent. When the alias name is used as part of a debugger command, it is automatically replaced by the alias equivalent before the command is parsed and executed.

The debugger supports two kinds of aliases. User-named aliases are set and are named by the user. Fixed-name aliases are set by the user, and are named $u0, $u1, ..., $u9.

Defining a User-Named Alias

When you define a user-named alias, you can choose both the alias name and the alias equivalent. The alias name can be any text string that does not contain the ENTER keystroke or spaces. The alias equivalent can be any text string that does not contain the ENTER keystroke and does not begin with leading spaces.

To define or redefine one of these aliases, use the AS (Set Alias) command.

To remove an alias, use the AD (Delete Alias) command.

To list all currently-set user-named aliases, use the AL (List Aliases) command.

Defining a Fixed-Name Alias

There are ten fixed-name aliases. Their alias names are $u0, $u1, ..., $u9. Their alias equivalents can be any text string that does not contain the ENTER keystroke.

The R (Registers) command is used to define these values. When defining a fixed-name alias, place a period (.) before the u. The entire text after the equal sign is taken to be the alias equivalent. The alias equivalent can include spaces or semicolons, although leading and trailing spaces will be ignored. This text should not be enclosed in quotes (unless quotes are actually desired in the results).

Note Do not be misled by this odd use of the R (Registers) command. These aliases are neither registers nor pseudo-registers, even though the R command is used to set their alias equivalents, and can also be used to display these equivalents. It is never necessary to prefix these aliases with an "at" ( @ ) sign.

A fixed-name alias defaults to an empty string if it has never been defined.

Using an Alias in the Debugger Command Window

After an alias is defined, it can be used in any command entry. The alias name is automatically replaced with the alias equivalent. It can therefore be used as an expression or as a macro.

An alias name will expand correctly even if it is enclosed in quotation marks. Since the alias equivalent can include any number of quotation marks or semicolons, it can represent multiple commands.

A user-named alias will only expand correctly if it is not touching any other text. The first character of its alias name must either begin the line, or be preceded by a space, a semicolon, or a quotation mark. The last character of its alias name must end the line, or be followed by a space, a semicolon, or a quotation mark.

A fixed-name alias will expand correctly from any point within a line, regardless of how it is embedded within the text of the line.

Examples

Using aliases can eliminate the need to type long or complex symbol names:

0:000> as Short usersrv!NameTooLongToWantToType
0:000> dw Short +8

Here is the same example with a fixed-name alias:

0:000> r $.u0=usersrv!NameTooLongToWantToType
0:000> dw $u0+8

Aliases can be used as macros for commands that will be used often. The following example increments the eax and ebx registers twice:

0:000> as GoUp r eax=eax+1; r ebx=ebx+1
0:000> GoUp
0:000> GoUp

Here is another example using an alias to simplify typing of commands:

0:000> as Cmd "dd esp 14; g"
0:000> bp MyApi Cmd

This same example, using a fixed-name alias:

0:000> r $.u5="dd esp 14; g"
0:000> bp MyApi $u5

Both of the preceding examples are equivalent to the following command:

0:000> bp MyApi "dd esp 14; g"

Recursion

A user-named alias cannot be used in the definition of another user-named alias.

However, a user-named alias can be used in the definition of a fixed-name alias. And a fixed-name alias can be used in the definition of any alias.

When you are using recursive definitions of this type, each alias is translated as soon as it is used. For example, the following gives 3, not 7:

0:000> r $.u2=2
0:000> r $.u1=1+$u2
0:000> r $.u2=6
0:000> ? $u1
Evaluate expression: 3 = 00000003

Similarly, the following gives 3, not 7:

0:000> as fred 2
0:000> r $.u1= 1 + fred
0:000> as fred 6
0:000> ? $u1
Evaluate expression: 3 = 00000003

The following is also permitted, and gives 9:

0:000> r $.u0=2
0:000> r $.u0=7+$u0
0:000> ? $u0
Evaluate expression: 9 = 00000009

The tools.ini File

CDB (and NTSD) support predefining fixed-name aliases in the tools.ini file. To do this, add the desired $u fields to your [NTSD] entry:

[NTSD]
$u1:_ntdll!_RtlRaiseException
$u2:"dd esp 14;g"
$u9:$u1 + 42

User-named aliases cannot be set in the tools.ini file.

Fixed-Name Aliases versus User-Named Aliases

Fixed-name aliases are easier to use than user-named aliases. Their definition syntax is simpler, and they can be listed using the AL (List Aliases) command.

User-named aliases are more powerful, since they will still be replaced if they are used adjacent to other text.

Fixed-name alias replacement occurs before user-named alias replacement.


Using Shell Commands

The debugger can transmit certain commands to the Windows environment in which it is running, or to an MS-DOS® shell running in that environment.

The .shell (MS-DOS Shell) command can be used in any debugger. It allows you to run an MS-DOS command directly from the debugger. If you are performing remote debugging, these shell commands are executed on the server. See Remote Debugging for more details.

The .noshell (Prohibit Shell Commands) command or the -noshell command-line option will disable all shell commands. This prohibition will last as long as the debugger is running, even if a new debugging session is begun. Shell disabling will persist even if a .restart (Restart Kernel Connection) command is issued in KD.

If you are running a debugging server, it may be a good idea to disable shell commands. If the shell is available, a remote connection can use the .shell command to manipulate your machine.

Network Drive Control

In WinDbg, the File | Map Network Drive and File | Disconnect Network Drive menu commands can be used to control the network drive mappings. These changes always take place on the computer on which WinDbg is running — never on any computer that is remotely connected to WinDbg.


The WinDbg Graphical Interface

This section includes:

Using Debugging Information Windows

Using Workspaces

Using the Toolbar and Status Bar

Using the Help File


Using Debugging Information Windows

WinDbg has eight kinds of debugging information windows: the Debugger Command window, the Watch window, the Locals window, the Registers window, the Memory window, the Calls window, the Disassembly window, as well as an unlimited number of Source windows.

This section details the use of these windows in general, rather than the specifics of each kind of window. It covers the following topics:

Opening a Window

Configuring a Window

Moving Through a Window

Changing Text Properties

Cutting and Pasting Text

Arranging the Windows

Closing a Window


Opening a Window

When WinDbg begins a debugging session, the Debugger Command window will automatically open. The Disassembly window will also automatically open, unless Window | Automatically Open Disassembly has been deselected.

Whenever WinDbg discovers a source file that corresponds to the current program counter, it will open a Source window for that file. Source windows can also be opened by a number of other means; see Setting Paths and Loading Files for details.

The following menu selections, toolbar buttons, and shortcut keys can also be used to activate these windows. If the window is not open, it will be opened; if it is open, but inactive or minimized, it will become active and restored to midsize or maximized.

Window | Menu selection | Button | Shortcut key
Command window | View | Command |  | ALT+1
Watch window | View | Watch |  | ALT+2
Locals window | View | Locals |  | ALT+3
Registers window | View | Registers |  | ALT+4
Memory window | View | Memory |  | ALT+5
Calls window | View | Call Stack |  | ALT+6
Disassembly window | View | Disassembly |  | ALT+7
Source window | File | Open Source File |  | CTRL+O
Scratch Pad | View | Scratch Pad |  | ALT+8

A window can also be made active and restored to midsize or maximized by selecting it from the list of open windows at the bottom of the Window menu.


Configuring a Window

Many of the debugging information windows can be customized by clicking buttons or selecting from a popup menu at the top of the window. See the individual window descriptions for details.

Some windows also have properties which can be set with the Edit | Properties menu command. This is equivalent to the following toolbar button:

If the active window has no properties which can be set in this manner, the button and the Edit | Properties menu command will be grayed.


Moving Through a Window

There are several ways of moving through a debugging information window. If a scrollbar appears in a window, you can use it to display more of the window text.

In addition, some windows support the Find, Go to Address, or Go to Line actions.

These actions merely change the WinDbg display. They do not affect the execution of the target or any other debugger operations.

Find

The Find action can be used in the Debugger Command window or in a Source window.

When one of these windows is active, select Edit | Find or press the CTRL+F shortcut key. The Find dialog box will appear.

Enter the text you wish to find in the dialog box window. Select either Up or Down check box to determine the direction of your search. The search will begin wherever the cursor is in the window; you can place the cursor at any point by using the mouse.

Choose Match whole word only if you wish to search for a single whole word. (Choosing this in a search for multiple words always results in a failed search.) Choose Match case to do a case-sensitive search.

Go to Address

The Go to Address action will look for an address in the program being debugged. To activate this option, select Edit | Go to Address, or use the CTRL+G shortcut key.

When the View Code Offset dialog box appears, enter the desired address. This address can be an expression such as a function, symbol, integer memory address, or any valid address expression. If the address is ambiguous, a list box with all ambiguous items is displayed.

After you click OK, the debugger moves the cursor to the beginning of the function or address in the Disassembly window or a Source window.

This action can be used regardless of which window is currently active. If the debugger is in disassembly mode, this address will be found in the Disassembly window. If the debugger is in source mode, this will be found in a Source window if possible; if this is not possible, it will be found in the Disassembly window. If the needed window is not open, it will be opened.

Moving to a Specific Line

The Go to Line action will look for a line number in the active Source window. If the active window is not a Source window, this action cannot be used.

To activate this option, select Edit | Go to Line, or use the CTRL+L shortcut key.

When the Go to Line dialog box appears, enter the desired line number and click OK. The debugger will move the cursor to that line. If the line number is greater than the last line in the file, the cursor will go to the end of the file.


Changing Text Properties

You can customize the font used in all the debugging information windows. You can also change the tab width used in the Source windows.

Setting the Tab Stops

To change the tab stop settings, select View | Options, or use the following toolbar button:

The Options dialog box will appear. Enter the number of spaces to which a tab should be equivalent in the Tab width field, and click OK.

The tab settings affect the display of the code in any Source window.

Setting the Font, Font Style, and Font Size

All debugging information windows share the same font. To change this font, select View | Font, or use the following toolbar button:

In the Font dialog box, select the font, style, and size from the appropriate list boxes, and click OK. All the available fonts are fixed-pitch, as these are the most useful for looking at code.


Cutting and Pasting Text

WinDbg uses the standard Microsoft methods of manipulating text, along with a few additional methods.

Selecting Text

To select text in a Source window, in the Disassembly window, in either pane of the Debugger Command window, or in a dialog box, point the mouse at one end of the text, hold down the left mouse button, and drag the pointer to the other end of the text.

You can also use the Edit | Select All menu command or the CTRL+A shortcut key to select all the text in one of these windows.

The Calls, Watch, Locals, Registers, and Memory window only allow you to select individual cell entries. Clicking the mouse in the desired cell will select that entire cell.

If you select text that you have entered and press the DELETE key or the BACKSPACE key, the text will be deleted, but not copied to the clipboard. If you select text and then type any characters, the new characters will replace what was selected.

Copying Text

To copy text, select that text with the left mouse button. Then use any one of the following methods:

  • Press the right mouse button. (This method only works in some locations. See The Right Mouse Button for details.)
  • Use the Edit | Copy menu command.
  • Press the CTRL+C shortcut key.
  • Click on this toolbar button:

Text can be copied from any debugging information window and from any dialog box.

Cutting Text

To cut text and move it to the clipboard, select that text with the left mouse button. Then use any one of the following methods:

  • Use the Edit | Cut menu command.
  • Press the CTRL+X shortcut key.
  • Press the SHIFT+DEL shortcut key.
  • Click on this toolbar button:

Text can be cut from the bottom pane of the Debugger Command window, from the left column of the Watch window, and from any dialog box (in other words, from any location which supports text entry).

Pasting Text

To paste text from the clipboard, place the cursor where you want the text to be. (Alternatively, select the text you wish to replace.) Then use any of the following methods:

  • Press the right mouse button. (This method only works in some locations, and cannot be used to replace text. See The Right Mouse Button for details.)
  • See below.)
  • Use the Edit | Paste menu command.
  • Press the CTRL+V shortcut key.
  • Click on this toolbar button:

Text can be pasted into the bottom pane of the Debugger Command window, into the left column of the Watch window, and into any dialog box (in other words, into any location which supports text entry).

The Right Mouse Button

The right mouse button has a number of effects which can make copying and pasting much quicker:

  • If you select text in either pane of the Debugger Command window and then press the right mouse button, the text will be copied to the clipboard.
  • If you place the cursor in the entry pane of the Debugger Command window (without selecting any text), or place the cursor in the text entry space of the Watch window, and then press the right mouse button, the contents of the clipboard will be pasted into the window.
  • If you place the cursor in any dialog box, or select text in any dialog box, and then press the right mouse button, a popup menu with Undo, Cut, Copy, Paste, and Select All options will appear. You can choose any of these options.


Arranging the Windows

Each debugging information window can be minimized, made midsize, or maximized by clicking on the standard Windows® buttons in its upper right corner. When midsize, a window can be resized by dragging its right edge, its lower edge, or its lower right corner.

The following menu selections can also be used to control the arrangement of the debugging information windows:

Window | Cascade
Arranges all open windows in an overlapped diagonal pattern. Minimized windows remain minimized, but their icons are moved to the bottom of the WinDbg window.
Window | Tile Horizontally
Arranges all open windows in horizontal strips. (If there are too many open windows, there may be some vertical tiling as well.) Minimized windows remain minimized, but their icons are moved to the bottom of the WinDbg window.
Window | Tile Vertically
Arranges all open windows in vertical strips. (If there are too many open windows, there may be some horizontal tiling as well.) Minimized windows remain minimized, but their icons are moved to the bottom of the WinDbg window.
Window | Arrange
Arranges all open windows in a convenient fashion. This can involve both horizontal and vertical tiling. If Window | Arrange All Windows is not checked, Source windows and the Disassembly window will not be rearranged by this action. Minimized windows remain minimized, but their icons are moved to the bottom of the WinDbg window. (This pattern imitates the old Microsoft® CodeView® debugger's pattern.)

This can also be accomplished by pressing the following toolbar button:

Window | Arrange Icons
Moves the icons representing minimized windows to the bottom of the WinDbg window, but leaves midsize windows unchanged.
Window | Auto-Arrange
When this is checked, all debugging information windows will be automatically arranged every time a window is opened, closed, minimized, or restored. If Window | Arrange All Windows is not checked, Source windows and the Disassembly window will not be rearranged by this action. (The arrangement scheme is the same as that of Window | Arrange.)
Window | Arrange All Windows
When this is checked, all debugging information windows will be affected by Window | Arrange or Window | Auto-Arrange actions. If it is not checked, Source windows and the Disassembly window are immune from these actions.
Window | Overlay Source
When this is checked, multiple source windows will appear in the same location on the screen. This takes effect every time a new source window is opened, and every time the windows are arranged by a Window menu command.


Closing a Window

To close any debugging information window, click on the Close button in the upper-right corner of the window.

If you wish to close the active window, you can also select File | Close Current Window or press the CTRL+F4 shortcut key.

To close all source windows at once, you can select Window | Close All Source Windows.


Using Workspaces

When you exit WinDbg, it saves your session configuration in a workspace. This allows you to easily preserve your settings from one session to another. You can also save or clear the workspaces manually, or even use a workspace to save a debugging session that is still in progress.

This section includes:

Creating and Opening a Workspace

Workspace Contents


Creating and Opening a Workspace

WinDbg has two basic types of workspaces: default workspaces and named workspaces.

Default Workspaces

WinDbg has several different types of default workspaces:

  • The base workspace is used when WinDbg is in a dormant state.
  • The default user-mode workspace is used when attaching to a user-mode process (with the -p command-line option or by using the File | Attach to a Process menu command).
  • The remote default workspace is used when connecting to a Debugging Server.
  • The default kernel-mode workspace is used when WinDbg begins a kernel-mode debugging session.
  • The processor-specific workspace is used during kernel-mode debugging once WinDbg attaches to the target computer. There are separate processor-specific workspaces for the x86, IA-64, and AMD64 architectures.
  • When WinDbg creates a user-mode process for debugging, a workspace is created for that executable. Each created executable will have its own workspace.
  • When WinDbg analyzes a dump file, a workspace is created for that dump file analysis session. Each dump file will have its own workspace.

Whenever you begin a debugging session, the appropriate workspace is loaded. When you end a debugging session or exit WinDbg, a popup window appears and asks you whether you wish to save the changes you have made to the current workspace. If you start WinDbg with the -Q command-line option , these popup windows will not appear, and no changes will be saved.

Workspaces load in a cumulative fashion. The base workspace is always loaded first. When a particular debugging action is begun, the appropriate workspace is loaded. So most debugging will be done with two workspaces active. Kernel-mode debugging will be done with three workspaces active: the base workspace, the default kernel-mode workspace, and the processor-specific workspace.

For greatest efficiency, you should save settings in lower-level workspaces if they should be applied to all your WinDbg work.

To directly access the base workspace, start WinDbg with no target, or select Debug | Stop Debugging after your session is complete. You can then make any edits which are allowable in the base workspace.

There is one exception to the cumulative nature of workspaces. A workspace will not close a window. So if the base workspace opens the Locals window, the Locals window will remain open once debugging has begun and a higher-level workspace has become dominant.

Named Workspaces

Workspaces can also be given names and then saved or loaded individually. Once a named workspace has been loaded, all automatic loading and saving of default workspaces is disabled.

Named workspaces contain some additional information that default workspaces do not. See Workspace Contents for details.

Opening, Saving, and Clearing Workspaces

Use the following menu commands and command-line options to control workspaces:

  • The -W command-line option can be used to open and load a named workspace.
  • The -WF command-line option can be used to open and load a workspace from a file.
  • The -WX command-line option disables all automatic workspace loading. Only explicit workspace commands will cause workspaces to be saved or loaded.
  • The File | Open Workspace menu command or the CTRL+W shortcut key can be used to open and load a named workspace.
  • The File | Save Workspace menu command can be used to save the current default workspace or the current named workspace.
  • The File | Save Workspace As menu command can be used to assign a name to the the current workspace and save it.
  • The File | Clear Workspace menu command allows you to delete specific items and settings from the current workspace.
  • The File | Delete Workspaces menu command allows you to delete entire workspaces.
  • The File | Open Workspace in File menu command can be used to open and load a workspace from a file.
  • The File | Save Workspace to File menu command can be used to save a workspace to a file.


Workspace Contents

All default workspaces and named workspaces preserve the following information about the WinDbg graphical interface:

  • The title of the WinDbg window
  • The size and position of the WinDbg window on the desktop
  • Which debugging information windows are open
  • The size and position of each window, and the location of the Debugger Command window divider
  • The default window options (Auto-Arrange, Arrange All Windows, Overlay Source, Automatically Open Disassembly)
  • The default font
  • Visibility of the toolbar and status bar, as well the individual toolbars on each debugging information window
  • Customization of the Register window
  • Flags in the Calls window and the Symbol window
  • Items being viewed in the Watch window

Each workspace preserves the following information about the WinDbg configuration settings:

  • The symbol path
  • The executable image path
  • The source path (In case of remote debugging, both the main source path and the local source path are saved.)
  • Log file settings
  • The COM or 1394 kernel connection settings
  • The most recent paths in each file open dialog box
  • The .enable_unicode setting

Each workspace preserves the following information about the current debugging session:

  • All break and handling information for exceptions and events
  • All open source files

In addition, breakpoint information is saved in workspaces, including break address and status. This means that breakpoints that are active when one session ends will be active when the next session is started. However, some of these breakpoints may be unresolved if the proper modules have not yet been loaded.

Breakpoints specified by a symbol expression, by a line number, or by using the mouse in a Source window are all saved in workspaces. To avoid ambiguity, breakpoints specified by numerical address alone, or by using the mouse in a Disassembly or Calls window, are not saved in workspaces.

If multiple user-mode processes are being debugged, only breakpoints associated with process zero will be saved.

Named Workspaces

Named workspaces contain additional information that is not stored in default workspaces.

This additional information includes information about the current session state. When a named workspace is saved, the current session will be saved. If this workspace is later opened, this session will be automatically restarted.

Only kernel debugging, dump file debugging, and debugging of spawned user-mode processes can be started in this way. Remote sessions and user-mode processes that the debugger attached to will not have this session information saved in their workspaces.

A named workspace of this type cannot be opened if another session is already active.

Debugging Clients and Workspaces

When WinDbg is being used as a Debugging Client, its workspace will only save values set through the graphical interface. Changes made through the Debugger Command window will not be saved. (This guarantees that only changes made by the local client will be reflected, since the Debugger Command window will accept input from all clients as well as the Debugging Server.) For more details, see Controlling the Remote Debugging Session.


Using the Toolbar and Status Bar

The toolbar appears beneath the menu bar, near the top of the WinDbg window. The status bar appears at the bottom of the WinDbg window.

Using the Toolbar

Toolbar

The toolbar buttons have various effects, but most of them provide shortcuts for menu selections. To execute the command associated with a toolbar button, click the toolbar button. See the Toolbar Buttons reference section for a description of each button.

When a button cannot be used, it appears dimmed.

Using the Status Bar

Status Bar

The following table describes the fields of the WinDbg status bar.

Field | Description
Message | Displays messages from the debugger.
Ln, Col | Displays the line number and column number at the insertion point in the active Source window.
Proc | Shows the internal decimal number of the process being debugged, followed by its hexadecimal process ID.
Thrd | Shows the internal decimal number of the thread being debugged, followed by its hexadecimal thread ID.
ASM | Indicates that WinDbg is in assembly mode. If this is grayed, WinDbg is in source mode.
OVR | Indicates overtype (insert) mode.
CAPS | Indicates that CAPS LOCK is on.
NUM | Indicates that NUM LOCK is on.

Hiding the Toolbar or Status Bar

To display or hide the toolbar, select or deselect View | Toolbar. To display or hide the status bar, select or deselect View | Status Bar.

Hiding the toolbar or the status bar gives you more room for debugging information windows in the WinDbg display area.

Setting the Window Title

The title of the main WinDbg window can be changed by using the .wtitle (Set Window Title) command.


Using the Help File

The Help file you are reading is named Using Debugging Tools for Windows. It is included as part of the Debugging Tools for Windows package.

This documentation uses the viewer supplied with Microsoft HTML Help (hh.exe). This viewer provides a table of contents and an index. It also allows you to search through the documentation, mark certain pages as "favorites", and print one or more pages.

The Contents Tab

The Contents tab provides an expandable view of the Using Debugging Tools for Windows' table of contents.

By clicking on the "+" sign next to a node or double-clicking on the node's title, you can expand or contract the table of contents under that node.

The Index Tab

The Index tab displays the complete index of terms used in Using Debugging Tools for Windows. You can enter the beginning of a term or use the scrollbar to look through this index.

The Search Tab

The Search tab gives you the ability to search for any word or phrase contained in the documentation. You can search all text, or limit your search to topic titles.

To search for phrases containing more than one word, enclose it in quotation marks ("). You can connect multiple words and phrases with the terms AND, OR, and NOT. The default is AND. Note that the combination "AND NOT" is invalid — to search for pages containing x and not y, the proper syntax is "x NOT y". The search term NEAR is also permitted.

Wildcard characters are also permitted. Use a question mark (?) to represent any single character, and an asterisk (*) to represents zero or more characters. However, wildcards are not permitted within quoted strings.

All letters and numbers are treated literally, but some symbols are not permitted in searches. A search returns a list of all pages that match the specified criteria. If you check the Search previous results box you can then search these results for more terms.

The Favorites Tab

The Favorites Tab lets you save the titles of commonly-visited topics. While viewing a topic, select the Favorites tab and click the Add button.

To rename a page on the favorites list, click on its name twice slowly, and retype the name. To view a page on the Favorites list, double-click on its name, or click on it once and select Display. To remove a page from the Favorites list, click on it once and select Remove.

Printing Topics

To print one or more topics, select a topic icon on the Contents tab. Then click the Print button on the taskbar. You will be asked whether you'd like to print just the selected topic, or that topic and all of its subtopics.

You can also print the topic you are viewing by right-clicking within the view window, and selecting Print from the context menu. However, this method does not allow you to print subtopics.

Searching within a Topic

To search for a text string within the topic you are viewing, press CTRL+F, or select Find in this Topic from the Edit menu.

Methods of Accessing this Help File

There are several ways to open this Help file:

  • Use the shortcut Start | Programs | Debugging Tools for Windows | Debugging Help.
  • Locate the file debugger.chm in Windows Explorer and double-click on it.
  • From a Command Prompt window, navigate to the folder containing debugger.chm and use the following command:
    hh debugger.chm
  • From any debugger, use the .hh (Open HTML Help File) command.
  • From WinDbg, use the Help | Contents menu command — this will open the Help file and select the Contents tab.
  • From WinDbg, use the Help | Index menu command — this will open the Help file and select the Index tab.
  • From WinDbg, use the Help | Search menu command — this will open the Help file and select the Search tab.
  • Many dialog boxes in WinDbg have "Help" buttons. Selecting one of these buttons will open this documentation and turn to the relevant page.

Updating this Help File

To obtain an updated version of this Help file, you should install the most recent version of Debugging Tools for Windows. For details, see Installing from the Web.

Warning When you update the documentation, any Favorites you have added will be lost.


Debugger Configuration

This section includes:

Keeping a Log File

Specifying Module and Function Owners

Setting Paths and Loading Files

Controlling Exceptions and Events


Keeping a Log File

The debugger can write a log file which records the debugging session. The entire contents of the Debugger Command window will be recorded in this log file: this includes the commands that you type and the responses from the debugger.

In WinDbg, some menu and toolbar actions cause a display to appear in the Debugger Command window, while others do not. The log file will not have any record of actions that do not generate text in this window.

Opening a New Log File

To open a new log file, or to overwrite a previous log file, you can use the following methods:

  • (Before starting the debugger — CDB and KD only) Set the _NT_DEBUG_LOG_FILE_OPEN environment variable.
  • (When starting the debugger) Use the -logo command-line option.
  • Use the .logopen (Open Log File) command.
  • (WinDbg only) Use the Edit | Open/Close Log File menu command.

Appending to an Existing Log File

To append to a log file, you can use the following methods:

  • (Before starting the debugger — CDB and KD only) Set the _NT_DEBUG_LOG_FILE_APPEND environment variable.
  • (When starting the debugger) Use the -loga command-line option.
  • Use the .logappend (Append Log File) command.
  • (WinDbg only) Use the Edit | Open/Close Log File menu command, and check Append.

Closing a Log File

To close the currently-open log file, you can use the following methods:

  • Use the .logclose (Close Log File) command.
  • (WinDbg only) Use the Edit | Open/Close Log File menu command and select Close Open Log File.

Checking Log File Status

To determine the log file status, you can use the following methods:

  • Use the .logfile (Display Log File Status) command.
  • (WinDbg only) Open the Edit | Open/Close Log File menu command and see if a log file is listed.


Specifying Module and Function Owners

The !analyze and !owner extensions use a file called triage.ini to determine the owner of the symbols that the debugger encounters.

When these extensions are used, the identities of the function or module owner is displayed after the word Followup.

The triage.ini file is a text file that resides in the triage subdirectory of your Debugging Tools for Windows installation. A sample triage.ini file is included as part of the Debugging Tools for Windows package.

Warning If you install an updated version of Debugging Tools for Windows in the same directory as the current version, it will overwrite all the files in that directory — including triage.ini! After you modify or replace the sample triage.ini file, be sure to save a copy of it to a different directory. After reinstalling the debuggers, you can copy the saved triage.ini over the default version.

Format of the Triage.ini File

Although the purpose of the triage.ini file is to help a debugger operator identify the owner of a function which has broken into the debugger, the "owner" strings in this file file can be anything that would be of use in debugging. They can be names of the people who wrote the code or maintain the code. Or they can be short notes instructing the user what to do when an error occurs in this module or function.

The basic syntax of each line in this file is

Module[!Function]=Owner

A wildcard (*) can only appear at the end of a module or function name. If it appears elsewhere, it is taken as a literal character.

Spaces are not permitted in the owner string — if they are present, they will be ignored.

See Special Triage.ini Syntax for more syntax options.

Here is a sample triage.ini file:

module1=Person1
module2!functionA=Person2
module2!functionB=Person3
module2!funct*=Person4
module2!*=Person5
module3!singleFunction=Person6
mod*!functionC=Person7

Triage.ini and !owner

When you pass a module or function name to the !owner extension, the debugger displays the word Followup followed by the name of the module or function's owner.

The following is an example using the sample triage.ini file shown above:

0:000> !owner module2!functionB
Followup:  Person3

According to the file, "Person3" owns module2!functionB, while "Person4" owns module2!funct*. Both of these match the argument passed to !owner, so the more complete match is used.

Triage.ini and !analyze

When the !analyze extension is used, the debugger looks at the top frame in the stack and attempts to determine the owner of the module and function in this frame. If the owner can be determined, this information is displayed.

If the owner cannot be determined, the debugger passes to the next stack frame, and so on, until the owner is determined or the stack is completely examined.

If the owner can be determined, their name will be displayed after the word Followup. If the stack is exhausted without any information being found, no name is displayed.

The following is an example using the sample triage.ini file shown above.

Suppose the first frame on the stack is MyModule!someFunction. The debugger fails to find MyModule in the triage.ini file. So it passes on to the second frame on the stack.

Suppose this is module3!anotherFunction. The debugger does see an entry for module3, but there is no match for anotherFunction in this module. So the debugger proceeds on to the third frame.

Suppose this frame is module2!functionC. The debugger first looks for an exact match; there is none. It then trims the function name down and discovers module2!funct* in triage.ini. This ends the search — the owner has been determined to be "Person4".

The debugger will then display something similar to the following:

0:000> !analyze
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

Probably caused by : module2 ( module2!functionC+15a )

Followup: Person4
---------

A more complete match takes precedence over a shorter match. However, a module name match is always preferred to a function name match. So if module2!funct* had not been in this file, the debugger would have selected module2!* as the match. And if both module2!funct* and module2!* were removed, then mod*!functionC would have been selected.

Special Triage.ini Syntax

Omitting the exclamation point and function name, or following a module name with !*, have the same effect: all functions in that module are indicated. If a function within this module is also specified separately, the more precise specification will take precedence.

The word default, used as either a module name or a function name, is equivalent to a wildcard. For example, nt!* is the same as nt!default, and default by itself is the same as *!*.

If a match is made, but the word ignore appears to the right of the equal sign, the debugger will go on to the next frame in the stack.

You can prefix an owner's name with last_ or maybe_. This gives the owner less priority when !analyze is run. The debugger will choose a definite match lower on the stack over a maybe_ match higher on the stack, and will choose a maybe_ match lower on the stack over a last_ match higher on the stack.

Sample Triage.ini

There is a sample triage.ini template included in the Debugging Tools for Windows package. You can add the owners of any modules and functions you wish to this file. If you wish to have no global default you should delete the default=MachineOwner line at the beginning of this file.


Setting Paths and Loading Files

To debug effectively, the debugger should have access to as much information about the target computer or target application as possible.

In many cases, the debugger will be able to locate the files it needs on its own. But in case it cannot do this, you can steer the debugger to the proper files by setting the executable image path, the symbol path, or the source path. You can also load source files at any time, regardless of the source path.

All three of these paths have the same syntax: they consist of multiple directory paths, separated by semicolons. Relative paths are supported, but unless you will always launch the debugger from the same directory, it is preferable to begin each path with a drive letter or a network share. Network shares are also supported.

There are a number of ways of setting and displaying each path, as well as loading and unloading individual files. If you attempt to add an invalid directory to a path through an environment variable, the debugger will disregard this directory.

The Executable Image Path

The executable image path specifies the directories in which the binary executable files are located.

In most cases, the debugger will know the location of the executables, so this path does not need to be set.

However, there are cases where this path is required. For instance, kernel-mode small memory dump files do not contain all the executables residing in memory at the time of the crash. Similarly, user-mode minidump files do not contain the application binaries. Setting this path allows the debugger to find these binary files.

The debugger searches the executable image path recursively: each directory listed in this path will have its entire subdirectory tree searched.

There are several methods of controlling the executable image path:

  • (Before starting the debugger) The _NT_EXECUTABLE_IMAGE_PATH environment variable can be used to set the path.
  • (When starting the debugger) The -i command-line option can be used to set the path.
  • The .exepath command can be used to display, set, change, or append to the path.
  • (WinDbg only) The File | Image File Path menu command or the CTRL+I shortcut key can be used to display, set, change, or append to the path.

If you use the -sins command-line option, the executable image path environment variable is ignored.

The Symbol Path

The symbol path specifies the directories in which the symbol files are located. See Symbols for an overview of symbol files.

Some compilers (such as Microsoft® Visual Studio®) place the symbol files in the same directory as the binaries. The symbol files and the checked binaries contain path and filename information. This often allows the debugger to find the symbol files automatically. If you are debugging a user-mode process on the machine where the executable was built, and if the symbol files are still in their original location, the debugger will be able to locate the symbol files without this path being set.

In most other cases, you will need to set the symbol path to point to your symbol file locations.

For each directory in the symbol path, the debugger will look in three directories. For instance, if the symbol path includes the directory c:\MyDir, and the debugger is looking for symbol information for a DLL, the debugger will first look in c:\MyDir\symbols\dll, then in c:\MyDir\dll, and finally in c:\MyDir. It will repeat this for each directory in the symbol path. Finally, it will look in the current directory, and then the current directory with \dll appended to it. (The debugger will append dll, exe, or sys, depending on what binaries it is debugging.)

However, since symbol files all have date and time stamps, there is no danger that the debugger will use the wrong symbols just because they are found first in this sequence. The debugger will always look for the symbols which match the time stamp on the binaries it is debugging. See Invalid or Missing Symbols for some responses in case these files are not available.

If you are connected to a corporate network, it might be easier to use a symbol server. See Using Symbol Servers and Symbol Stores for details.

The debugger's default behavior is to use lazy symbol loading (also called deferred symbol loading). This means that symbols are not actually loaded until they are needed. However, if the symbol path is changed, all already-loaded symbols are immediately reloaded. See Deferred Symbol Loading for an explanation of lazy symbol loading and how to activate and deactivate it.

Lazy symbol loading can be turned off in CDB and KD with the -s command-line option. Symbol loading can also be forced with the LD (Load Symbols) command, or by using the .reload (Reload Module) command with the /f option.

There are several methods of controlling the symbol path:

  • (Before starting the debugger) The _NT_SYMBOL_PATH and _NT_ALT_SYMBOL_PATH environment variables can be used to set the path. The symbol path is created by appending the _NT_SYMBOL_PATH after the _NT_ALT_SYMBOL_PATH. (Normally, the entire path is set through the _NT_SYMBOL_PATH. However, you might want to use _NT_ALT_SYMBOL_PATH to override these settings in special cases — for instance, if you have private versions of shared symbol files.)
  • (When starting the debugger) The -y command-line option can be used to set the path.
  • The .sympath command can be used to display, set, change, or append to the path.
  • (WinDbg only) The File | Symbol File Path menu command or the CTRL+S shortcut key can be used to display, set, change, or append to the path.

If you use the -sins command-line option, the symbol path environment variable is ignored.

The Source Path

The source path specifies the directories in which the C and C++ source files are located.

If you are debugging a user-mode process on the machine where the executable was built, and if the source files are still in their original location, the debugger will be able to locate the source files automatically.

In most other cases, you will need to set the source path or load the individual source files.

When you are performing remote debugging through the debugger, the source path is used by the Debugging Server. If you are using WinDbg as your debugger, each Debugging Client has its own local source path as well. All source-related commands will access the source files on the local computer. So the proper paths have to be set on any client or server which wishes to use source commands.

This multiple-path system also allows a Debugging Client to use source-related commands without actually sharing the source files with other clients or with the server. This is useful if there are private or confidential source files which one of the users has access to.

There are several methods of controlling the source path and local source path:

  • (Before starting the debugger) The _NT_SOURCE_PATH environment variable can be used to set the source path.
  • (When starting the debugger) The -srcpath command-line option can be used to set the source path.
  • The .srcpath command can be used to display, set, change, or append to the source path.
  • (WinDbg only) The .lsrcpath command can be used to display, set, change, or append to the local source path.
  • (WinDbg only) The File | Source File Path menu command or the CTRL+P shortcut key can be used to display, set, change, or append to either the source path or the local source path.

There are also several methods of directly opening or closing a source file:

  • The LSF (Load or Unload Source File) command can be used to open or close a source file.
  • (WinDbg only) The .open (Open Source File) command can be used to open a source file.
  • (WinDbg only) The File | Open Source File menu command or the CTRL+O shortcut key can be used to open a source file. The following toolbar button can also be used:

  • (WinDbg only) The File | Recent Files menu command can be used to open one of the four most recently-opened source files.
  • (WinDbg only) To close a source file, select File | Close Current Window or simply click on the "X" in the corner of the Source window.

See Debugging in Source Mode for a detailed description of the use of source files.


Controlling Exceptions and Events

Exceptions in user-mode and kernel-mode programs can be caught and handled by a variety of methods. An active debugger, a postmortem debugger, or an internal error handling routine are all common ways to handle exceptions.

For a description of the precedence order of these various exception handlers, see Enabling Postmortem Debugging.

When Windows allows a debugger to handle an exception, the application that generated the exception will break into the debugger. This means that the application will halt and the debugger will become active. The debugger will then have the option of handling the exception in some way or otherwise analyzing the situation. The debugger can then terminate the process or let it resume running.

If the debugger ignores the exception and lets the program continue running, the operating system will look for other exception handlers as if no debugger was present. If the exception is handled, the program will continue running. However, if the exception remains unhandled the debugger will then be given a second chance to deal with the situation.

Using the Debugger to Analyze an Exception

When an exception or event breaks into the debugger, you can use it to examine the code being executed and the memory being used by the program. By altering certain quantities or jumping to a different point in the program, you may be able to remove the cause of the exception.

You can resume execution by issuing a GH (Go with Exception Handled) or GN (Go with Exception Not Handled) command.

If you issue the GN command in the face of a "second-chance" exception, the program will terminate.

Kernel-Mode Exceptions

Exceptions which occur in kernel-mode code are more serious than user-mode exceptions. If they are not handled, a bug check will be issued and the entire system will halt.

As with user-mode exceptions, if a kernel-mode debugger is attached to the system it will be notified before the bug check screen ("blue screen") appears. If no debugger is attached, the blue screen will appear. In this case, a crash dump file may be created.

Controlling Exceptions and Events from the Debugger

The debugger can be configured to react to specified exceptions and events in a pre-determined way.

The debugger can set the break status for each exception or event. The event can cause a break into the debugger as soon as it occurs (the "first chance"); it can break in after other error handlers have been given an opportunity to respond (the "second chance"); it can just send the debugger a message but continue executing; or it can be ignored entirely.

The debugger can also set the handling status for each exception and event. The event can be treated as a handled exception or as an unhandled exception. (Of course, events which are not actually errors will not require any handling.)

Break status and handling status can be controlled by the following methods:

  • Use the SXE, SXD, SXN, or SXI command in the Debugger Command window.
  • (CDB only) Use the -x, -xe, -xd, -xn, or -xi option on the CDB command line.
  • (CDB only) Use the sxe or sxd keyword can be used in the tools.ini file.
  • (WinDbg only) Use the Debug | Event Filters menu selection to open the Event Filters dialog box, and choose the desired options in this box.

The SX* command, the -x* command-line option, and the sx* Tools.ini keyword normally set the break status of the specified event. Adding the -h option causes the handling status to be set instead.

There are four special event codes (cc, hc, bpec, and ssec) which always specify handling status rather than break status.

You can display the most recent exception or event by using the .lastevent (Display Last Event) command.

Controlling Break Status

When you set the break status of an exception or event, the following options are possible:

Command | Status Name | Description
SXE or -xe | Break (Enabled) | When this exception occurs, the target will immediately break into the debugger. This will happen before any other error handlers are activated — this is called first chance handling.
SXD or -xd | Second chance break (Disabled) | The debugger will not break for a first-chance exception of this type (although a message will be displayed). If other error handlers then fail to address this exception, execution will halt and the target will break into the debugger. This is called second chance handling.
SXN or -xn | Output (Notify) | When this exception occurs, the target application will not break into the debugger at all. However, a message informing the user of this exception will be displayed.
SXI or -xi | Ignore | When this exception occurs, the target application will not break into the debugger at all, and no message will be displayed.

If an exception is not anticipated by an SX* setting, it will break into the debugger on the second chance. The default status for events is listed below.

To set break status using the WinDbg graphical interface, select Debug | Event Filters from the menu, click on the desired event from the list in the Event Filters dialog box, and then select Enabled, Disabled, Output, or Ignore.

Controlling Handling Status

All events will be considered unhandled unless the GH (Go with Exception Handled) command is used.

The same is true of exceptions, unless the SX* command is used with the -h option.

Additionally, there are three events (invalid handles, STATUS_BREAKPOINT break instructions, and single-step exceptions) which can have their handling status configured by the SX* options. This is separate from their break configuration. When configuring their break status, these events are respectively named ch, bpe, and sse. When configuring their handling status, they are named hc, bpec, and ssec. (See full listing of events below.)

The CTRL+C event (cc) can have its handling status configured, but not its break status. If an application receives a CTRL+C, it will always break into the debugger.

When using the SX* command on the cc, hc, bpec, and ssec events, or when using the SX* command with the -h option on an exception, the following effects result:

Command | Status Name | Description
SXE | Handled | The event will be considered handled when execution resumes.
SXD, SXN, SXI | Not Handled | The event will be considered not handled when execution resumes.

To set handling status using the WinDbg graphical interface, select Debug | Event Filters from the menu, click on the desired event from the list in the Event Filters dialog box, and then select Handled or Not Handled.

Automatic Commands

The debugger also allows you to set commands which will be automatically executed if the event or exception causes a break into the debugger. A command string for the first-chance break and a command string for the second-chance break are permitted. These can be set with the SX* command or the Debug | Event Filters menu command. Each command string can contain multiple commands separated with semicolons.

These commands will be executed regardless of the break status. In other words, if the break status is "Ignore," the command will still be executed; if the break status is "Second-chance break," the first-chance command will be executed when the exception first occurs, before any other exception handlers are involved. The command string can end with an execution command such as G (Go), GH (Go with Exception Handled), or GN (Go with Exception Not Handled).

Event Definitions and Defaults

The following exceptions can have their break status or handling status changed. Their default break status is indicated.

Their default handling status is always Not Handled. You should be very careful about changing this — if you change this to Handled, all first-chance and second-chance exceptions of this type will be considered handled, and this will bypass all the exception-handling routines.

Event Code | Meaning | Default Break Status
av | Access violation | Break
dm | Data misaligned | Break
dz | Divide by zero | Break
eh | C++ EH exception | Second-chance break
gp | Guard page violation | Break
ii | Illegal instruction | Second-chance break
iov | Integer overflow | Break
ip | In-page I/O error | Break
isc | Invalid system call | Break
lsq | Invalid lock sequence | Break
sbo | Stack buffer overflow | Break
sov | Stack overflow | Break
wkd | Wake debugger | Break
aph | Application hang This exception is triggered if Windows concludes that a process has "hung" | Break
3c | Child application termination | Second-chance break
ch hc | Invalid handle | Break
Number | Any numbered exception | Second-chance break

Note The ch and hc event codes refer to the same exception. When you are controlling its break status, use sx* ch. When you are controlling its handling status, use sx* hc.

The following exceptions can have their break status or handling status changed. Their default break status is indicated.

Their default handling status is always Handled. Since these exceptions are used for communication with the debugger, you will usually not want to change their status to Not Handled, as this would cause other exception handlers to catch them if the debugger chooses to ignore them.

An application can use the DBG_COMMAND_EXCEPTION (dbce) to communicate with the debugger. This does not essentially differ from a breakpoint, but you can use the SX* command to react in a specific way when this occurs.

Event Code | Meaning | Default Break Status
dbce | Special debugger command exception | Ignore
vcpp | Special Visual C++ exception | Ignore
wos | WOW64 single-step exception | Break
wob | WOW64 breakpoint exception- | Break
sse ssec | Single-step exception | Break
bpe bpec | Breakpoint exception | Break
cce cc | CTRL+C or CTRL+BREAK This exception is triggered if the target is a console application and CTRL+C or CTRL+BREAK is passed to it. | Break

Note The final three exceptions in the table above have two different event codes each. When you are controlling their break status, use sse, bpe, and cce. When you are controlling their handling status, use ssec, bpec, and cc.

The following events can have their break status changed. Since these are not exceptions, their handling status is irrelevant.

Event Code | Meaning | Default Break Status
ser | System error | Ignore
cpr | Process creation This event can only be controlled if debugging of child processes has been activated through CDB's -o command-line option. | Ignore
epr | Process exit This event can only be controlled if debugging of child processes has been activated through CDB's -o command-line option. | Ignore
ct | Thread creation | Ignore
et | Thread exit | Ignore
ld[:Module] | Load module If Module is specified, the break will occur when the module with this name is loaded. If it is not specified, the break will occur when any module is loaded. The debugger will only remember the most recent ld setting; separate settings for separate modules are not supported. There should be either a colon or a space between ld and Module. | Output
ud[:Module] | Unload module If Module is specified, the break will occur when the module with this name or at this base address is unloaded. If it is not specified, the break will occur when any module is unloaded. The debugger will only remember the most recent ud setting; separate settings for separate modules are not supported. There should be either a colon or a space between ud and baseaddr. | Output
out | Target application output | Ignore
ibp | Initial break point (This occurs at the beginning of the debug session, as well as after restarting or rebooting.) | In user mode: Break. This can be changed to Ignore by using the -g command-line option. In kernel mode: Ignore. This can be changed to Enabled by a variety of methods; see Crashing and Rebooting the Target Computer for details.
iml | Initial module load (Kernel mode only) | Ignore. This can be changed to Break by a variety of methods. See Crashing and Rebooting the Target Computer for details.


Debugger Operation (General)

This section includes:

Controlling the Target

Using Breakpoints

Reading and Writing Memory

Reading and Writing Registers and Flags

Viewing the Call Stack

Debugging in Assembly Mode

Debugging in Source Mode

Debugging BIOS Code

Ending the Debugging Session


Controlling the Target

While debugging a target application in user mode or target computer in kernel mode, there are two basic states. The target can be running or the target can be stopped.

When the debugger first connects to a user-mode target, it will immediately stop the target, unless the -g command-line option was used.

When the debugger connects to a kernel-mode target, it will leave the target running, unless the -b command-line option was used, or the target system has already crashed, or the target system is still halted as a result of an earlier kernel debugging action.

When the Target is Running

When the target is running, most debugger actions are unavailable.

If you wish to stop a running target, you can issue a Break command. This causes the debugger to break into the target: in other words, it will stop the target and all control will be given to the debugger. The program may not break immediately. For example, if all threads are currently executing system code, or are in a wait operation, the program will break only after control has returned to the program's code.

If a running target encounters an exception, if certain events occur, if a breakpoint is hit, or if the program terminates normally, the target will break into the debugger. This will stop the target and give all control to the debugger. A message will be displayed in the Debugger Command window describing the error, event, or breakpoint.

When the Target is Stopped

A variety of commands exist to start or control the target's execution:

  • To cause the application to begin running, issue the Go command.
  • To step through the program one instruction at a time, use the Step Into or Step Over commands. If a function call occurs, Step Into will enter the function and continue stepping through each instruction, while Step Over will treat the function call as a single step. When the debugger is in Assembly Mode, stepping is done one machine instruction at a time. When the debugger is in Source Mode, stepping is done one source line at a time.
  • To finish the current function and stop when the return occurs, use the Step Out or Trace and Watch commands. The Step Out command will continue until the current function ends. Trace and Watch will do the same and also display a summary of that function's calls. However, the Trace and Watch command has to be issued on the first instruction of the function in question. On IA-64 machines, Trace to Next Branch will execute until a branch instruction is encountered.
  • If an exception has occurred, the Go with Exception Handled and Go with Exception Not Handled commands can be used to resume execution and control the status of the exception. (See Controlling Exceptions and Events for related information.)
  • (WinDbg only) If you select a line in the Disassembly window or a Source window and then use the Run to Cursor command, the program will execute until this line is reached.
  • (User Mode only) To terminate the target application and restart it from the beginning, use the Restart command. This command can only be used with a process which was originally created by the debugger. After the process is restarted it immediately breaks into the debugger.
  • (WinDbg only) To terminate the target application and clear the debugger, use the Stop Debugging command. This allows you to begin debugging a different target.

Command Forms

Most of these commands exists in several forms. A basic text command can be used in CDB, KD, or WinDbg. In addition, WinDbg supports command execution through menu items, toolbar buttons, and shortcut keys.

The text commands often support additional options, such as changing the location of the program counter or executing a fixed number of instructions. See the individual command pages for details.

The following table lists the forms of these commands and contains jumps to the individual reference pages:

Command Name | Text Command | WinDbg Button | WinDbg Menu | WinDbg Shortcut Key
Break | (CDB/KD only) CTRL+C |  | Debug | Break | CTRL+BREAK
Go | G (Go) |  | Debug | Go | F5
Step Into | T (Trace) |  | Debug | Step Into | F11 F8
Step Over | P (Step) |  | Debug | Step Over | F10
Step Out | g @$ra |  | Debug | Step Out | SHIFT+F11
Go to Next Call | PC (Step to Next Call) TC (Trace to Next Call) |  |  |
Go to Next Branch | (Kernel mode only) TB (Trace to Next Branch) |  |  |
Trace and Watch | WT (Trace and Watch Data) |  |  |
Trace to Next Branch | TB (Trace to Next Branch) |  |  |
Go with Exception Handled | GH (Go with Exception Handled) |  | Debug | Go Handled Exception |
Go with Exception Not Handled | GN (Go with Exception Not Handled) |  | Debug | Go Unhandled Exception |
Run to Cursor |  |  | Debug | Run to Cursor | F7 CTRL+F10
Restart | .restart (Restart Target Application) |  | Debug | Restart | CTRL+SHIFT+F5
Stop Debugging |  |  | Debug | Stop Debugging | SHIFT+F5

For information about rebooting the target computer, see Crashing and Rebooting the Target Computer.

Command-Line Options

If you do not wish the application to stop upon loading, use CDB or WinDbg with the -g command-line option. This will start the program, and the debugger will only be alerted if a problem occurs or if a breakpoint is hit.

CDB and WinDbg also support the -G command-line option, which causes the debugging session to terminate if the application completes properly.

Thus the command line

cdb -g -G ApplicationName

will attempt to run the application from start to finish, and the debugger prompt will appear only if an error occurs.

The -pt command-line option can be used to set the break timeout. There are certain problems that can render the target incapable of communicating with the debugger. If a break command is issued and the debugger is unable to break into the target after this time, it will display a "Break-in timed out" message.

At this point, the debugger will give up attempting to break into the target. Instead, it will freeze the target and allow the user to examine (but not control) the target application.

The default timeout is 30 seconds.


Using Breakpoints

Breakpoints are places in the executable code at which the operating system will halt execution and break into the debugger. You can then analyze the target and issue other debugger commands.

Breakpoint addresses can be specified by virtual address, by module and routine offsets, or by source file and line number (when in source mode). If the breakpoint is placed on a routine with no offset, it will be activated when that routine is entered.

There are a number of additional kinds of breakpoints. A breakpoint can be associated with a certain thread. A breakpoint can allow a fixed number of passes through an address before it is triggered. A breakpoint can automatically issue certain commands when it is triggered. And a breakpoint can be set on non-executable memory and watch for that location to be read or written to.

If you are debugging more than one process in user mode, the collection of breakpoints will depend on the current process. To view or change a process' breakpoints, you will have to select it as the current process. See Controlling Processes and Threads for details.

Methods of Controlling Breakpoints

The following methods can be used to control or display breakpoints:

  • The BL (Breakpoint List) command will list all the current breakpoints and their current status.
  • The BP (Set Breakpoint) command will set a new breakpoint.
  • The BU (Set Unresolved Breakpoint) command will set a new breakpoint. Breakpoints set with BU have different characteristics than breakpoints set with BP; see details below.
  • The BM (Set Symbol Breakpoint) command will set new breakpoints on symbols matching a specified pattern.
  • The BA (Break on Access) command will set a data breakpoint. This breakpoint will be triggered if a specific memory location is accessed. (These breakpoints can be triggered when the memory location is written to, when it is read, when it is executed as code, or when kernel I/O occurs. Not all processors support all memory access breakpoints. See the command page for details.)
  • The BC (Breakpoint Clear) command will permanently remove one or more breakpoints.
  • The BD (Breakpoint Disable) command will temporarily disable an existing breakpoint.
  • The BE (Breakpoint Enable) command will re-enable a disabled breakpoint.
  • (WinDbg only) The Disassembly window and the Source windows highlight lines which have breakpoints set. Enabled breakpoints are red; disabled breakpoints are yellow; a breakpoint corresponding to the current program counter location is purple.
  • (WinDbg only) The Edit | Breakpoints menu item or the ALT+F9 shortcut key will open the Breakpoints dialog box. This dialog box lists all breakpoints, and can be used to disable, enable, or clear existing breakpoints, or to set new breakpoints.
  • (WinDbg only) If you set the cursor on a specific line in the Disassembly window or in a Source window and then press the F9 shortcut key or following toolbar button

    a breakpoint will be set at that line. If this shortcut key or this button is pressed when the active window is neither the Disassembly window nor a Source window, it has the same effect as Edit | Breakpoints.

Each breakpoint has a decimal number called the breakpoint ID associated with it. This is used to identify it in various commands.

Deferred Breakpoints: BU vs. BP

If a breakpoint is set for a routine name that has not been loaded, the breakpoint is considered deferred. Deferred breakpoints (also known as unresolved or virtual breakpoints) are not associated with any specific load of a module. Each time a new application is loaded, it is checked for this routine name. If this routine appears, the debugger will compute the actual coded address of the virtual breakpoints and enable it.

If a breakpoint is set by using the BU command, it is automatically considered unresolved. If this breakpoint is in a currently-loaded module, it is still enabled, and will function normally. However, if the module is subsequently unloaded and reloaded, this breakpoint will not vanish. On the other hand, a breakpoint set with BP is immediately resolved to an address.

In practice, there are three major differences between BP breakpoints and BU breakpoints:

  • A BP breakpoint location is always converted to an address. If some module change moves the code that a BP breakpoint was set at, the breakpoint will remain at the same address. On the other hand, a BU breakpoint will remain associated with the symbolic value (usually a symbol plus an offset) that was used, and it will track this symbolic location even if its address changes.
  • If a BP breakpoint address is found in a loaded module, and that module is subsequently unloaded, the breakpoint will be removed from the breakpoint list. On the other hand, BU breakpoints persist over repeated unloads and loads.
  • Breakpoints set with BP are not saved in WinDbg workspaces. Breakpoints set with BU are saved in workspaces.

Breakpoints set by the BM command or by using the mouse in WinDbg's Disassembly or Source windows have the same characteristics as BP breakpoints.

Initial Breakpoint

When performing user-mode debugging, an initial breakpoint automatically occurs after all statically-linked DLLs are loaded, but before any DLL initialization routines are invoked.

The -g command-line option will cause WinDbg or CDB to ignore this default breakpoint. See Controlling the Target for a discussion of this option. It is also possible to automatically execute a command at this point; see Controlling Exceptions and Events for details.

If you wish to break after DLL initialization, do not use the -g option. Instead, once the program has loaded and broken into the debugger, you should set a breakpoint on the main or winmain routine and then use the G (Go) command to proceed through initialization. The program will halt when the actual execution is about to begin.

For an explanation of automatic breakpoints in kernel mode, see Crashing and Rebooting the Target Computer.

Addresses in Breakpoints

A large variety of address syntax forms are supported. Virtual addresses, function offsets, and source line numbers are all supported. For example, any of the following commands can be used to set breakpoints:

bp 0040108c
bp main+5c
bp `source.c:31`

See Expression Syntax, Source Line Syntax, and the individual command pages for details.

Number of Breakpoints

In kernel mode, a maximum of 32 breakpoints are supported. In user mode, any number are supported.

The number of data breakpoints supported depends on the target processor architecture.

Conditional Breakpoints

Conditional breakpoints can be very useful in debugging. The following command sets a breakpoint at line 143 of the source file mysource.cpp. When this breakpoint is hit, the variable MyVar is tested. If this variable is less than or equal to 20, execution continues; if it is greater than 20, execution stops.

0:000> bp `mysource.cpp:143` "j (poi(MyVar)>0n20) ''; 'g' "

This command has a fairly complicated syntax. Some clarifications:

  • Source line numbers are specified by using grave accents ( ` ). For details, see Source Line Syntax.
  • When the breakpoint is hit, the command in double quotation marks ( " ) is executed. In this case, it is a J (Execute If - Else) command, which tests the expression in parentheses.
  • In the source program, MyVar is an integer. If C++ expression syntax is being used, MyVar is interpreted as an integer. However in this example (and in the default debugger configuration), MASM expression syntax is being used. In a MASM expression, the symbol MyVar is treated as an address. Thus you need to use the poi operator to dereference it. (If your variable actually is a C pointer, you will need to dereference it twice — poi(poi(MyPtr)), for example.) The prefix 0n specifies that this number is decimal. For syntax details, see MASM Numbers and Operators.
  • The test is followed by two commands surrounded by single quotation marks ( ' ). If the test is true, the first of these commands is executed. In this case there is no first command, so command execution will end and control will remain with the debugger. If the test is false, the second command will execute. In this example it is a G (Go) command, which will cause execution to continue.

If you want to see a message each time the breakpoint is passed or when it is finally hit, you can use additional commands in the single quotation marks. For example:

0:000> bp `:143` "j (poi(MyVar)>5) '.echo MyVar Too Big'; '.echo MyVar Acceptable; g' "

This is especially useful if you have several such breakpoints running at the same time, since the debugger does not display its standard "Breakpoint n Hit" messages when you are using a command string in the BP command.

Conditional breakpoints are just one example of using a breakpoint command with a command string. Another useful example is the following, which creates a dump file:

0:000> bu MyFunction+0x47 ".dump c:\mydump.dmp; g"

Warning Don't use G (Go) in the breakpoint command string while you are controlling the user-mode debugger from the kernel debugger. The serial interface may not be able to keep up with this, and you will be unable to break back into CDB. See Controlling the User-Mode Debugger from the Kernel Debugger for details.

Breakpoints on Methods

If you wish to place a breakpoint on the method MyMethod in the class MyClass, you can use two different syntaxes.

In MASM expression syntax, a method can be indicated by a double colon or by a double underscore, as follows:

0:000> bp MyClass::MyMethod
0:000> bp MyClass__MyMethod

In C++ expression syntax, a method must be indicated by a double colon, as follows:

0:000> bp @@( MyClass::MyMethod )

If you plan to use a more complicated breakpoint command, it is easiest to use MASM expression syntax. See Evaluating Expressions for full details.

User Space and System Space

Each user-mode application is given a block of virtual addresses from 0x00000000 to 0x7FFFFFFF which is referred to as its user space.

When WinDbg or CDB sets a breakpoint in an address less than 0x80000000, this breakpoint is set at the specified address in the user space of a single process. During user-mode debugging, the meaning of virtual addresses is determined by the current process. See Controlling Processes and Threads for details.

In kernel mode, you can set breakpoints in user space with the BP, BU, and BA commands, or with the Breakpoints dialog box. You must first use the process context to specify the user-mode process that owns that address space. See Process Context for details.

Breakpoints in user space are always associated with the process whose process context was active when they were set. If the process in question is being debugged by a user-mode debugger, and the computer it is running on is being debugged by a kernel debugger, this breakpoint will break into the user-mode debugger—even though it was actually set from the kernel debugger. You can break into the system from the kernel debugger at this point, or use the .breakin (Break to the Kernel Debugger) command from the user-mode debugger to transfer control to the kernel debugger.

A kernel debugger cannot set breakpoints in user space if the target computer is running Windows NT® 4.0.

Breakpoint Pseudo-Registers

If you wish to refer to a breakpoint address in an expression, you can use a pseudo-register with the syntax $bp Number, where Number is the breakpoint ID. For more details, see Pseudo-Register Syntax.


Reading and Writing Memory

The three debuggers can read and write directly into memory. Memory can be referenced by addresses or by the names of variables.

Accessing Memory by Virtual Address

There are several commands which allow you to access specified memory addresses or address ranges.

The following commands can read or write memory in a variety of formats. These include hexadecimal bytes, words, double words, and quad-words; short, long, and quad integers and unsigned integers; 10, 16, 32, and 64 byte real numbers, and ASCII characters.

  • The D* (Display Memory) command can display the contents of a specified memory address or range.
  • The E* (Enter Values) command can write a value to the specified memory address.
  • (WinDbg only) The Memory window can display the contents of a specified memory range, and write to any location in that range.

The following commands can be used to deal with more specialized data types:

  • The DT (Display Type) command can look up a great variety of data types, and display data structures which have been created by the program being debugged. This is a highly versatile command, and has many variations and options.
  • The DS (Display String) command can display a STRING, ANSI_STRING, or UNICODE_STRING data structure.
  • The DL (Display Linked List) command can trace and display a linked list.
  • The D*S (Display Words and Symbols) command can look up double-words or quad-words which may contain symbol information, and then display the data and the symbol information.

The following commands can be used to manipulate entire memory ranges:

  • The M (Move Memory) command can move the contents of one memory range to another.
  • The F (Fill Memory) command can write a pattern to a memory range, repeating it until the range is full.
  • The C (Compare Memory) command can compare the contents of two memory ranges.
  • The S (Search Memory) command can search for a specified pattern in memory.

In most cases, these commands will interpret their parameters in the current radix. Therefore, hexadecimal addresses should be prefixed by 0x if this radix is not 16. However, the display output of these commands is usually in hexadecimal, regardless of the current radix. (See the individual command pages for details.) The Memory window displays integers and real numbers in decimal, and displays other formats in hexadecimal.

To change the default radix, use the N (Set Number Base) command. To quickly convert numbers from one base to another, use the ? (Evaluate Expression) or the .formats (Show Number Formats) command.

When you are performing user-mode debugging, the meaning of virtual addresses is determined by the current process. When you are performing kernel-mode debugging, the meaning of virtual addresses can be controlled by the debugger. See Process Context for more details.

Accessing Memory by Physical Address

To read from a physical address, use the !db, !dc, !dd, !dp, !du, and !dw, extension commands.

To write to a physical address, use the !eb and !ed extension commands.

The FP (Fill Physical Memory) command can write a pattern to a physical memory range, repeating it until the range is full.

When using WinDbg in kernel mode, you can also read or write to physical memory directly from the Memory window.

Also see Converting Virtual Addresses to Physical Addresses.

Accessing Global Variables

The names of global variables are stored in the symbol files which are created when an application is compiled. The debugger interprets the name of a global variable as a virtual address. As a result, any command which accepts an address as a parameter will also accept the name of a variable as that parameter.

This means that all the commands described above can be used to read or write global variables.

In addition, you can use the ? (Evaluate Expression) command to display the address associated with any symbol.

Here is an example. Suppose you wish to examine the global variable MyCounter, which is a 32-bit integer. Suppose also that the default radix is 10.

You can obtain this variable's address and then display it in the following manner:

0:000> ? MyCounter
Evaluate expression: 1244892 = 0012fedc
0:000> dd 0x0012fedc L1
0012fedc  00000052

The first command output tells you that the address of MyCounter is 0x0012FEDC. You can then use the D* command to display one double-word at this address. (You could use 1244892, the decimal version of this address, instead. However, this seems unnatural to most C programmers.) The second command tells you that the value of MyCounter is 0x52 (decimal 82).

You could also do this in a single command, as follows:

0:000> dd MyCounter L1
0012fedc  00000052

To change the value of MyCounter to decimal 83, use this command:

0:000> ed MyCounter 83

This example uses decimal input, since that seems more natural for an integer. The output of the D* command is still in hexadecimal, however:

0:000> dd MyCounter L1
0012fedc  00000053

Accessing Local Variables

Local variables, like global variables, are stored in the symbol files. Like global variables, the debugger interprets their names as addresses. Thus they can be read and written in the same manner as global variables.

There are also additional methods of displaying and changing local variables:

  • The DV (Display Local Variables) command displays the names and values of all local variables.
  • (WinDbg only) The Locals window displays the names and values of all local variables. It can also be used to change the values of these variables.

However, there is one major difference between local and global variables. When a program is executing, the meaning of local variables depends on the location of the program counter, since the scope of such variables extends only to the function in which they are defined.

The debugger interprets local variables according to the local context. This matches the location of the program counter by default, but can be altered by the debugger. See Local Context for more details.

When the local context is changed, the Locals window is immediately updated to reflect the new collection of local variables. The DV command will show the new variables as well. All these variable names will now be correctly interpreted by the memory commands described above; this allows you to read or write to these variables.

When debugging optimized code, some local variables may be collapsed, replaced with a register, or perhaps even temporarily stored on the stack. If you wish to use source files or local variables while debugging, you should not optimize your code.

Controlling Variables Through the Watch Window

WinDbg has an additional way of displaying and changing global and local variables: the Watch window.

The Watch window can display any list of variables you choose. These can include global variables as well as local variables from any function. At any given time, the Watch window will display the values of those variables which match the current function's scope. These variables can have their values changed through this window as well.

Unlike the Locals window, the Watch window is not affected by changes to the local context. Only those variables which are defined in the scope of the current program counter can have their values displayed or modified.

For details of its use, see The Watch Window.


Reading and Writing Registers and Flags

Registers are small volatile memory units located on the CPU. Many of these are dedicated to specific uses, whereas others are available for use by user-mode programs.

The x86 and IA-64 processors have different collections of registers available. See Processor Architecture for a description of the registers on each processor.

There are two ways to manipulate CPU registers:

  • The R (Registers) command can be used to display or control the registers. This display can be customized by using a number of options, or by using the Rm (Register Mask) command.
  • (WinDbg only) The Registers window can be used to display or control the registers. It can be customized to display the registers in any order.
  • (WinDbg only) The Watch window can be used to display any list of registers or variables. It cannot be used to alter the value of registers.

Registers are also automatically displayed each time the target halts. This means that if you are stepping through your code with the P (Step) or T (Trace) commands, you will see a register display at every step. To stop this display, use the r option with these commands.

On an x86 processor, the R command also controls a number of one-bit registers known as flags. Changing these flags is done by a slightly different syntax than changing regular registers. For a list of these flags and an explanation of this syntax, see The x86 Flags.


Viewing the Call Stack

The call stack is the chain of function calls which have led to the current location of the program counter. The top function on the call stack is the current function, the next function is the function which called the current function, and so forth.

The call stack also preserves a number of facts each time a function calls a new function. These vary from processor to processor, but typically they include the name or location of the function called, the return address (this is usually the assembly instruction just after the address from which the function was called), the parameters passed to the function, and the base pointer for the stack frame itself.

There are several ways to display the call stack:

  • The K (Display Stack Backtrace) command is the basic stack trace command. It displays the base pointer for the stack frame, the return address, and the name of the function. If source line information is available, it also displays source modules and line numbers.
  • The KB (Display Stack Backtrace) command displays the same stack as the K command, as well as the first three parameters passed to the function.
  • The KP (Display Stack Backtrace) command displays the same stack as the KB command, as well as a full listing of the parameters passed to each function.
  • The KV (Display Stack Backtrace) command displays the same stack as the KB command, as well as additional FPO information. On an x86 processor, this command also displays calling convention information. On an IA-64 processor, this command also displays nonvolatile registers.
  • The KD (Display Stack Backtrace) command displays the raw stack data, without any formatting.
  • (WinDbg only) The Calls window displays call stack information. It can be customized to display different stack data. It can also be used to quickly jump to the corresponding function in a Source or Disassembly window.

If you attempt to display the call stack at the very beginning of a function (before the function prolog has been executed), you will probably see incorrect results. The debugger uses the frame register to compute the current backtrace, and this register is not correctly set for a function until its prolog has been executed.

The call stack displayed is based on the current program counter, unless the register context has been changed. See Changing Contexts for details on how to change the register context.

A variety of problems can make it difficult to get an accurate stack trace. For a more advanced treatment of this matter, see Stack Traces.


Debugging in Assembly Mode

If you have C or C++ source files for your program, you can use the debugger much more powerfully if you debug in source mode. See Debugging in Source Mode for details.

However, there are many times you cannot perform source debugging. You may no longer have the source files for your program. You may be debugging someone else's code. You may have failed to build your executables with full .pdb symbols. And even if you can do source debugging on your application, you may need to trace Windows routines which are called by your program, or which are used to load your program.

In these cases, you will have to debug in assembly mode.

Moreover, assembly mode has many useful features which are not present in source debugging. The debugger will automatically display the contents of memory locations and registers as they are accessed, as well as displaying the address of the program counter. This makes assembly debugging a valuable tool which can be used side-by-side with source debugging.

Disassembly Code

The debugger is primarily analyzing binary executable code. Rather than displaying this in raw format, it disassembles this code, converting it from machine language to assembly language.

The resulting "disassembly code" can be displayed in several different ways:

  • The U (Unassemble) command can disassemble and display a specified section of machine language.
  • (WinDbg only) The Disassembly window can disassemble and display a specified section of machine language. This window is automatically active if the Window | Automatically Open Disassembly menu command is checked. It can also be opened or made active by selecting View | Disassembly, pressing the ALT+7 shortcut key, or pressing the following toolbar button:

The disassembly display appears in four columns: address offset, binary code, assembly language mnemonic, and assembly language details. Here is an example of this display:

0040116b    45          inc         ebp
0040116c    fc          cld
0040116d    8945b0      mov         eax,[ebp-0x1c]

At the right side of the line representing the current program counter, the values of any memory locations or registers being accessed are displayed. as well. If this line contains a branch instruction, the notation [br=1] or [br=0] will appear. These indicate a branch that will or will not be taken, respectively

In WinDbg's Disassembly window, the line representing the current program counter is highlighted in green. Lines at which breakpoints are set are highlighted as well: an enabled breakpoint in red, a disabled breakpoint in yellow, and a breakpoint that coincides with the current program counter in purple.

Other commands are also available for manipulating assembly code:

  • The # (Search for Disassembly Pattern) command searches a region of memory for a specific pattern. This is equivalent to searching each of the four columns of the disassembly display.
  • The A (Assemble) command can take assembly instructions and translate them into binary machine code.

Assembly Mode and Source Mode

The debugger has two different operating modes: assembly mode and source mode.

When single-stepping through a program, the size of a single step will either be one line of assembly code or one line of source code, depending on the mode.

Several commands result in different data displays depending on the mode.

In WinDbg, the Disassembly window will automatically move to the foreground when you execute or step through a program in assembly mode. In source mode, the Source window will move to the foreground.

Setting the mode can be done in two ways:

  • The L+, L- (Set Source Options) command can control the mode. The L-t command activates assembly mode.
  • (WinDbg only) De-selecting the Debug | Source Mode menu item causes the debugger to enter assembly mode.This can also be done by clicking on the following toolbar button:

When WinDbg is in assembly mode is active, the ASM indicator on the status bar is visible.

Assembly Language Source Files

If your program was originally written in assembly language, the disassembly produced by the debugger may not precisely match your original code. In particular, NO-OPs and comments will of course not be present.

If you wish to debug your code by referencing the original .asm files, you need to use source mode debugging. Your assembly file can be loaded just like a C or C++ source file. See Debugging in Source Mode for full details.


Debugging in Source Mode

Debugging a program is made much easier if you can analyze the code in terms of the source, rather than the disassembled binaries.

WinDbg, CDB, and KD can use source code in debugging, provided that the source language is C, C++, or assembly.

Compilation Requirements

For source debugging to be possible, you must build a checked (debug) version of your binaries. The compiler will create symbol files (.pdb files). These symbol files will show the debugger how the binary instructions correspond to the source lines.

The actual source files themselves must also be accessible to the debugger. The symbol files do not actually contain the text of the source files themselves.

It is best if the linker does not optimize your code. Source debugging and access to local variables are more difficult, and sometimes nearly impossible, if the code has been optimized.

Locating the Symbol Files and Source Files

To debug in source mode, the debugger needs to be able to find your source files and your symbol files. See Setting Paths and Loading Files for details.

Beginning Source Debugging

The debugger can display source information whenever it has proper symbols and source files for the thread which is currently being debugged.

If you launch a new user-mode application with the debugger, the initial break will occur when the application is loaded by ntdll.dll. Since the debugger will not have access to the ntdll.dll source files, you will not be able to access source information for your application at this point.

To move the program counter to the beginning of your application itself, place a breakpoint at the entry point to your binary. In the Debugger Command window, type:

bp main
g

The application will then be loaded and will halt when the main function is entered. (Of course you can use any entry point, not just main.)

If the application throws an exception, it will break into the debugger. Source information will be available at this point. However, if you issue a break by using the CTRL+C, CTRL+BREAK, or Debug | Break commands, a new thread is created by the debugger; as a result, you will not see your source code at this point.

Once you have reached a thread for which you have source files, you can use the Debugger Command window to execute the various source debugging commands. If you are using WinDbg, the Source window will appear at this point. If you have already opened a Source window by using Open Source File from the File menu, WinDbg will usually create a new window for the source. The old window can be closed without affecting the debugging process.

Source Debugging in the WinDbg GUI

If you are using WinDbg, a Source window will appear as soon as the program counter is in code for which the debugger has source information.

WinDbg displays one Source window for each source file which has been opened by you or opened by WinDbg itself. See Source Windows for a description of the text properties of this window.

You can then step through your program or execute to a breakpoint or to the cursor. See Controlling the Target for stepping and tracing commands.

If you are in source mode, the proper Source window will move to the foreground as you step through your program. Since there will be Windows routines which are called during your program's execution as well, the debugger may move a Disassembly window to the foreground when this occurs (since it will not have access to the source for these functions). When the program counter returns to known source files, the proper Source window will again become active.

As you move through your program, WinDbg will highlight your location in the Source window and the Disassembly window in green. Lines at which breakpoints are set are highlighted as well. Enabled breakpoints are red and disabled breakpoints are yellow. If a breakpoint coincides with the current program counter, it is highlighted in purple.

To activate source mode in WinDbg, use the L+t command, select the Debug | Source Mode menu item, or click on the following toolbar button:

When source mode is active, the ASM indicator on the status bar is grayed.

You can view or alter the values of any local variables as you step through a function in source mode. See Reading and Writing Memory for details.

Source Debugging in the Debugger Command Window

If you are using CDB, you will not have the benefit of a separate Source window. However, you can still view your progress as you step through the source.

Before you can do source debugging in CDB, you have to load source line symbols by issuing the .lines (Toggle Source Line Support) command, or by starting the debugger with the -lines command-line option.

If you execute an L+t command, all program stepping will be done one source line at a time. Use L-t to step one assembly instruction at a time. If you are using WinDbg, this has the same effect as selecting or deselecting Debug | Source Mode or using the toolbar buttons.

The L+s command will cause the current source line and line number to be displayed at the prompt. If you only wish to see the line number, use L+l instead.

If you use L+o and L+s, only the source line will be displayed while you step through the program. The program counter, disassembly code, and register information will be suppressed. This allows you to quickly step through the code and view nothing but the source.

The LSP (Set Number of Source Lines) command can be used to specify exactly how many source lines will be displayed when you step or execute your program.

The following sequence of commands is an effective way to step through a source file:

.lines        enable source line information
bp main       set initial breakpoint
l+t           stepping will be done by source line
l+s           source lines will be displayed at prompt
g             run program until "main" is entered
pr            execute one source line, and toggle register display off
p             execute one source line

Since ENTER will repeat the last command, you can now step through the program with the enter key. Each step will cause the source line, memory offset, and assembly code to be displayed.

See Debugging in Assembly Mode for how to interpret the disassembly display.

When the assembly code is displayed, any memory location being accessed will be displayed at the right end of the line. You can use the D* (Display Memory) and E* (Enter Values) commands to view or change the values in these locations.

If you need to view each assembly instruction in order to determine offsets or memory information, use L-t to step by assembly instructions instead of source lines. The source line information can still be displayed. Each source line will correspond to one or more assembly instructions.

All of these commands are available in WinDbg as well as in CDB. They can be used to view source line information from WinDbg's Debugger Command window rather than from the Source window.

Source Lines and Offsets

Another way to do source debugging is to use the expression evaluator to determine the offset corresponding to a specific source line.

The following command will output a memory offset:

? `[[module!]filename][:linenumber]`

If filename is omitted, the debugger looks for the source file which corresponds to the current program counter.

The linenumber will be read as a decimal number unless preceded by an 0x, regardless of the current default radix. If linenumber is omitted, the expression evaluates to the initial address of the executable corresponding to the source file.

This syntax will only be understood in CDB if source line symbols have been loaded by the .lines command or the -lines command-line option.

This is a very versatile technique, since it can be used regardless of where the program counter is pointing. For example, it allows breakpoints to be set in advance, by using commands such as the following:

bp `source.c:31`

For more details, see Source Line Syntax and Using Breakpoints.


Debugging BIOS Code

BIOS code is not built from standard assembly code, and therefore it requires different debugging techniques.

On an x86 processor, the BIOS uses 16-bit code. To disassemble this code, use the UX (Unassemble x86 BIOS) command. To display information about the Intel® Multiprocessor Specification (MPS), use the !mps extension.

On an IA-64 processor, the BIOS uses two different kinds of code: EFI code (32-bit) and real-mode code (16-bit). To disassemble real-mode code, use UR (Unassemble Real Mode BIOS). The debuggers cannot disassemble EFI code.

If you are debugging ACPI BIOS code, these commands will not work, because ACPI BIOS is written in ACPI Machine Language (AML). To disassemble this, you should use !amli u. For more details, see ACPI Debugging.


Ending the Debugging Session

You can exit any debugger at any time during the debugging session. The three debuggers have somewhat different methods of exiting. WinDbg also allows you to end the debugging session without exiting WinDbg.

Exiting CDB

You can exit CDB by using the Q (Quit) command. This also terminates the application you were debugging.

On Windows XP and Windows .NET Server 2003, the QD (Quit and Detach) command will detach CDB from the target application, exit the debugger, and leave the target application running. If the -pd command-line option was used when the debugger was started, detaching will occur if the session is ended for any reason. (This makes -pd especially useful when debugging a sensitive process, like CSRSS, that you do not wish to terminate.)

On Windows NT and Windows 2000, the QD command or the -pd option will generate a warning message and have no effect. These operating systems do not allow a debugger to detach from its target application. (If it is crucial that the target not be terminated, you should use noninvasive debugging, and exit using the Q command. See Attaching to a Running Process (User Mode) for details.)

If the debugger is not responding, you can exit by pressing CTRL+B and then ENTER. This is a secondary exit mechanism; it abruptly terminates the debugger. It is similar to terminating the process through Task Manager or by closing the window.

Exiting KD

There are two different ways to exit KD.

Issuing a Q (Quit) command in KD will save the log file, end the debugging session, and exit the debugger. The target computer will remain locked.

Pressing CTRL+B and then ENTER will end the debugger abruptly. If you want the target computer to keep running after the debugger is terminated, you must use this method. Since CTRL+B does not remove breakpoints, you should do this first:

kd>  bc *
kd>  g
kd>  <CTRL+B> <ENTER>

Note that while exiting the debugger by using CTRL+B does not clear kernel-mode breakpoints, attaching a new kernel debugger will clear these breakpoints.

When you are doing remote debugging, Q will end the debugging session. CTRL+B will exit the debugger but leave the session active. This allows another debugger to connect to the session.

If the Q command fails to work, try pressing CTRL+R followed by ENTER on the host computer's keyboard, and then retry the Q command. If this does not work, you must use CTRL+B to exit the debugger.

Exiting WinDbg

You can exit WinDbg by selecting the File | Exit menu command or by using the ALT+F4 shortcut key.

If you are performing user-mode debugging, this will terminate the application you were debugging, unless the -pd command-line option was used.

If you are performing kernel-mode debugging, the target computer will remain in its current state. This allows you to leave the target running or frozen, as you prefer. (If you leave it frozen, any future connection from a kernel debugger can resume debugging where you left off.)

Ending a User-Mode Session Without Exiting

To end a user-mode debugging session, return the debugger to dormant mode, and terminate the target application, you can use the following methods:

  • The .kill (Kill Process) command
  • (WinDbg only) The Q (Quit) command (unless the debugger was started with the -pd option)
  • (WinDbg only) The Debug | Stop Debugging menu command
  • (WinDbg only) The SHIFT+F5 shortcut key
  • (WinDbg only) The following button from the toolbar:

To end a user-mode debugging session, return the debugger to dormant mode, and set the target application running again, you can use the following methods:

  • (Windows XP and Windows .NET Server 2003 only) The .detach (Detach from Process) command. If you are debugging multiple systems at the same time, the .detach command will stop debugging one of the systems, but continue the debugging session with the remaining systems.
  • (Windows XP and Windows .NET Server 2003 only, WinDbg only) The QD (Quit and Detach) command
  • (Windows XP and Windows .NET Server 2003 only,WinDbg only) The Q (Quit) command, if the debugger was started with the -pd option

Detaching is permitted only in Windows XP and Windows .NET Server 2003. On Windows NT and Windows 2000, the QD command or the -pd option will generate a warning message and have no effect. These operating systems do not allow a debugger to detach from its target application. If it is crucial that the target not be terminated, you should use noninvasive debugging instead. See Noninvasive Debugging (User Mode) for details.

To end a user-mode debugging session, return the debugger to dormant mode, but leave the target application in the debugging state, you can use the following method:

  • (Windows XP and Windows .NET Server 2003 only) The .abandon (Abandon Process) command

For more details, see Re-attaching to the Target Application.

Ending a Kernel-Mode Session Without Exiting

To end a kernel-mode debugging session, return the debugger to dormant mode, and leave the target computer frozen, you can use the following methods:

  • (WinDbg only) The Q (Quit) command (unless the debugger was started with the -pd option)
  • (WinDbg only) The Debug | Stop Debugging menu command
  • (WinDbg only) The SHIFT+F5 shortcut key
  • (WinDbg only) The following button from the toolbar:

When a WinDbg session ends, you will be prompted to save the workspace for the current session, and then WinDbg will return to dormant mode. At this point, all starting options are available to you: you can begin debugging a running process, spawn a new process, attach to a target computer, open a crash dump, or connect to a remote debugging session. See Starting the Debugger for details on all these options.


Debugger Operation (User Mode)

This section includes:

Behavior of Spawned Processes

Controlling Processes and Threads

Re-attaching to the Target Application


Behavior of Spawned Processes

Processes created by the debugger behave slightly differently than they would under normal conditions.

Instead of using the standard heap API, processes created by the debugger use a special debug heap. On Windows XP and Windows .NET Server 2003, you can force a spawned process to use the standard heap instead of the debug heap by using the _NO_DEBUG_HEAP environment variable or the -hd command-line option.

Also, since the target application is itself a child process of the debugger, it inherits the debugger's permissions. This may allow the target application to perform certain actions that would otherwise be forbidden. For example, the target application might be able to affect protected processes.


Controlling Processes and Threads

When performing user-mode debugging, processes and threads can be made active, displayed, frozen or unfrozen, suspended or unsuspended.

The current or active process is the process that is currently being debugged. Similarly, the current or active thread is the thread that is currently being controlled by the debugger. The actions of many debugger commands are determined by the identity of the current process and thread. The current process also determines the virtual address mappings used by the debugger.

When debugging begins, the current process is the one that the debugger is attached to or that caused the exception that broke into the debugger. Likewise, the current thread is the one that was active when the debugger attached to the process, or that caused the exception. However, you can use the debugger to change the current process and thread, and to freeze or unfreeze individual threads.

In kernel-mode debugging, processes and threads are not controlled by the methods described in this section. See Changing Contexts for an explanation of how processes and threads are manipulated in kernel mode.

Displaying Processes and Threads

To display process and thread information, the following methods are available:

  • The | (Process Status) command
  • The ~ (Thread Status) command
  • (WinDbg only) The View | Processes and Threads menu command

Setting the Current Process and Thread

To change the current process or thread, the following methods are available:

  • The |S (Set Current Process) command
  • The ~S (Set Current Thread) command
  • (WinDbg only) The View | Processes and Threads menu command

Freezing and Suspending Threads

The debugger can alter the execution of a thread in two ways: by suspending it or by freezing it. These two actions have somewhat different effects.

Each thread has a suspend count associated with it. If it is one or higher, the system will not run the thread. If it is zero or lower, the system will run the thread when appropriate.

Normally, each thread has a suspend count of zero. When the debugger attaches to a process it increments the suspend counts of all threads in that process by one. If the debugger detaches from the process, it decrements all suspend counts by one. When the debugger executes the process, all suspend counts are temporarily decremented by one.

The suspend count of any thread can be directly controlled from within the debugger by the following methods:

  • The ~N (Suspend Thread) command will increment the specified thread's suspend count by one.
  • The ~M (Resume Thread) command will decrement the specified thread's suspend count by one.

The most common use for these commands is to raise a specific thread's suspend count from one to two. When the debugger executes or detaches from the process, the thread will then have a suspend count of one, and remain suspended, even if other threads in the process are executing.

Threads can be suspended even when performing noninvasive debugging.

A thread can also be frozen by the debugger. This is similar to suspending the thread in some ways. However, it is solely a debugger setting; nothing in Windows itself will recognize anything different about this thread.

All threads are unfrozen by default. When the debugger causes a process to execute, threads that are frozen will not execute. However, if the debugger detaches from the process, all threads will unfreeze.

To freeze and unfreeze individual threads, the following methods are available:

  • The ~F (Freeze Thread) command will freeze the specified thread.
  • The ~U (Unfreeze Thread) command will unfreeze the specified thread.

In any event, threads belonging to the target process will never actually execute when the debugger has broken into the target. The suspend count of a thread only affects the thread's behavior when the debugger executes the process or detaches. The frozen status only affects the thread's behavior when the debugger executes the process.

Threads and Processes in Other Commands

There are also a large number of other commands which can be prefixed by thread specifiers or process specifiers. See the individual command pages for details.

Many commands and extension commands can be proceeded with the ~E (Thread-Specific Command) qualifier. This causes the command to be executed with respect to the specified thread. This is especially useful if you wish to apply a command to more than one thread. For example, the following command will repeat the extension command !gle for every single thread being debugged:

~*e !gle

Multiple Systems

The debugger can attach to processes on multiple computers. When this is done, the debugger will reference a system, process, and thread for each action. See Debugging Multiple Systems for details.


Re-attaching to the Target Application

If the debugger freezes or otherwise crashes while performing user-mode debugging, it is possible to attach a new debugger to the existing process.

This method is supported only on Windows XP and Windows .NET Server 2003. It does not depend on whether the debugger originally spawned the process or attached to an existing process. It does not depend on whether the -pd option was used.

To re-attach a debugger to an existing target application

  1. Determine the process ID of the target application. (See Finding the Process ID.)
  2. Start a new instance of CDB or WinDbg. The -pe command-line option should be used:
    Debugger -pe -p PID

    Other command-line options are also permitted.

    It is also possible to connect from a dormant debugger by using the .attach (Attach to Process) command with the -e option.

  3. Once the attach is complete, you should end the original debugger process.
  4. If the process does not respond properly, it may have a suspend count that is too high. You can use the ~M (Resume Thread) command to lower the suspend count. See Controlling Processes and Threads for details.

If the original debugger is still operating properly, this method may not work. This is because the two debuggers will be competing for debugging events, and Windows will not necessarily assign all the debugging events to the new debugger.

If the original debugger is terminated before the new debugger is attached, the target application will be terminated as well. (However, if the debugger attached with the -pd option and then exits normally, the target application will continue running. In this case, a second debugger can attach to the target application without using the -pe option.)

If you are already debugging a process and wish to detach from it, but leave it frozen in a debugging state, you can use the .abandon (Abandon Process) command. After this, any debugger can re-attach to it using the procedure outlined in this section.


Debugger Operation (Kernel Mode)

This section includes:

Crashing and Rebooting the Target Computer

Synchronizing with the Target Computer

Changing Contexts

Mapping Driver Files

Performing Local Kernel Debugging


Crashing and Rebooting the Target Computer

When performing kernel debugging, you can cause the target computer to undergo a system crash (bug check) by issuing the .crash (Force System Crash) command. This command will immediately cause the target computer to crash. A kernel-mode dump file will be written if crash dumps have been enabled. (See Creating a Kernel-Mode Dump File for details.)

To reboot the target computer, use the .reboot (Reboot Target Computer) command. This will cause the target computer to restart.

If you want the target computer to create a crash dump file and then reboot, you should issue the .crash command, followed by the .reboot command. If you simply want to reboot, the .crash command is not required.

In the early stages of the boot process, the connection between the host computer and the target computer will be lost. No information about the target computer will be available to the debugger.

Once the connection is broken, the debugger will close all symbol files and unload all debugger extensions. At this point, all breakpoints will be lost if you are running KD or CDB. In WinDbg, you will be given the option to save the current workspace; this will save all breakpoints.

If you wish to end the debugging session at this point, use the CTRL+B command (in KD) or select Exit from the File menu (in WinDbg).

If you do not quit the debugger, the connection will be re-established once enough of the boot process has completed. Symbols and extensions will be reloaded at this point. If you are running WinDbg, the kernel-mode workspace will be reloaded.

The debugger can be instructed to automatically break into the target computer during the reboot process. There are two possible times at which this break can occur. The earlier time is when the first kernel module is loaded into memory. The later time is when the kernel initializes.

To set an automatic breakpoint when the first kernel module loads, use the -d command-line option.

To set an automatic breakpoint when the kernel initializes, use the -b command-line option.

You can also change the break state once the debugger is running. There are two ways to do this:

  • The initial module load and kernel initialization breakpoints can be controlled like all exceptions and events. They can be set as breakpoints or ignored. It is also possible to have a specified command automatically execute when these breakpoints are hit. See Controlling Exceptions and Events for details.
  • The CTRL+K key in KD, the CTRL+ALT+K key in WinDbg, and the Debug | Kernel Connection | Cycle Initial Break menu command in WinDbg will change the break state. Each time they are used, the debugger toggles between three states: no automatic break, break upon kernel initialization, and break on first kernel module load. Note that this method cannot activate both automatic breakpoints at the same time.


Synchronizing with the Target Computer

Sometimes during kernel-mode debugging, the target computer will stop responding to the debugger.

In KD, use the CTRL+R (Re-synchronize) key followed by ENTER to synchronize with the target computer. In WinDbg, use CTRL+ALT+R or Debug | Kernel Connection | Resynchronize.

This will often restore communication between the host and the target.

The .restart (Restart Kernel Connection) command provides an even more powerful method of resynchonization. It is equivalent to exiting the debugger and then attaching a fresh debugger to the existing session. This command is only available in KD, not in WinDbg.

The .restart command is most useful when performing remote debugging through remote.exe, when actually ending and restarting the debugger may be difficult. However, it cannot be used from a Debugging Client if you are performing remote debugging through the debugger.


Changing Contexts

In kernel-mode debugging, there are a large number of processes, threads, and sometimes user sessions that are executing at the same time. This means that expressions such as "virtual address 0x80002000" or "the eax register" are ambiguous. You need to specify the context in which such expressions will be understood.

The debugger has five different contexts that can be set while debugging:

  1. The session context indicates the default user session. (This is only applicable to Windows XP and Windows .NET Server 2003, which allow multiple logon sessions to coexist.)
  2. The process context determines how the debugger will interpret virtual addresses.
  3. The user-mode address context is almost never set directly. It is automatically set when the process context is changed.
  4. The register context determines how the debugger will interpret registers, and also controls the results of a stack trace. This is sometimes called the thread context, although that term is not completely accurate.
  5. The local context determines how the debugger will interpret local variables. This is sometimes called the scope.

Session Context

In Windows XP and Windows .NET Server 2003, multiple logon sessions can run at the same time. Each of these has its own processes.

The !session extension can be used to display a list of all logon sessions, or to change the current session context.

The session context is used by the !sprocess and !spoolused extensions when the session number is entered as "-2".

When the session context is changed, the process context is automatically changed to the active process for that session.

Process Context

Each process has its own page directory that records how virtual addresses are mapped to physical addresses. When any thread within a process is executing, Windows® uses this page directory to interpret virtual addresses.

During user-mode debugging, the process context is determined by the current process. Virtual addresses used in debugger commands, extensions, and debugging information windows will be interpreted according to the page directory of the current process.

During kernel-mode debugging, the process context can be set with the .process (Set Process Context) command. Use this command to choose which process' page directory will be used to interpret virtual addresses.

Once the process context has been set, it can be used in any commands that take addresses. Breakpoints can even be set at this address. This allows the kernel debugger to set breakpoints in user space.

The user-mode address context is part of the process context. Normally, you do not need to set the user-mode address context directly — setting the process context will automatically change the user-mode address context to the directory base of the relevant page table for the process. However, on an IA-64 processor, a single process may have more than one page directory. In this case, it may be useful to change the user-mode address context directly. This is done with the .context (Set User-Mode Address Context) command.

When the process context is set during kernel-mode debugging, it will keep this setting until changed by another .process command. The user-mode address context will keep this setting until changed by a .process or .context command. These contexts are not changed when the target computer executes, nor are they affected by changes to the register context or the local context.

Register Context

Each thread has its own register values. These values are stored in the CPU registers when the thread is executing, and are stored in memory when another thread is executing.

During user-mode debugging, the register context is usually determined by the current thread. Any reference to registers in debugger commands, extensions, and debugging information windows, will be interpreted according to the current thread's registers.

The register context can be changed to a value other than the current thread while performing user-mode debugging. This can be done by using the following commands:

.cxr (Display Context Record)

.ecxr (Display Exception Context Record)

During kernel-mode debugging, the register context can be controlled by a variety of debugger commands. These include:

.thread (Set Register Context)

.cxr (Display Context Record)

.trap (Display Trap Frame)

These commands do not actually cause the values of all registers to change: only the most important registers are revealed. See each command's reference page for details on how these commands work, and how they differ.

Stack traces depend on the register context. This is because the stack trace begins at the location pointed to by the stack pointer register (esp on an x86 processor, or sp on an IA-64 processor). If the register context is set to an invalid or inaccessible value, stack traces cannot be obtained.

Changing the register context can also result in a change to the local context. In this way, the register context can affect the display of local variables.

There is one major exception to these rules. When debugging multiprocessor machines, some commands allow you to specify a processor. If you specify a processor for a command, the current register context is not used; rather, the register context matching the active thread on that processor is used. This is true even if the specified processor is the currently-active processor.

If any program execution, stepping, or tracing occurs, the register context is immediately reset to match the program counter's position. In user mode, the register context will also be reset if the current process or thread is changed.

Local Context

When a program is executing, the meaning of local variables depends on the location of the program counter, since the scope of such variables extends only to the function in which they are defined.

When performing either user-mode or kernel-mode debugging, the debugger uses the scope of the current function (the current frame on the stack) as the local context. To change this, use the .frame (Set Local Context) command, or double-click on the desired frame in the Calls window.

In user-mode debugging, the local context is always a frame within the stack trace of the current thread. In kernel-mode debugging, the local context is always a frame within the stack trace of the current register context's thread.

Only one stack frame at a time can be used for the local context. Local variables in other frames cannot be accessed.

The local context will be reset if any of the following occur:

  • Any program execution, stepping or tracing
  • Any use of the thread delimiter (~) in any command
  • Any change to the register context


Mapping Driver Files

Replacing driver files can be a difficult task. It often requires booting to the Windows safe build, replacing the driver binary, and then booting a second time.

However, Windows XP and Windows .NET Server 2003 supports a simpler method of replacing driver files. It can be used to replace any kernel-mode driver (including display drivers), as well as Windows subsystem drivers. This method can be used whenever WinDbg or KD is attached as a kernel debugger.

Using a driver replacement map to replace driver files

  1. Create a driver replacement map file. This is a text file that lists the drivers on the target computer and their replacement drivers on the host computer. Any number of drivers can be replaced. For example, you might create a file named mymap.ini in the d:\Map_Files directory of your host computer which reads as follows:
    map
\Systemroot\system32\drivers\videoprt.sys
\\myserver\myshare\new_drivers\videoprt.sys

    See Driver Replacement Map File Format for an explanation of the syntax of this file.

  2. Set up a kernel debugging connection to the target computer, and start the kernel debugger (KD or WinDbg) on your host computer. (You do not have to actually break in to the target computer.)
  3. Load the driver replacement map file. This can be done in one of two ways.

    You can set the _NT_KD_FILES environment variable before starting the kernel debugger:

    D:\Debugging Tools for Windows> set _NT_KD_FILES=d:\Map_Files\mymap.ini
D:\Debugging Tools for Windows> kd

    Or you can use the .kdfiles (Set Driver Replacement Map) command after starting the kernel debugger:

    D:\Debugging Tools for Windows> kd
kd> .kdfiles d:\Map_Files\mymap.ini
KD file associations loaded from 'd:\Map_Files\mymap.ini'

    The .kdfiles command can also be used to display the current driver replacement map file, or to delete the driver replacement map. If this command is not used, the map persists until you exit the debugger.

Once this procedure has been completed, the driver replacement map will take effect.

Whenever the target computer is about to load a driver, it will query the kernel debugger to determine if this driver has been mapped. If it has been mapped, the replacement file will be sent over the kernel connection and copied over the old driver file. The new driver will then be loaded.

Driver Replacement Map File Format

Each driver file replacement is indicated by three lines in the driver replacement map file. The first line consists of the word "map". The second line specifies the path and filename of the old driver on the target computer. The third line specifies the full path and filename of the new driver, which can be on the host computer or on some other server.

This pattern can be repeated any number of times.

Paths and filenames are case-insensitive. The actual driver file names can be different: the file specified on the third line will be copied over the file specified on the second line when the target computer is about to load that driver.

Warning The old driver's path and file name must be an exact case-insensitive match for the path and file name stored in the Service Control Manager (SCM) database. This path will often begin with \SystemRoot\system32\drivers. However, a number of variations are possible — for example, a path beginning with \??\c:\windows\system32\drivers. The name in the SCM database is identical to the name that was passed to MmLoadSystemImage.

The file may include blank lines. It may also include comment lines beginning with a pound sign (#). However, once the indicator "map" has appeared, the next two lines must be the old driver and the new driver — neither blank lines nor comment lines may break up the three-line map blocks.

For example:

map
\Systemroot\system32\drivers\videoprt.sys
e:\MyNewDriver\binaries\videoprt.sys
map
\Systemroot\system32\mydriver.sys
\\myserver\myshare\new_drivers\mydriver0031.sys

# Here is a comment
map
\??\c:\windows\system32\beep.sys
\\myserver\myshare\new_drivers\new_beep.sys

The driver replacement map file must be a text file, but any file name and extension will be accepted (.ini, .txt, .map, and so on).

Additional Notes

When driver substitution occurs, a message will appear in the kernel debugger.

If you use CTRL+D (in KD) or CTRL+ALT+D (in WinDbg) you will see verbose information about the replacement request. This can be useful if you are not sure whether the name you have listed matches the one in the SCM database.

If the kernel debugger exits, no more driver replacement will take place. However, any drivers that have already been replaced will not revert to their old binaries, since the driver files are actually overwritten.

This feature automatically bypasses Windows File Protection (WFP).

It is not necessary to reboot the target computer — driver replacement will occur any time the target computer loads a driver, regardless of whether it has been rebooted. Of course, most drivers are loaded during the boot process, so in practice you will usually want to reboot the target computer once the map file has been loaded.

If the _NT_KD_FILES variable is defined, the specified driver replacement map file will be read when the kernel debugger is started. If the .kdfiles command is issued, the specified file will be read immediately. At this point, the debugger verifies that the file has the basic "map" - "line" - "line" format. But the actual paths and file names are not verified until substitution occurs.

Once the map file has been read, its contents will be remembered by the debugger. Changes to this file after this point will not have any effect (unless the .kdfiles command is reissued).

For large driver files, 1394 kernel connections are recommended. A kernel connection through a COM port may result in a long copying time.


Performing Local Kernel Debugging

KD and WinDbg are capable of performing local kernel debugging. This is kernel debugging on a single machine. In other words, the debugger is debugging the machine it is running on.

Local kernel debugging is only supported on Windows XP and Windows .NET Server 2003. Only users that have debug privileges can start local kernel debugging. For information on how to begin a local kernel debugging session, see Attaching to a Target Computer (Kernel Mode).

Commands That Are Not Available

Not all commands are available in a local kernel debugging session. As a general rule, any command that causes the target computer to halt, even momentarily, cannot be used — since there would be no way to order the target to resume operation.

In particular, the following commands cannot be used:

  • Execution commands,such as G (Go), P (Step), T (Trace), WT (Trace and Watch Data), TB (Trace to Next Branch), GH (Go with Exception Handled), and GN (Go with Exception Not Handled)
  • Shutdown and dump file commands, such as .crash, .dump, and .reboot
  • Breakpoint commands, such as BP, BU, BA, BC, BD, BE, and BL
  • Register display commands, such as R and variations
  • Stack trace commands, such as K and variations

If you are performing local kernel debugging with WinDbg, all the equivalent menu commands and buttons will be unavailable as well.

Commands That Are Available

All memory input and output commands are available. You can freely read from user memory and kernel memory. You can also write to memory, but of course writing to the wrong part of kernel memory can corrupt data structures and will often cause your computer to crash.

Difficulties in Performing Local Kernel Debugging

One of the most difficult aspects of local kernel debugging is that the machine state is constantly changing. Memory can be paged in and out, the active process will constantly change, and virtual address contexts will not remain constant. However, things that change slowly, such as certain device states, can still be effectively analyzed under these conditions.

Local kernel debugging is a very delicate operation. Care should be taken, lest you corrupt or crash the system.

The LiveKD Tool

There is a tool named LiveKD that simulates local kernel debugging. It creates a "snapshot" dump file of the kernel memory, without actually halting the kernel while this snapshot is made. (As a result, the snapshot may not actually show a single instantaneous state of the computer.)

LiveKD is not part of the Debugging Tools for Windows package. It can be found on the companion CD of the book Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


Debugger Extensions

CDB, KD, and WinDbg all allow the use of debugger extension commands. These extensions give these three Microsoft debuggers a great degree of power and flexibility.

Debugger extension commands are used much like the standard debugger commands. However, while the built-in debugger commands are part of the debugger binaries themselves, debugger extension commands are exposed by DLLs distinct from the debugger.

This allows you to write new debugger commands which are tailored to your specific need. In addition, a number of debugger extension DLLs are shipped with the debugging tools themselves.

This section includes:

Loading Debugger Extension DLLs

Using Debugger Extension Commands

Writing New Debugger Extensions

For information on specific extension commands, see the Debugger Extension Commands reference section.


Loading Debugger Extension DLLs

There are several methods of loading debugger extension DLLs, as well as controlling the default debugger extension DLL and the default debugger extension path:

  • (Before starting the debugger) Use the _NT_DEBUGGER_EXTENSION_PATH environment variable to set the default path for extension DLLs. This can be a number of directory paths, separated by semicolons.
  • Use the .load (Load Extension DLL) command to load a new DLL.
  • Use the .unload (Unload Extension DLL) command to unload a DLL.
  • Use the .unloadall (Unload All Extension DLLs) command to unload all debugger extensions.
  • (Before starting the debugger; CDB only) Use the tools.ini file to set the default extension DLL.
  • (Before starting the debugger) Use the -a command-line option to set the default extension DLL.
  • Use the .setdll (Set Default Extension DLL) command to set the default extension DLL.
  • Use the .chain (List Debugger Extensions) command to display all loaded debugger extension modules, in their default search order.

You can also load an extension DLL simply by using the full !module.extension syntax the first time you issue a command from that module. See Using Debugger Extension Commands for details.

The extension DLLs that you are using must match the operating system of the target computer. The extension DLLs that ship with the Debugging Tools for Windows package are each placed in a different subdirectory of the installation directory:

  • The nt4fre directory contains extensions that can be used with the free build of Microsoft® Windows NT® 4.0.
  • The nt4chk directory contains extensions that can be used with the checked build of Windows NT 4.0.
  • The w2kfre directory contains extensions that can be used with the free build of Microsoft Windows® 2000.
  • The w2kchk directory contains extensions that can be used with the checked build of Windows 2000.
  • The winxp directory contains extensions that can be used with Windows XP and Windows .NET Server 2003.
  • The winext directory contains extensions that can be used with any version of Windows. The dbghelp.dll module, located in the base directory of Debugging Tools for Windows, also contains extensions of this type.

If you write your own debugger extensions, you can place them in any directory. However, it is advised that you place them in a new directory and add that directory to the debugger extension path.

There can be as many as 32 extension DLLs loaded.


Using Debugger Extension Commands

The use of debugger extension commands is very similar to the use of debugger commands. The command is typed in the Debugger Command window, producing either output in this window or a change in the target application or target computer.

An actual debugger extension command is an entry point in a DLL called by the debugger.

Debugger extensions are invoked by the following syntax:

![module.]extension [arguments]

The module name should not be followed with the .dll file name extension. If module includes a full path, the default string size limit is 255 characters.

If the module has not already been loaded, it will be loaded into the debugger using a call to LoadLibrary(module). After the debugger has loaded the extension library, it calls the GetProcAddress function to locate the extension name in the extension module. The extension name is case-sensitive and must be entered exactly as it appears in the extension module's .def file. If the extension address is found, the extension is called.

Search Order

If the module name is not specified, the debugger will search the loaded extension modules for this export.

The default search order is as follows:

  1. The extension modules that work with all operating systems and in both modes: dbghelp.dll and winext\ext.dll.
  2. The extension module that works in all modes but is operating-system-specific. For Windows XP and Windows .NET Server 2003, this is winxp\exts.dll. There is no corresponding module for Windows NT 4.0 or Windows 2000.
  3. The extension module that works with all operating systems but is mode-specific. For kernel mode, this is winext\kext.dll. For user mode, this is winext\uext.dll.
  4. The extension module that is both operating-system-specific and mode-specific. The following table specifies this module.
    Windows Build User Mode Kernel Mode
    Windows NT 4.0
    (free build)         		nt4fre \ ntsdexts.dll nt4fre \ kdextx86.dll
    Windows NT 4.0
    (checked build)         		nt4chk \ ntsdexts.dll nt4chk \ kdextx86.dll
    Windows 2000
    (free build)         		w2kfre \ ntsdexts.dll w2kfre \ kdextx86.dll
    Windows 2000
    (checked build)         		w2kchk \ ntsdexts.dll w2kchk \ kdextx86.dll
    Windows XP
    or
    Windows .NET Server 2003         		winxp \ ntsdexts.dll winxp \ kdexts.dll

When an extension module is unloaded, it is removed from the search chain. When an extension module is loaded, it is added to the beginning of the search order. The .setdll (Set Default Extension DLL) command can be used to promote any module to the top of the search chain. By using this command repeatedly, you can completely control the search chain.

Use the .chain (List Debugger Extensions) command to display a list of all loaded extension modules in their current search order.

If you attempt to execute an extension command that is not in any of the loaded extension modules, you will get an Export Not Found error message.

Additional Information

For information on specific extension commands, see the Debugger Extension Commands reference section.


Writing New Debugger Extensions

You can create your own debugging commands by writing an extension DLL. You might want to write a command, for example, to dump a complex data structure.

Each extension command name will be an entry point into your DLL, and must be explicitly declared as an export in your .def file. These names must consist entirely of lower-case letters.

There are two different types of debugger extension DLLs:

  • Extensions that call routines in wdbgexts.h
  • Extensions that call routines in dbgeng.h and wdbgexts.h

Extension code samples are available as part of the Debugging Tools for Windows package. These will only appear if you have done a full install of all components of the package. They can be found in the sdk\samples subdirectory of the Debugging Tools for Windows installation directory.

The easiest way to write new debugger extensions is to study the samples of these extensions. Each of them includes makefile and sources files to be used with the Build utility. Both types of extensions are represented in the samples.

These sample extensions, as well as any extensions you develop, should be built by running the Build utility in one of the build environments that ship with the Microsoft® Windows® DDK.

WinDbg Exports

If you wish your DLL to be usable by WinDbg, the following additional requirements apply:

  1. You must export a routine named WinDbgExtensionDllInit. When WinDbg loads an extension DLL, it first calls WinDbgExtensionDllInit and passes it the following parameters:
    Parameter | Description
    Pointer to an extension API structure This structure contains the callbacks to functions that you can use to do standard operations. For example, to print a string you can use dprintf("string"). Include the header file wdbgexts.h in your extension source and use the #define function definitions from that file.

    Save the pointer in a global variable named ExtensionApis.

    See Routines in Wdbgexts.h for a full listing of functions in wdbgexts.h.
    Major version | This indicates whether the target system is running a checked build of Windows (0xC) or a free build (0xF).
    Minor version | This is the Windows build number of the target system (for example, 2600).

  2. You must export a routine called ExtensionApiVersion. The debugger calls this routine and expects back a pointer to API_VERSION. The version number of your extension DLL must match the version number of the debugger. If the numbers don't match, the debugger will not load the extension DLL.
  3. You can optionally export a routine called CheckVersion. The debugger calls this routine every time you use your DLL. Use it to verify that the version of your DLL matches that of the target system. To disable version checking, issue the .noversion command at the debugger command prompt.
  4. Use the DECLARE_API macro defined in wdbgexts.h to declare your command routines. The basic format is:
    DECLARE_API(foo)
{
code for foo
}

The debugger will place a "try/except" around a call to an extension DLL. Bugs in your code may cause your extension to work improperly. In this case, you will have to quit and restart the debugger. (A bad extension will not cause the debugger to crash, however.)


Logger and LogViewer

The Debugging Tools for Microsoft® Windows® package includes a pair of tools named Logger and LogViewer. These provide an alternative to standard user-mode debugging. Logger can monitor the actions of a user-mode target application and record all of its API calls. The resulting information can be displayed in the debugger, saved as a text file, or displayed in a powerful interactive format by the LogViewer tool.

This section includes:

Logger

LogViewer

The Logger Manifest


Logger

The Logger tool can be activated through two different vehicles. One way is to use the stand-alone logger.exe program. The other is to start CDB or WinDbg, and use the logexts.dll debugger extensions. Both of these methods will produce the same type of log output.

This section includes:

Using the Debugger and Logexts.dll

Using Logger.exe

Choosing the Best Logger Vehicle

Logger Restrictions and Limitations


Using the Debugger and Logexts.dll

One way to activate Logger is to start CDB or WinDbg and attach to a user-mode target application as usual. Then, use the !logexts.logi or !logexts.loge extension command.

This will insert code at the current breakpoint that will jump off to a routine that loads and initializes logexts.dll in the target application process. This is referred to as "injecting Logger into the target application."

There will actually be two instances of logexts.dll running, since this module is both a debugger extension DLL and the program that is injected into the target application. The debugger and target instances of logexts.dll communicate through a shared section of memory that includes the output file handles, current category mask, and a pointer to the log output buffer.

Attaching to the Target Application

For information on attaching the debugger to the target application, see Attaching to a Running Process (User Mode) or Spawning a New Process (User Mode).

Using the Logger Extension Commands

For the full syntax of each extension, see its reference page.

!logexts.logi
Injects Logger into the target application. This initializes logging, but does not enable it.
!logexts.loge
Enables logging. If !logexts.logi has not been used, this extension will initialize and then enable logging.
!logexts.logd
Disables logging. This will cause all API hooks to be removed in an effort to allow the program to run freely. COM hooks are not removed because they cannot be re-enabled at will.
!logexts.logo
Displays or modifies output options. Three types of output are possible: messages sent directly to the debugger, a text file, or an .lgv file. The .lgv file contains much more information than the other two; it can be read with LogViewer.

If you disable the text file output, a .txt file of size zero will still be created. This may overwrite a previously-saved text file in the same location.

!logexts.logc
Displays available API categories, controls which categories will be logged and which will not, and displays the APIs that are contained in any category.

If a category is disabled, the hooks for all APIs in that category will be removed so that there is no longer any performance overhead. COM hooks are not removed because they cannot be re-enabled at will.

Enabling only certain categories can be useful when you are only interested in a particular type of interaction that the program is having with the Windows — for example, file operations. This reduces the log file size and also reduces the effect that Logger has on the execution speed of the process.

!logexts.logb
Displays or flushes the current output buffer. As a performance consideration, log output is flushed to disk only when the output buffer is full. By default, the buffer is 2144 bytes.

Since the buffer memory is managed by the target application, the automatic writing of the buffer to the log files on the disk will not occur if there is an access violation or some other non-recoverable error in the target application. In such cases, you should use this command to manually flush the buffer to the disk, or else the most recently-logged APIs may not appear in the log files.

!logexts.logm
Displays or creates a module inclusion/exclusion list. It is often desirable to only log those API calls that are made from a certain module or set of modules. To facilitate that, Logger allows you to specify a module inclusion list or, alternatively, a module exclusion list. For instance, you would use an inclusion list if you only wanted to log calls from one or two modules. If you wanted to log calls made from all modules except a short list of modules, you would use an exclusion list. The modules logexts.dll and kernel32.dll are always excluded, since Logger is not permitted to log itself.


Using Logger.exe

One way to activate Logger is to run the stand-alone logger.exe program. This is essentially a very small debugger that can only take a single target. To run it, include the name of the target application on the command line:

logger Target

When this is activated, it will load the specified application, and insert code into the target application that will jump off to a routine that loads and initializes logexts.dll in the target application process. This is referred to as "injecting Logger into the target application."

The logger.exe utility and the logexts.dll module are the two components of this Logger vehicle. They communicate through a shared section of memory that includes the output file handles, current category mask, and a pointer to the log output buffer.

A window entitled Logger (debugger) will appear. This window will display the progress of Logger.

Change Settings Dialog Box

After the initialization finishes and the initial display is complete, the Change Settings dialog box will appear. This allows you to configure the Logger settings. The various settings are described as follows:

API Settings
This list displays the available API categories. The highlighted categories will be logged; the non-highlighted categories will not. The first time you run Logger, all categories will be highlighted. However, on subsequent runs, Logger will keep track of which categories are selected for a given target application.

If a category is disabled, the hooks for all APIs in that category will be removed so that there is no longer any performance overhead. COM hooks are not removed because they cannot be re-enabled at will.

Enabling only certain categories can be useful when you are only interested in a particular type of interaction that the program is having with the Windows — for example, file operations. This reduces the log file size and also reduces the effect that Logger has on the execution speed of the process.

Logging
This section contains Enable and Disable radio buttons. Disabling logging will cause all API hooks to be removed in an effort to allow the program to run freely. COM hooks are not removed because they cannot be re-enabled at will.
Inclusion / Exclusion List
This section controls the module inclusion/exclusion list. It is often desirable to log only those function calls that are made from a certain module or set of modules. To facilitate that, Logger allows you to specify a module inclusion list or, alternatively, a module exclusion list. For instance, you would use an inclusion list if you only wanted to log calls from one or two module. If you wanted to log calls made from all modules except a short list of modules, you would use an exclusion list. The modules logexts.dll and kernel32.dll are always excluded, since Logger is not permitted to log itself.
Flush the Buffer
This button will flush the current output buffer. As a performance consideration, log output is flushed to disk only when the output buffer is full. By default, the buffer is 2144 bytes.

Since the buffer memory is managed by the target application, the automatic writing of the buffer to the log files on the disk will not occur if there is an access violation or some other non-recoverable error in the target application. In such cases, you should try to activate the target application's window and hit F12 to get this dialog box back, and then press Flush the Buffer. If this is not done, the most recently-logged functions might not appear in the log files.

Go
This causes the target application to begin executing.

Running the Target Application

Once you have chosen the settings, click Go. The dialog box will close and the target application will begin to run.

If you make the target application's window active and press F12, it will break into Logger. This will cause the target application to freeze and the Change Settings dialog box to reappear. You can alter the settings if you wish, and then press Go to continue execution.

You can let the target application run for as long as you wish. If it terminates normally or due to an error, the logging will stop and cannot be restarted.

When you wish to exit, select File | Exit and click Yes. If the target application is still running, it will be terminated.

Limitations of Logger.exe

When you are running Logger through the logger.exe tool, it will create only one output file — an .lgv file. No text file will be written. However, a .txt file of size zero will be written; this could overwrite a text log written by the debugger previously.

The output file will always be placed in LogExts subdirectory of the desktop; this location cannot be changed.

These limitations will not apply if you are running Logger through the debugger and logexts.dll.


Choosing the Best Logger Vehicle

Logger can operate on Microsoft Windows® 98, Windows 98 Second Edition, Windows Me, Windows NT® 4.0, Windows 2000, Windows XP, and Windows .NET Server 2003. However, these Windows versions have different levels of support for debugging operations and also behave differently when executing code that attempts to "inject" itself into a particular process.

Windows 98, Windows 98 Second Edition, and Windows Me

The Logger vehicle to use on any Windows 9x system is logger.exe. The debuggers in the Debugging Tools for Windows package are not supported on Windows 9x.

Windows NT 4.0, Windows 2000, Windows XP, and Windows .NET Server 2003

The best vehicle to use on any NT-based operating system is CDB or WinDbg with the logexts.dll extension commands.

The Logger vehicle works as well, but using the debugger gives you the full power of the debugger along with the power of Logger.


Logger Restrictions and Limitations

Logger increases stack consumption for a process because it introduces an additional "wrapping" function before the actual function call.

This can expose bugs in applications that are usually related to uninitialized variables. Since Logger alters stack usage, a local variable declared in a function call might take a different initial value than it does without the presence of Logger. If the program uses this variable without initializing it, the program might crash or otherwise behave differently than if Logger was not present.

Unfortunately, there is no easy way around such problems. The only workaround is to try disabling categories of functions in an attempt to isolate the area that is causing the problem.


LogViewer

The LogViewer utility can manipulate an .lgv file, which is a compressed log file produced by the Logger tool. To load a file, simply launch logviewer.exe through Windows Explorer or from a Command Prompt window. It will take a moment to parse the manifest files. Once this is complete, you can invoke File | Open and select the desired .lgv file.

Once LogViewer has opened an .lgv file, it will display a list of all functions in the order they were logged. LogViewer supports powerful commands to filter out functions that you are not interested in. It can also save a filtered version of the log file as a text file.

This section includes:

Reading the LogViewer Display

Filtering the LogViewer Function List

Exporting LogViewer Files to Text


Reading the LogViewer Display

LogViewer displays a list of all functions in the order they were logged.

Each row of the display contains several columns. The significance of each column is as follows.

Column | Meaning
+/- | If this column contains a "+" (plus sign), it indicates that the function takes one or more parameters. To see the parameters and their values, either double click on the row or hit the right arrow key when the row is outlined in red. To hide it again, double click it again or hit the left arrow key when the row is outlined in red. There is also a "d#" value in this column. This indicates the "depth" of the function call (in other words, how deep the call is nested in other logged function calls).
# | The sequential row number of the function call. This is useful when you have filters applied and are interested to know how far apart two function calls are.
Thrd | The thread number that the function call was made on. This number is not a thread ID, but is rather an assigned number based on the order that threads were created in the process.
Caller | The instruction address that made the function call. This is derived from the return address for the call. It is actually the return address minus 5 bytes (the typical size of a call dword ptr instruction).
Module | The module that contains the calling instruction.
API Function | The name of the function. The name of the module that contains the function is omitted for brevity.
Return Value | The value returned by the function, if it is not a void function.

Double-clicking on a row in the viewer will expand the row to reveal the parameters to the function and their values "going in" to the function. If they are designated as OUT parameters, their value "coming out" is shown on the right.

You can also use the ENTER key or the right and left arrow keys to expand and collapse rows.

function calls that returned failure status codes are shaded in pink.


Filtering the LogViewer Function List

Logger usually captures some function calls that are not needed for your analysis. These can be filtered out by Logger when it creates the log file. However, this process is not reversible, so it is usually preferable to allow all functions to be logged, and then filter the display in LogViewer.

There are several ways to filter out function calls in LogViewer:

  • In the main viewing area, selected a function by clicking on it or using the cursor keys. (When a function is selected, LogViewer outlines it in red.) Then, press the DELETE key, or right-click and select Hide. This will hide all instances of that function call from the view.
  • Select View | APIs Display. A dialog box will appear that has three areas. On the right is an alphabetical listing of all functions, and on the left are categorical groupings. You can enable or disable the display of any function by checking or clearing the box to the left of its name.
  • Select View | Modules Display. A dialog box will appear that allows you to select calling modules; only those functions that were called from these modules will be displayed.
  • Select View | First Level Calls Only. This will display only calls that have "d0" in the left column. It is often desirable to hide function calls that are made by other logged functions. (For example, it is usually not interesting to know that ShellExecuteEx makes thirty different registry calls during its course of execution.)


Exporting LogViewer Files to Text

A powerful way to manipulate log files is to export them to text. This allows you to find specific parameter values by using the Find facility of any text editor. Although it is possible for a text file to be generated by Logger directly, you will have more flexibility if you use LogViewer to filter the function calls or add aliasing, and then export this information into a text file.

To create a text file from an .lgv file, open the file in LogViewer, and then select File | Export to Text. In the dialog box, choose a file name and location.

There are several options at the bottom of the dialog box:

Export Diff Information
This option will alias all pointers, handle values, and other values that change from execution to execution. Instead of outputting the actual value of a pointer (for example, "0x00123FA2"), LogViewer will output "Pointer." Similarly, handles will be aliased as "HeapHandle1" or some other value that will not register as a diff when the two files are compared using a differencing tool.
Include Non-Visible Rows
This option disables whatever filters are currently applied to the view while exporting.
Create a Separate File For Each Thread
This option splits up the text file by thread, making it easier to follow a thread of execution. This is useful if you intend to "diff" two instances of execution.
Export Range
This option specifies the range of rows to export.


The Logger Manifest

This section includes:

Overview of the Logging Manifest

Manifest File Placement

Manifest File Format


Overview of the Logging Manifest

The logging manifest is the group of "header" files that define the functions and COM interfaces that are intercepted and logged. These are not true C++ header files — they are in a slightly different format that explicitly declares the information needed by Logger.

For example, the manifest format facilitates the following features:

  • Designation of OUT parameters. These are parameters that should be logged both on their way into an function and also on their way out.
  • Definition of flag masks. This feature allows LogViewer to break a DWORD flag into its constituent bit labels for easier reading.
  • Definition of failure cases. This feature allows LogViewer to shade the rows of functions that have returned a failure status code or another error code. Also, if the function sets the "LastError" value for the thread, LogViewer can store away the error code and expand it to its corresponding human-readable error message.
  • Designation of parameters that can be aliased for log differencing. This feature gives LogViewer the option of assigning a constant string to a value that changes from execution to execution like pointers and handles when it exports the data to a file. You can then use a differencing tool to compare two execution logs for discrepancies. If pointers and handle values were not aliased, they would produce uninteresting discrepancies when the two files are compared.


Manifest File Placement

The primary manifest file must be named main.h.

When Logger is running, main.h must be located in the Manifest subdirectory of the directory containing logexts.dll.

LogViewer is more flexible than Logger. It will search for main.h in the following directories in this order:

  1. The Manifest directory subordinate to the directory containing logviewer.exe
  2. The WinExt\Manifest directory subordinate to the directory containing logviewer.exe
  3. The %WinDir%\System32\Manifest directory
  4. The %WinDir%\System\Manifest directory

All additional manifest files must reside in the same directory as main.h.


Manifest File Format

The file format for the manifest files borrows as much from C++ and IDL as possible. As a result, it is fairly easy to take a normal C++ SDK header file and modify it to be a manifest file. The parser fully supports C and C++ style comments to help you organize and document the file.

If you are attempting to add a manifest file or make alterations to an existing file, the best way to do it is to just experiment. When you issue a !logexts.logi or !logexts.loge command in the debugger, Logger will attempt to parse the manifest files. If it encounters a problem, it will produce an error message which might indicate the mistake.

A manifest file is made up of the following basic elements: module labels, category labels, function declarations, COM interface definitions, and type definitions. Other types of elements exist as well, but these are the most important.

Module Labels

A module label simply declares what DLL exports the functions that are declared thereafter. For example, if your manifest file is for logging a group of functions from COMCTL32.DLL, you would include the following module label before declaring any function prototypes:

module COMCTL32.DLL:

A module label must appear before any function declarations in a manifest file. A manifest file can contain any number of module labels.

Category Labels

Similar to a module label, a category label identifies which "category" all subsequent functions and/or COM interfaces belong to. For example, if you are creating a COMCTL32.DLL manifest file, you can use the following as your category label:

category CommonControls:

A manifest file can contain any number of category labels.

Function Declarations

An function declaration is what actually prompts Logger to log something. It is nearly identical to a function prototype found in a C/C++ header file. There are a few notable additions to the format, which can be best illustrated by the following example:

HANDLE [gle] FindFirstFileA(
       LPCSTR lpFileName,
       [out] LPWIN32_FIND_DATAA lpFindFileData);

The function FindFirstFileA takes two parameters. The first is lpFileName, which is a full path (usually with wildcards) defining where to search for a file or files. The second is a pointer to a WIN32_FIND_DATAA structure that will be used to contain the search results. The returned HANDLE is used for future calls to FindNextFileA. If FindFirstFileA returns INVALID_HANDLE_VALUE, then the function call failed and an error code can be procured by calling the GetLastError function.

The HANDLE type is declared as follows:

value DWORD HANDLE
{
#define NULL                       0 [fail]
#define INVALID_HANDLE_VALUE      -1 [fail]
};

If the value returned by this function is 0 or -1 (0xFFFFFFFF), Logger will assume that the function failed, because such values have a [fail] modifier in the value declaration. (See the Value Types section later in this section.) Since there is a [gle] modifier right before the function name, Logger recognizes that this function uses GetLastError to return error codes, so it captures the error code and logs it to the log file.

The [out] modifier on the lpFindFileData parameter informs Logger that the data structure is filled in by the function and should be logged when the function returns.

COM Interface Definitions

A COM interface is basically a vector of functions that can be called by a COM object's client. The manifest format borrows heavily from the Interface Definition Language (IDL) used in COM to define interfaces.

Consider the following example:

interface IDispatch : IUnknown
{
    HRESULT GetTypeInfoCount( UINT pctinfo  );

    HRESULT GetTypeInfo(
        UINT iTInfo,
        LCID lcid,
        LPVOID ppTInfo );

    HRESULT GetIDsOfNames(
        REFIID riid,
        LPOLECHAR* rgszNames,
        UINT cNames,
        LCID lcid,
        [out] DISPID* rgDispId );

    HRESULT Invoke(
        DISPID  dispIdMember,
        REFIID  riid,
        LCID  lcid,
        WORD  wFlags,
        DISPPARAMS*  pDispParams,
        VARIANT*  pVarResult,
        EXCEPINFO*  pExcepInfo,
        UINT*  puArgErr );
};

This declares an interface called IDispatch that is derived from IUnknown. It contains four member functions, which are declared in specific order within the interface's braces. Logger will intercept and log these member functions by replacing the function pointers in the interface's vtable (the actual binary vector of function pointers used at runtime) with its own. See the COM_INTERFACE_PTR Types section later in this section for more details on how Logger captures interfaces as they are handed out.

Type Definitions

Defining data types is the most important (and most tedious) part of manifest file development. The manifest language allows you to define human-readable labels for numeric values that are passed in or returned from a function.

For example, winerror.h defines a type called "WinError" that is a list of error values returned by most Microsoft® Win32® functions and their corresponding human-readable labels. This allows Logger and LogViewer to replace uninformative error codes with meaningful text.

You can also label individual bits within a bit mask to allow Logger and LogViewer to break a DWORD bit mask into its components.

There are 13 basic types supported by the manifest. They are listed in the following table.

Type | Length | Display Example
Pointer | 4 bytes | 0x001AF320
VOID | 0 bytes |
BYTE | 1 byte | 0x32
WORD | 2 bytes | 0x0A23
DWORD | 4 bytes | -234323
BOOL | 1 byte | TRUE
LPSTR | Length byte plus any number of characters | "Quick brown fox"
LPWSTR | Length byte plus any number of Unicode characters | "Jumped over the lazy dog"
GUID | 16 bytes | {0CF774D0-F077-11D1-B1BC-00C04F86C324}
COM_INTERFACE_PTR | 4 bytes | 0x0203404A
value | Dependent on base type | ERROR_TOO_MANY_OPEN_FILES
mask | Dependent on base type | WS_MAXIMIZED | WS_ALWAYSONTOP
struct | Dependent on size of encapsulated types | + lpRect nLeft 34 nRight 54 nTop 100 nBottom 300

Type definitions in manifest files work like C/C++ typedefs. For example, the following statement defines PLONG as a pointer to a LONG:

typedef LONG *PLONG;

Most basic typedefs have already been declared in main.h. You should only have to add typedefs that are specific to your component. Structure definitions have the same format as C/C++ struct types.

There are four special types: value, mask, GUID, and COM_INTERFACE_PTR.

Value Types
A value is a basic type that is broken out into human-readable labels. Most function documentation only refers to the #define value of a particular constant used in a function. For example, most programmers are unaware of what the actual value is for all the codes returned by GetLastError, making it unhelpful to see a cryptic numerical value in LogViewer. The manifest value overcomes this by allowing value declarations like so:
value LONG ChangeNotifyFlags
{
#define SHCNF_IDLIST      0x0000        // LPITEMIDLIST
#define SHCNF_PATHA       0x0001        // path name
#define SHCNF_PRINTERA    0x0002        // printer friendly name
#define SHCNF_DWORD       0x0003        // DWORD
#define SHCNF_PATHW       0x0005        // path name
#define SHCNF_PRINTERW    0x0006        // printer friendly name
};

This declares a new type called "ChangeNotifyFlags" derived from LONG. If this is used as a function parameter, the human-readable aliases will be displayed instead of the raw numbers.

Mask Types
Similar to value types, a mask type is a basic type (usually a DWORD) that is broken out into human-readable labels for each of the bits that have meaning. Take the following example:
mask DWORD DirectDrawOptSurfaceDescCapsFlags
{
#define DDOSDCAPS_OPTCOMPRESSED                 0x00000001
#define DDOSDCAPS_OPTREORDERED                  0x00000002
#define DDOSDCAPS_MONOLITHICMIPMAP              0x00000004
};

This declares a new type derived from DWORD that, if used as a function parameter, will have the individual values broken out for the user in LogViewer. So, if the value is 0x00000005, LogViewer will display:

DDOSDCAPS_OPTCOMPRESSED | DDOSDCAPS_MONOLITHICMIPMAP
GUID Types
GUIDs are 16-byte globally-unique identifiers that are used extensively in COM. They are declared in two ways:
struct __declspec(uuid("00020400-0000-0000-C000-000000000046")) IDispatch;

or

class __declspec(uuid("11219420-1768-11D1-95BE-00609797EA4F")) ShellLinkObject;

The first method is used to declare an interface identifier (IID). When displayed by LogViewer, "IID_" is appended to the beginning of the display name. The second method is used to declare a class identifier (CLSID). LogViewer appends "CLSID_" to the beginning of the display name.

If a GUID type is a parameter to a function, LogViewer will compare the value against all declared IIDs and CLSIDs. If a match is found, it will display the IID friendly name. If not, it will display the 32-hexadecimal-character value in standard GUID notation.

COM_INTERFACE_PTR Types
The COM_INTERFACE_PTR type is the base type of a COM interface pointer. When you declare a COM interface, you are actually defining a new type that is derived from COM_INTERFACE_PTR. As such, a pointer to such a type can be a parameter to a function. If a COM_INTERFACE_PTR basic type is declared as an OUT parameter to a function and there is a separate parameter that has an [iid] label, Logger will compare the passed in IID against all declared GUIDs. If there is a match and a COM interface was declared that has the same name as the IID, Logger will hook all the functions in that interface and log them.

Here is an example:

STDAPI CoCreateInstance(
  REFCLSID rclsid,     //Class identifier (CLSID) of the object
  LPUNKNOWN pUnkOuter, //Pointer to controlling IUnknown
  CLSCTX dwClsContext, //Context for running executable code
  [iid] REFIID riid,   //Reference to the identifier of the interface
  [out] COM_INTERFACE_PTR * ppv
                       //Address of output variable that receives
                       //the interface pointer requested in riid
);

In this example, riid has an [iid] modifier. This indicates to Logger that the pointer returned in ppv is a COM interface pointer for the interface identified by riid.

It is also possible to declare a function as follows:

DDRESULT DirectDrawCreateClipper( DWORD dwFlags, [out] LPDIRECTDRAWCLIPPER *lplpDDClipper, IUnknown *pUnkOuter );

In this example, LPDIRECTDRAWCLIPPER is defined as a pointer to the IDirectDrawClipper interface. Since Logger can identify which interface type is being returned in the lplpDDClipper parameter, there is no need for an [iid] modifier on any of the other parameters.


Remote Debugging

This section covers three different methods of remote debugging:

Remote Debugging Through the Debugger

Remote Debugging Through a Process Server

Remote Debugging Through Remote.exe

Remote user-mode debugging involves two computers: the client and the server. The server is the machine that has the application to be debugged and the user-mode debugger. The client is the machine that will remotely control the debugging session.

Remote kernel-mode debugging involves three computers: the client, the server, and the target computer. The target computer is the machine to be debugged. The server is a machine with a kernel debugger, located at the same physical location as the target computer. The client is the machine that will remotely control the debugging session. See Configuring Hardware for Kernel-Mode Debugging for details on the connection between the server and the target computer.

Choosing the Best Method

Performing remote debugging directly through the debugger is the most powerful of the three methods. As long as both the server and the client have the same debugger binaries installed, this is the recommended method.

The client and the server can be running Windows NT®, Windows® 2000, or later versions of Windows. They do not have to be running the same version as each other.

Performing remote debugging through a process server allows you to place a very light burden on the server. You first start a very small application called a process server on the server. Then you start CDB, NTSD, or WinDbg on the client. Nearly all the processing is done by this debugger (which is therefore called a Smart Client).

This method is especially useful when the target application is running on a computer with limited resources, or when a technician wishes to debug a process remotely and does not want to have a running debugger on the server. However, this process is slower than remote debugging through the debugger, and cannot be used to perform kernel-mode debugging.

The remote.exe tool is used to remotely control a Command Prompt window. It can be used to remotely control KD, CDB, or NTSD. It cannot be used with WinDbg.

If your client does not have copies of the debugger binaries, you must use the remote.exe method. This method is also required if you are running Windows 95 or Windows 98 on the client.

Controlling a User-Mode Debugger from a Kernel Debugger

It is also possible to control CDB (or NTSD) from the kernel debugger. This is yet another form of remote debugging. See Controlling the User-Mode Debugger from the Kernel Debugger for details.


Remote Debugging Through the Debugger

Remote debugging directly through the debugger involves running two debuggers at different locations. The debugger that is actually doing the debugging is called the Debugging Server. The debugger that is controlling the session from a distance is called the Debugging Client.

The two computers do not have to be running the same version of Windows; they can be running Windows NT, Windows 2000, or later versions of Windows. The actual debuggers used need not be the same; a WinDbg Debugging Client can connect to a CDB Debugging Server, and so on.

However, the debugger binaries on the two computers must be from identical releases of the Debugging Tools for Windows package.

Note Debugging Clients and Debugging Servers cannot be run on Windows 95, Windows 98, or Windows Millennium. To remotely control a debugger from a computer running one of these operating systems, see Remote Debugging through Remote.exe.

To set up this remote session, the Debugging Server is set up first, and then the Debugging Client is activated. Any number of Debugging Clients can connect to a Debugging Server. A single debugger can turn itself into several Debugging Servers at the same time, to facilitate different kinds of connections.

However, no single debugger can be a client and a server simultaneously. If you need to chain together three debuggers, see Remote Debugging Through a Process Server.

This section includes:

Activating the Debugging Server

Searching for Debugging Servers

Activating the Debugging Client

Client and Server Examples

Controlling the Remote Debugging Session


Activating the Debugging Server

There are two ways to activate the Debugging Server. It can be activated when the debugger is started by using the -server command-line option. It can also be activated after the debugger is running by using the .server command.

The debuggers support six different transport protocols: TCP, named pipe (NPIPE), 1394, COM port, secure sockets layer (SSL), and secure pipe (SPIPE). The SSL and SPIPE protocols are only supported on Windows 2000, Windows XP, and Windows .NET Server 2003. The 1394 protocol is only supported on Windows XP and Windows .NET Server 2003.

The general syntax for starting a Debugging Client depends on the protocol used. The following options exist:

Debugger -server tcp:port=Socket[,password=Password] [-noio] [Options]

Debugger -server npipe:pipe=PipeName[,password=Password] [-noio] [Options]

Debugger -server 1394:channel=1394Channel[,password=Password] [-noio] [Options]

Debugger -server com:port=COMPort,baud=BaudRate,channel=COMChannel[,password=Password] [-noio] [Options]

Debugger -server ssl:SSL-Parameters [-noio] [Options]

Debugger -server spipe:SPIPE-Parameters [-noio] [Options]

Another method of starting a Debugging Server is to use the .server (Create Debugging Server) command after the debugger has already been started. The syntax for this command is similar to that of the command line:

.server tcp:port=Socket[,password=Password]

.server npipe:pipe=PipeName[,password=Password]

.server 1394:channel=1394Channel[,password=Password]

.server com:port=COMPort,baud=BaudRate,channel=COMChannel[,password=Password]

.server ssl:SSL-Parameters

.server spipe:SPIPE-Parameters

The parameters in the previous commands have the following possible values:

Debugger
Can be KD, CDB, NTSD, or WinDbg.
Socket
When TCP protocol is used, Socket is the socket port number. In this parameter, it is also possible to specify a range of ports separated by a colon — for example, port=2:7. If this is done, the debugger will check each port in this range to see if it is free. If it finds a free port and no error occurs, the Debugging Server will be created.
PipeName
When NPIPE protocol is used, PipeName is a string that will serve as the name of the pipe. Each pipe name should identify a unique Debugging Server. If you attempt to reuse a pipe name, you will receive a message saying "Unable to start server, 0x800700B7." PipeName must not contain spaces or quotation marks. In user mode, PipeName can include a numerical printf-style format code. The debugger will replace this with the process ID of the debugger. A second such code will be replaced with the thread ID of the debugger. (The printf codes %04x and %05d will allow sufficient space for these numbers.)
1394Channel
(Windows XP and Windows .NET Server 2003 only) When 1394 protocol is used, Channel specifies the 1394 channel to be used. Valid channel numbers are 1 through 62. Any unused channel number can be selected. If you are performing kernel debugging over another 1394 connection, the channel number selected for Channel should not be the same channel used for the kernel connection. The channel number does not depend on the physical 1394 port chosen on the adapter.
COMPort
When COM protocol is used, COMPort specifies the COM port to be used. The prefix "COM" is optional — for example, both "com2" and "2" are acceptable.
BaudRate
When COM protocol is used, BaudRate specifies the baud rate at which the connection will run. Any baud rate that is supported by the hardware is permitted.
COMChannel
If COM protocol is used, COMChannel specifies the COM channel to be used in communicating with the Debugging Client. This can be any value between 0 and 254, inclusive.
SSL-Parameters
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) See the Secure Channel (S-Channel) documentation in the MSDN® for details.
SPIPE-Parameters
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) See the Secure Channel (S-Channel) documentation in the MSDN for details.
Password
This can be any alphanumeric string. If Password is used when the server is created, any Debugging Client must supply this password in order to connect to the debugging session.

Warning Using a password with TCP, NPIPE, 1394, or COM protocols only offers a small amount of protection. The password itself is not encrypted in any way. If you want to establish a secure remote session, you must use SSL or SPIPE protocol!

-noio
If the Debugging Server is created with the -noio option, no input or output can be done through the server. Only a Debugging Client can control the session. If NTSD is used for the server, no console window will be created at all.
Options
Any additional command-line parameters can be placed here. See Command-Line Options for a full list.

You can use the .server command to start multiple servers using different protocol options. This allows different kinds of Debugging Clients to join the session.


Searching for Debugging Servers

You can use KD or CDB with the -QR command-line option to obtain a list of available Debugging Servers that are running on a network server. Note that this list can also include servers that no longer exist but which were not shut down properly; connecting to one of these generates an error message. This list will also include process servers (these will be labelled "Remote Process Server" to avoid confusion).

The syntax for this is as follows:

Debugger -QR \\Server

In this specific case, Debugger can be either KD or CDB. The two backslashes (\\) preceding Server are optional.

In WinDbg, you can use the Connect to Remote Session dialog box to browse a list of available servers. See File | Connect to Remote Session for details.

Each Debugging Server is listed with the complete connection string that can be used to start a Debugging Client (except that any password will be replaced with an asterisk).


Activating the Debugging Client

Once the Debugging Server has been activated, you can start a Debugging Client on another computer and connect to the debugging session.

There are two ways to start a Debugging Client: by using the -remote command-line option, or by using the WinDbg graphical interface.

The protocol of the client must match the protocol of the server. The general syntax for starting a Debugging Client depends on the protocol used. The following options exist:

Debugger -remote tcp:server=Server,port=Socket[,password=Password]

Debugger -remote npipe:server=Server,pipe=PipeName[,password=Password]

Debugger -remote 1394:server=Server,channel=1394Channel[,password=Password]

Debugger -remote com:server=Server,port=COMPort,baud=BaudRate,channel=COMChannel[,password=Password]

Debugger -remote ssl:server=Server,SSL-Parameters

Debugger -remote spipe:server=Server,SPIPE-Parameters

To use the graphical interface to connect to a remote debugging session, WinDbg must be in dormant mode — it must either have been started with no command-line parameters, or it must have ended the previous debugging session. Select the File | Connect to Remote Session menu command, or press the CTRL+R shortcut key. When the Connect to remote debugger session dialog box appears, enter one of the following strings into the Connection string text box:

tcp:server=Server,port=Socket[,password=Password]

npipe:server=Server,pipe=PipeName[,password=Password]

1394:server=Server,channel=1394Channel[,password=Password]

com:server=Server,port=COMPort,baud=BaudRate,channel=COMChannel[,password=Password]

ssl:server=Server,SSL-Parameters

spipe:server=Server,SPIPE-Parameters

Alternatively, you can use the Browse button to locate active Debugging Servers. See File | Connect to Remote Session for details.

The parameters in the preceding commands have the following possible values:

Debugger
This does not have to be the same debugger as the one used by the Debugging Client — WinDbg, KD, and CDB are all interchangeable for purposes of remote debugging through the debugger.
Server
This is the network name of the machine on which the Debugging Server was created. The two initial backslashes (\\) are optional.
Socket
If TCP protocol is used, Socket is the same socket port number that was used when the server was created.
PipeName
If NPIPE protocol is used, PipeName is the name that was given to the pipe when the server was created.
1394Channel
(Windows XP and Windows .NET Server 2003 only) If 1394 protocol is used, Channel specifies the 1394 channel that was chosen when the server was created.
COMPort
If COM protocol is used, COMPort specifies the COM port to be used. The prefix "COM" is optional — for example, both "com2" and "2" are acceptable.
BaudRate
If COM protocol is used, BaudRate should match the baud rate chosen when the server was created.
COMChannel
If COM protocol is used, COMChannel should match the channel number chosen when the server was created.
SSL-Parameters
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) If SSL protocol is used, SSL-Parameters should match those used when the server was created.
SPIPE-Parameters
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) If SPIPE protocol is used, SPIPE-Parameters should match those used when the server was created.
Password
If a password was used when the server was created, Password must be supplied in order to create the Debugging Client. It must match the original password. Passwords are case-sensitive. If the wrong password is supplied, the error message will specify "Error 0x80004005."


Client and Server Examples

Suppose one person is running an application on a computer named \\BOX17. This application has problems, but the debugging technician is at a different site.

The first person sets up a Debugging Server using CDB on \\BOX17. The target application has a process ID of 122. TCP protocol is chosen, with a socket port number of 1025. The server is started with the following command:

E:\Debugging Tools for Windows> cdb -server tcp:port=1025 -p 122

On the other computer, the technician decides to use WinDbg as the Debugging Client. It can be started with this command:

G:\Debugging Tools> windbg -remote tcp:server=BOX17,port=1025

Here is another example. In this case, NPIPE protocol is chosen, and CDB is used instead of WinDbg. The first user chooses a pipe name. This can be any alphanumeric string — in this example, "MainPipe". The Debugging Server is started with this command:

E:\Debugging Tools for Windows> cdb -server npipe:pipe=MainPipe -v winmine.exe

The technician is not sure what name was used, so he or she queries the network for pipe names:

G:\Debugging Tools> cdb -QR \\BOX17
Servers on \\BOX17:
Debugger Server - npipe:Pipe=MainPipe
Remote Process Server - npipe:Pipe=AnotherPipe

Two pipes are shown. However, only one is a Debugging Server — the other is a process server, and we are not interested in that. So MainPipe must be the correct name. Then the following command can be used to start the Debugging Client:

G:\Debugging Tools> cdb -remote npipe:server=BOX17,pipe=MyPipe


Controlling the Remote Debugging Session

Once the remote session has been started, commands can be entered into either the Debugging Server or the Debugging Client. If there are multiple clients, any of them can enter commands. Once ENTER is pressed, the command is transmitted to the Debugging Server and executed.

Whenever one user enters a command, all users will see the command itself and its output. If this command was issued from a Debugging Client, all other users will see an identification, preceding the command, of which user issued the command. Commands issued from the Debugging Server do not have this prefix.

After a command is executed by one user, other users who are connected through KD or CDB will not see a new command prompt. On the other hand, users of WinDbg will see the prompt in the bottom panel of the Debugger Command window continuously, even when the debugger engine is running. Neither of these should be a cause for alarm; any user can enter a command at any time, and the engine will execute these commands in the order they were received.

Communication Between Users

Whenever a new Debugging Client connects to the session, all other users will see a message that this client has connected. No message is displayed when a client disconnects.

The .clients (List Debugging Clients) command will list all clients currently connected to the debugging session.

The .echo (Echo Comment) command and the * (Comment) specifier are useful for sending messages from one user to another.

WinDbg Workspaces

When WinDbg is being used as a Debugging Client, its workspace will only save values set through the graphical interface. Changes made through the Debugger Command window will not be saved. (This guarantees that only changes made by the local client will be reflected, since the Debugger Command window will accept input from all clients as well as the Debugging Server.)

File Paths

The symbol path, executable image path, and extension DLL path are all interpreted as file paths on the Debugging Client's computer. (Of course, network shares are permitted.) In addition, if WinDbg is used as a Debugging Client, it will have its own local source path as well. All source-related commands will access the source files on the local computer. Therefore, the proper paths have to be set on any client or server that will use source commands. See Setting Paths and Loading Files for details on these paths.

This multiple-path system allows a Debugging Client to use source-related commands without actually sharing the source files with other clients or with the server. This is useful if there are private or confidential source files which one of the users has access to.

Cancelling the Debugging Server

The .endsrv (End Debugging Server) command can be used to terminate a Debugging Server. If the debugger has established multiple Debugging Servers, you can cancel some of them while leaving others running.

Terminating a server will prevent any future clients from attaching to it. It will not cut off any clients that are currently attached through the server.

Exiting the Debugger and Terminating the Session

To exit from one Debugging Client without terminating the server, you must issue a command from that specific client. If this client is KD or CDB, use the CTRL+B key to exit. If you are using a script to run KD or CDB, use .remote_exit (Exit Debugging Client). If this client is WinDbg, choose Exit from the File menu to exit.

To terminate the entire session and exit the Debugging Server, use the Q (Quit) command. This command can be entered from any server or client, and it will terminate the entire session for all users.


Remote Debugging Through a Process Server

Remote debugging through a process server involves running a small application called a process server on the server. Then a user-mode debugger is started on the client. Since this debugger will be doing all of the actual processing, it is called the Smart Client.

The Debugging Tools for Windows package includes a process server called DbgSrv (dbgsrv.exe).

The two computers do not have to be running the same version of Windows; they can be running Windows NT, Windows 2000, or later versions of Windows. However, the debugger binaries used on the client and the DbgSrv binary used on the server must be from identical releases of the Debugging Tools for Windows package.

Note Process servers cannot be used to perform kernel-mode debugging. If you wish to perform remote kernel-mode debugging, see Remote Debugging Through the Debugger or Remote Debugging Through Remote.exe. You must also use Remote.exe if you wish to remotely control a debugger from a computer running Windows 9x.

To set up this remote session, the process server is set up first, and then the Smart Client is activated. Any number of Smart Clients can operate through a single process server; these debugging sessions will remain separate and will not interfere with each other. If a debugging session is ended, the process server will continue to run and can be used for new debugging sessions.

This section includes:

Activating a Process Server

Searching for Process Servers

Activating the Smart Client

Process Server Examples

Controlling a Process Server Session

Debugging Multiple Systems


Activating a Process Server

The process server that is included in the Debugging Tools for Windows package is called DbgSrv (dbgsrv.exe).

DbgSrv supports six different transport protocols: TCP, named pipe (NPIPE), 1394, COM port, secure sockets layer (SSL), and secure pipe (SPIPE). The SSL and SPIPE protocols are only supported on Windows 2000, Windows XP, and Windows .NET Server 2003. The 1394 protocol is only supported on Windows XP and Windows .NET Server 2003.

The syntax for the DbgSrv command line depends on the protocol used. The following options exist:

dbgsrv tcp:port=Socket[,password=Password]

dbgsrv npipe:pipe=PipeName[,password=Password]

dbgsrv 1394:channel=1394Channel[,password=Password]

dbgsrv com:port=COMPort,baud=BaudRate,channel=COMChannel[,password=Password]

dbgsrv ssl:SSL-Parameters

dbgsrv spipe:SPIPE-Parameters

The parameters in the previous commands have the following possible values:

Socket
When TCP protocol is used, Socket is the socket port number. It is also possible to specify a range of ports separated by a colon — for example, port=2:7. If this is done, the debugger will check each port in this range to see if it is free. If it finds a free port and no error occurs, the Debugging Server will be created.
PipeName
When NPIPE protocol is used, PipeName is a string that will serve as the name of the pipe. Each pipe name should identify a unique Debugging Server. If you attempt to reuse a pipe name, you will receive a message saying "Unable to start server, 0x800700B7." PipeName must not contain spaces or quotation marks. In user mode, PipeName can include a numerical printf-style format code. The debugger will replace this with the process ID of the debugger. A second such code will be replaced with the thread ID of the debugger. (The printf codes %04x and %05d will allow sufficient space for these numbers.)
1394Channel
(Windows XP and Windows .NET Server 2003 only) When 1394 protocol is used, Channel specifies the 1394 channel to be used. Valid channel numbers are 1 through 62. Any unused channel number can be selected. The channel number does not depend on the physical 1394 port chosen on the adapter.
COMPort
When COM protocol is used, COMPort specifies the COM port to be used. The prefix "COM" is optional — for example, both "com2" and "2" are acceptable.
BaudRate
When COM protocol is used, BaudRate specifies the baud rate at which the connection will run. Any baud rate that is supported by the hardware is permitted.
COMChannel
If COM protocol is used, COMChannel specifies the COM channel to be used in communicating with the Debugging Client. This can be any value between 0 and 254, inclusive.
SSL-Parameters
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) See the Secure Channel (S-Channel) documentation in the MSDN® for details.
SPIPE-Parameters
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) See the Secure Channel (S-Channel) documentation in the MSDN for details.
Password
This can be any alphanumeric string. If Password is used when the process server is created, any Smart Client must supply this password in order to connect to the debugging session.

Warning Using a password with TCP, NPIPE, 1394, or COM protocols only offers a small amount of protection. The password itself is not encrypted in any way. If you want to establish a secure remote session, you must use SSL or SPIPE protocol!

You can start any number of process servers on one computer. However, this is generally unnecessary, since one process server can be used by any number of Smart Clients (each engaged in a different debugging session).


Searching for Process Servers

You can use KD or CDB with the -QR command-line option to obtain a list of available process servers that are running on a network server. Note that this list can also include servers that no longer exist but which were not shut down properly; connecting to one of these generates an error message. This list will also include Debugging Servers (these will be labelled "Debugger Server" to avoid confusion).

The syntax for this is as follows:

Debugger -QR \\Server

In this specific case, Debugger can be either KD or CDB. The two backslashes (\\) preceding Server are optional.

WinDbg's Connect to Remote Session dialog box cannot be used to browse a list of process servers.


Activating the Smart Client

Once the DbgSrv process server has been activated, you can start a Smart Client on another computer and begin a debugging session. This is done by using the -premote parameter.

The protocol of the Smart Client must match the protocol of the process server. The general syntax for starting a Debugging Client depends on the protocol used. The following options exist:

Debugger -premote tcp:server=Server,port=Socket[,password=Password] [Options]

Debugger -premote npipe:server=Server,pipe=PipeName[,password=Password] [Options]

Debugger -premote 1394:server=Server,channel=1394Channel[,password=Password] [Options]

Debugger -premote com:server=Server,port=COMPort,baud=BaudRate,channel=COMChannel[,password=Password] [Options]

Debugger -premote ssl:server=Server,SSL-Parameters [Options]

Debugger -premote spipe:server=Server,SPIPE-Parameters [Options]

The parameters in the preceding commands have the following possible values:

Debugger
This can be CDB or WinDbg. Since process servers do not support kernel-mode debugging, KD cannot be used.
Server
This is the network name of the machine on which the process server was created. The two initial backslashes (\\) are optional.
Socket
If TCP protocol is used, Socket is the same socket port number that was used when the process server was created.
PipeName
If NPIPE protocol is used, PipeName is the name that was given to the pipe when the process server was created.
1394Channel
(Windows XP and Windows .NET Server 2003 only) If 1394 protocol is used, Channel specifies the 1394 channel that was chosen when the process server was created.
COMPort
If COM protocol is used, COMPort specifies the COM port to be used. The prefix "COM" is optional — for example, both "com2" and "2" are acceptable.
BaudRate
If COM protocol is used, BaudRate should match the baud rate chosen when the process server was created.
COMChannel
If COM protocol is used, COMChannel should match the channel number chosen when the process server was created.
SSL-Parameters
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) If SSL protocol is used, SSL-Parameters should match those used when the process server was created.
SPIPE-Parameters
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) If SPIPE protocol is used, SPIPE-Parameters should match those used when the process server was created.
Password
If a password was used when the process server was created, Password must be supplied in order to create the Smart Client. It must match the original password. Passwords are case-sensitive. If the wrong password is supplied, the error message will specify "Error 0x80004005."
Options
Any additional command-line parameters can be placed here. See Command-Line Options for a full list. If you are using CDB, this must specify the process you wish to debug. If you are using WinDbg, you can specify the process on the command line or through the graphical interface.

Since the process server simply acts as a gateway for the Smart Client, the additional Options will be the same as those you would use if you were starting a user-mode debugger on the same machine as the target application. See Starting the Debugger for instructions.

If you are using the -premote option with .attach (Attach to Process) or .create (Create Process), the parameters are the same as those listed above.

Using WinDbg as a Smart Client

When WinDbg is started as a smart client, it will remain attached to the process server permanently. If the debugging session is ended, the File | Attach to a Process command will allow you to attach to a process on the computer running the process server.

The File | Open Executable command cannot be used once WinDbg is running; a new process can only be spawned if it is included on the WinDbg command line.


Process Server Examples

Suppose one person is running an application on a computer named \\BOX17. This application has problems, but the debugging technician is at a different site.

The first person sets up a process server using DbgSrv on \\BOX17. The target application has a process ID of 122. TCP protocol is chosen, with a socket port number of 1025. The server is started with the following command:

E:\Debugging Tools for Windows> dbgsrv tcp:port=1025

On the other computer, the technician starts WinDbg as a Smart Client with this command:

G:\Debugging Tools> windbg -premote tcp:server=BOX17,port=1025 -p 122

Here is another example. In this case, NPIPE protocol is chosen, and CDB is used instead of WinDbg. The first user chooses a pipe name. This can be any alphanumeric string — in this example, "AnotherPipe". The process server is started with this command:

E:\Debugging Tools for Windows> dbgsrv npipe:pipe=AnotherPipe

The technician is not sure what name was used, so he or she queries the network for pipe names:

G:\Debugging Tools> cdb -QR \\BOX17
Servers on \\BOX17:
Debugger Server - npipe:Pipe=MainPipe
Remote Process Server - npipe:Pipe=AnotherPipe

Two pipes are shown. However, only one is a process server — the other is a Debugging Server, and we are not interested in that. So AnotherPipe must be the correct name. Then the following command can be used to start the Smart Client:

G:\Debugging Tools> cdb -premote npipe:server=BOX17,pipe=AnotherPipe -v sol.exe

Three-Machine Scenario

Since the Smart Client behaves like a regular debugger in every way, it can be used as a Debugging Server at the same time. This allows you to link three machines together.

Extending the previous example, the machine \\BOX17 can start the process server as before:

E:\Debugging Tools for Windows> dbgsrv npipe:pipe=AnotherPipe

The "middle machine" can start the debugger with both the -premote and -server parameters. In this case, let us suppose that this debugger is running on the machine \\BOX42:

G:\Debugging Tools> cdb -server npipe:pipe=ThirdPipe -premote npipe:server=BOX17,pipe=AnotherPipe -v sol.exe

Then a Debugging Client on a third machine can be started as follows:

C:\Latest Downloads\Debuggers> windbg -remote npipe:server=BOX42,pipe=ThirdPipe

In this scenario, the third machine is used to control the debugging, the second machine is where most of the actual processing is done, and the first machine is where the target application is located.


Controlling a Process Server Session

Once the remote session has been started, the Smart Client can be used as if it were debugging a target application on a single machine. All commands will behave as they would in this situation.

If you are using WinDbg as the Smart Client, you can begin and end debugging sessions as usual. However, this WinDbg process will continue to work through the process server even if a debugging session ends. Only processes running on the same machine as the process server can be debugged. It also means that WinDbg cannot start a kernel debugging session without first exiting.

To view a list of processes on the server's machine, use the .tlist (List Process IDs) command. In WinDbg, you can also use the File | Attach to a Process menu command.

Ending the Session

The debugger can exit, or end the debugging session, in the normal fashion. See Ending the Debugging Session for details. The process server will remain in operation and can be re-used as many times as desired. (It can also be used by for any number of simultaneous debugging sessions.)

If you wish to terminate the process server itself, you can use Task Manager to terminate the process server, or use the .endpsrv (End Process Server) command in the Smart Client.


Debugging Multiple Systems

The .attach (Attach to Process) and .create (Create Process) commands can be used to debug multiple processes.

You can use these commands can even if the processes are on different systems. Simply start a process server on each system, and then use the -premote parameter with .attach or .create to identify the proper process server.

The debugger will keep track of all the systems it is debugging. Each system will contain one or more processes, and each process will contain one or more threads.

The current or active system is the system currently being debugged. If you use the .attach or .create command again without specifying the -premote parameter, the debugger will attach to, or create, a process on the current system.

When debugging begins, the current system is the one that the debugger most recently attached to. If an exception occurs, the current system will switch to the system on which this occurred.

To control the debugging of multiple systems, the following methods are available:

  • The || (System Status) command displays information about one or more systems
  • The ||S (Set Current System) command allows you to select the current system
  • (WinDbg only) The View | Processes and Threads menu command allows you display or select systems, processes, and threads

For information on displaying or changing the current process or the current thread, see Controlling Processes and Threads.


Remote Debugging Through Remote.exe

Remote debugging through remote.exe involves running the debugger on the remote computer and running the remote.exe tool on the local computer.

The remote computer must be running Windows 2000 or later for the debuggers to function properly. The local computer can be running any Windows operating system.

Note Since remote.exe only works for console applications, it cannot be used to remotely control WinDbg. To remotely debug with WinDbg, see Remote Debugging Through the Debugger or Remote Debugging Through a Process Server.

This section includes:

The Remote.exe Utility

Starting a Remote.exe Session

Remote.exe Batch Files


The Remote.exe Utility

The remote.exe utility is a versatile server/client tool that allows you to run command-line programs on remote computers.

Remote.exe provides remote network access by means of named pipes to applications that use STDIN and STDOUT for input and output. Users at other computers on a network, or connected by a direct-dial modem connection. can either view the remote session or enter commands themselves.

This utility has a large number of uses. For example, when you are developing software, you can compile code with the processor and resources of a remote computer while you perform other tasks on your computer. You can also use remote.exe to distribute the processing requirements for a particular task across several computers.

Please note that remote.exe does no security authorization, and will permit anyone running Remote.exe Client to connect to your Remote.exe Server. This leaves the account under which the Remote.exe Server was run open to anyone who connects.


Starting a Remote.exe Session

There are two ways to start a remote.exe session with KD or CDB. Only the second of these methods works with NTSD.

Customizing Your MS-DOS Command Prompt Window

The Remote.exe Client and Remote.exe Server run in MS-DOS® Command Prompt windows.

To prepare for the remote session, you should customize this window to increase its usability. Open an MS-DOS Command Prompt window. Right-click on the title bar and select Properties. Select the Layout tab. Go to the section titled "Screen Buffer Size" and type 90 in the Width box and a value between 4000 and 9999 in the Height box. This enables scroll bars in the remote session on the kernel debugger.

Change the values for the height and width of the "Windows Size" section if you want to alter the shape of the command prompt. Select the Options tab. Enable the Edit Options quickedit mode and insert mode. This allows you to cut and paste information in the command prompt session. Click OK to apply the changes. Select the option to apply the changes to all future sessions when prompted.

Starting the Remote.exe Server: First Method

The general syntax for starting a Remote.exe Server is as follows:

remote /s "Command_Line" Unique_Id [/f Foreground_Color] [/b Background_Color]

This can be used to start KD or CDB on the remote computer, as in the following examples:

remote /s "KD [options]" MyBrokenBox

remote /s "CDB [options]" MyBrokenApp

This starts the Remote.exe Server in the MS-DOS Command Prompt window, and starts the debugger.

You cannot use this method to start NTSD directly, because the NTSD process runs in a different window than the one in which it was invoked.

Starting the Remote.exe Server: Second Method

There is an alternate method that can start a Remote.exe Server. This method involves first starting the debugger, and then using the .remote (Create Remote.exe Server) command to start the server.

Since the .remote command is issued after the debugger has started, this method works equally well with KD, CDB, and NTSD.

Here is an example. First, start the debugger in the normal fashion:

KD [options]

Once the debugger is running, use the .remote command:

.remote MyBrokenBox

This results in a KD process that is also a Remote.exe Server with an ID of "MyBrokenBox", exactly as in the first method.

One advantage of this method is that you do not have to decide in advance if you intend to use remote debugging. If you are debugging with one of the console debuggers and then decide that you would prefer someone in a remote location to take over, you can use the .remote command and then they can connect to your session.

Starting the Remote.exe Client

The general syntax for starting a Remote.exe Client is as follows:

remote /c ServerNetBIOSName Unique_ID [/l Lines_to_Get] [/f Foreground_Color] [/b Background_Color]

For example, if the "MyBrokenBox" session, described above, was started on a local host computer whose network name was "Server2", you can connect to it with the command:

remote /c server2 MyBrokenBox

Anyone on the network with appropriate permission can connect to this debug session, as long as they know your machine name and the session ID.

Issuing Commands

Commands are issued through the Remote.exe Client and are sent to the Remote.exe Server. You can enter any command into the client as if you were directly entering it into the debugger.

To exit from the remote.exe session on the Remote.exe Client, enter the @Q command. This leaves the Remote.exe Server and the debugger running.

To end the server session, enter the @K command on the Remote.exe Server.


Remote.exe Batch Files

As a more detailed example of remote debugging with remote.exe, assume the following about a local host computer in a three-computer kernel debugging scenario:

  • Debugging needs to take place over a null-modem cable on COM2.
  • The symbol files are in the folder c:\winnt\symbols.
  • A log file called debug.log is created in c:\temp.

The log file holds a copy of everything you see on the Debug screen during your debug session. All input from the person doing the debugging, and all output from the kernel debugger on the target system, is written to that log file.

A sample batch file for running a debugging session on the local host is:

set _NT_DEBUG_PORT=com2
set _NT_DEBUG_BAUD_RATE=19200
set _NT_SYMBOL_PATH=c:\winnt\symbols
set _NT_LOG_FILE_OPEN=c:\temp\debug.log
remote /s "KD -v" debug

Note If this batch file is not in the same directory as Remote.exe, and Remote.exe is not in a directory listed in the system path, then you should give the full path to the utility when invoking Remote.exe in this batch file.

After this batch file is run, anyone with a Windows computer that is networked to the local host computer can connect to the debug session by using the following command:

remote /c computername debug

where computername is the NetBIOS name of the local host computer.


Symbols

This section includes:

Symbol Files: Overview

Installing Windows Symbol Files

Using Symbol Servers and Symbol Stores

Using SymChk

Deferred Symbol Loading

Setting Symbol Options

Symbol Syntax and Symbol Matching

Symbol Status Abbreviations

Performance-Optimized Code

Invalid or Missing Symbols


Symbol Files: Overview

When applications, libraries, drivers, or operating systems are linked, the linker which creates the .exe and .dll files also creates a number of additional files known as symbol files.

Symbol files hold a variety of data which are not actually needed when running the binaries, but which could be very useful in the debugging process.

Typically, symbol files might contain:

  • Global variables
  • Local variables
  • Function names and the addresses of their entry points
  • FPO data
  • Source-line numbers

The binaries are smaller and faster as a result of keeping these symbol files separate. However, this means that when debugging, you must make sure that the debugger can access the symbol files that are associated with the target you are debugging.

Both interactive debugging and debugging crash dump files require symbols. You must obtain the proper symbols for the code that you wish to debug, and load these symbols into the debugger.

Windows Symbols

Microsoft® Windows NT® and Windows® 2000 keep their symbols in files with the extensions .pdb and .dbg. Windows XP and Windows .NET Server 2003 use .pdb files exclusively. Windows drivers can follow either model.

The compiler and the linker control the symbol format. The Visual C++® 5.0 Linker creates both .pdb and .dbg symbol files — the .dbg files it creates are essentially pointers to the .pdb files. The Visual C++ 6.0 Linker places all symbols into .pdb files.

All NT-based operating systems and drivers are built in two versions. The free build (or retail build) has relatively small binaries, and the checked build (or debug build) has larger binaries, with more debugging symbols in the code itself. Each of these builds has its own symbol files. When debugging a target on Windows, you must use the symbol files that match the build of Windows on the target. See Free Build and Checked Build for more details.

The following table lists several of the directories which exist in a standard Windows symbol tree:

Directory | Contains Symbol Files for
ACM | Microsoft® Audio Compression Manager files
COM | Executable files (.com)
CPL | Control Panel programs
DLL | Dynamic-link library files (.dll)
DRV | Driver files (.drv)
EXE | Executable files (.exe)
SCR | Screen-saver files
SYS | Driver files (.sys)


Installing Windows Symbol Files

Before you debug the Windows kernel or a driver or application running on Windows, you need access to the proper symbol files.

If you have access to the internet while your debugger is running, you may wish to use Microsoft's public symbol store. You can connect to this with one simple use of the .symfix (Set Symbol Store Path) command. For full details, see Using Symbol Servers and Symbol Stores.

If you plan to install symbols manually, it is crucial that you remember this basic rule: the symbol files on the host computer are required to match the version of Windows installed on the target computer. If you are planning to do a kernel mode debug of a Windows XP target from a Windows 2000 host, you need to install the Windows XP symbol files on the Windows 2000 system. If you plan to perform user-mode debugging on the same computer as the target application, then install the symbol files that match the version of Windows running on that system. If you are analyzing a memory dump file, then the version of symbol files needed on the debug computer are those that match the version of the operating system that produced the dump file, not necessarily those matching the version of the operating system on the machine running the debug session.

Note If you are going to use your host computer to debug several different target computers, you may need symbols for more than one build of Windows. In this case, be sure to install each symbol collection in a distinct directory path.

If you are debugging from a Windows computer attached to a network, it may be useful to install symbols for a variety of different builds on a network server. Microsoft® debuggers will accept a network path (\\server\share\dir) as a valid symbol directory path. This avoids the need for each debugging computer on the network to install the symbol files separately.

Symbol files stored on a crashed target computer are not useable by the debugger on the host computer.

To install symbol files for Windows XP or Windows .NET Server 2003

  1. Make sure you have at least 1000 MB of available space on the disk drive of the host computer.
  2. Open http://www.microsoft.com/ddk/debugging/symbols.asp in your internet browser.
  3. Follow the links to download the appropriate symbol package.

To install symbol files for Windows 2000 from the Web

  1. Make sure you have at least 1000 MB of available space on the disk drive of the host computer.
  2. Open http://www.microsoft.com/ddk/debugging/symbols.asp in your internet browser.
  3. Follow the links to download Windows 2000 symbols.

To install symbol files for Windows 2000 from the Support CD

  1. Make sure you have at least 500 MB of available space on the disk drive of the host computer.
  2. Insert the Windows 2000 Customer Support Diagnostics CD.
  3. Click on Install Symbols.
  4. Select either Install Retail Symbols (free build) or Install Debug Symbols (checked build). The symbols must match the version of the operating system being debugged.
  5. Enter the path where the symbols are to be stored, or accept the default path. The default path is %windir%\symbols.

To install symbol files for Windows NT 4.0 from the Windows CD

  1. Make sure you have at least 450 MB of available space on the disk drive of the host computer.
  2. From the command prompt, go to the \support\debug folder on the Windows NT 4.0 CD-ROM.
  3. Run the ExpndSym command. ExpndSym requires two command-line parameters, Source_drive and Target_folder. Source_drive is the CD-ROM drive. Target_folder is where you want the symbol files installed.

    A typical example of the use of the tool might look like the following:

    expandsym d: c:\winnt

    In this example, the symbols will be placed in c:\winnt\symbols (not in c:\winnt itself).

Sequence of Symbol File Installation

If you intend to keep your symbols in a single directory tree, the installation sequence of symbol files should mirror the installation sequence of operating system files:

To install the symbol files in correct sequence

  1. Install the operating system symbol files.
  2. Install the symbol files for the currently installed Service Pack (if any).
  3. Install the symbol files for any Hot Fixes that were installed after the current Service Pack was installed (if any).

However, a superior setup would be to install the symbols from each Service Pack and Hot Fix in a separate directory tree, and put all these directories in your symbol search path. The debugger will then find the proper symbols. (Since the symbol files have date and time stamps, the debugger will be able to know which are the most recent.) See Setting Paths and Loading Files for details.

Installing User-Mode Symbols

If you are going to debug a user-mode application, you also need to install the symbols for this application as well.

You can debug an application if you have its symbols but not Windows symbols. However, your results will be much more limited. You will still be able to step through the application code, but any debugger activity which requires analysis of the kernel (such as getting a stack trace) is likely to fail.


Using Symbol Servers and Symbol Stores

To set up symbols correctly for debugging can be a challenging task, particularly for kernel debugging. It often requires that you know the names and releases of all products on your computer. The debugger must be able to locate each of the symbol files corresponding to the product releases and service packs.

This can result in an extremely long symbol path consisting of a long list of directories.

To simplify these difficulties in coordinating symbol files, a symbol server can be used. A symbol server enables the debuggers to automatically retrieve the correct symbol files without product names, releases, or build numbers. Debugging Tools for Windows contains a symbol server called SymSrv.

The symbol server is activated by including a certain text string in the symbol path. Each time the debugger needs to load symbols for a newly loaded module, it calls the symbol server to locate the appropriate symbol files. The symbol server locates the files in a symbol store. This is a collection of symbol files, an index, and a tool that can be used by an administrator to add and delete files. The files are indexed according to unique parameters such as the time stamp and image size. Debugging Tools for Windows contains a symbol store tool called SymStore.

This section includes:

Using SymSrv

Using Other Symbol Servers

Firewalls and Proxy Servers

Using SymStore

Using Other Symbol Stores


Using SymSrv

SymSrv (symsrv.dll) is a symbol server that is included in the Debugging Tools for Windows package.

SymSrv can deliver symbol files from a centralized symbol store. This store can contain any number of symbol files, corresponding to any number of programs or operating systems. The store can also contain binary files (this is useful when debugging minidumps).

The store can contain the actual symbol and binary files, or it can simply contain pointers to symbol files. If the store contains pointers, SymSrv will retrieve the actual files directly from their sources.

SymSrv can also be used to separate a large symbol store into a smaller subset that is appropriate for a specialized debugging task.

Finally, SymSrv can obtain symbol files from an HTTP or HTTPS source using the logon information provided by the operating system. SymSrv supports HTTPS sites protected by smartcards, certificates, and regular logins and passwords.

Setting the Symbol Path

To use this symbol server, symsrv.dll must be installed in the same directory as the debugger. The symbol path must be set in one of the following ways:

set _NT_SYMBOL_PATH = symsrv*ServerDLL*DownstreamStore*\\Server\Share

set _NT_SYMBOL_PATH = symsrv*ServerDLL*\\Server\Share

set _NT_SYMBOL_PATH = srv*DownstreamStore*\\Server\Share

set _NT_SYMBOL_PATH = srv*\\Server\Share

The parts of this syntax are explained in the following table.

Field | Description
symsrv | This keyword must always appear first. It indicates to the debugger that this item is a symbol server, not just a normal symbol directory.
ServerDLL | Specifies the name of the symbol server DLL. If you are using the SymSrv symbol server, this will always be symsrv.dll.
srv | This is shorthand for symsrv*symsrv.dll.
DownstreamStore | Specifies a local directory or network share that will be used to cache individual symbol files. If DownstreamStore specifies a directory that does not exist, SymStore will attempt to create it.
\\Server\Share | Specifies the server and share of the symbol store.

The DownstreamStore parameter can be omitted, as shown in the first syntax example before the table. This parameter is required if you are accessing symbols from an HTTP or HTTPS site, or if you are using compressed files on your store.

If DownstreamStore is not included, the debugger will load all symbol files directly from the server.

If DownstreamStore is included, the debugger will first look for a symbol file in this location. If the symbol file is not found, the debugger will locate the symbol file from the specified Server and Share, and then cache a copy of this file in the downstream store. The file will be copied to a subdirectory in the tree under DownstreamStore which corresponds to its location in the tree under \\Server\Share.

The symbol server does not have to be the only entry in the symbol path. If the symbol path consists of multiple entries, the debugger checks each entry for the needed symbol files, in order (from left to right), regardless of whether a symbol server or an actual directory is named.

Here are some examples. To use SymSrv as the symbol server with a symbol store on \\mybuilds\mysymbols, set the following symbol path:

set _NT_SYMBOL_PATH= symsrv*symsrv.dll*\\mybuilds\mysymbols

To set the symbol path so that the debugger will copy symbol files from a symbol store on \\mybuilds\mysymbols to your local directory c:\localsymbols, use:

set _NT_SYMBOL_PATH=symsrv*symsrv.dll*c:\localsymbols*\\mybuilds\mysymbols

To set the symbol path so that the debugger will copy symbol files from the HTTP site www.somecompany.com/manysymbols to a local network directory \\localserver\myshare\mycache, use:

set _NT_SYMBOL_PATH=symsrv*symsrv.dll*\\localserver\myshare\mycache*http://www.somecompany.com/manysymbols

This last example can also be shortened as such:

set _NT_SYMBOL_PATH=srv*\\localserver\myshare\mycache*http://www.somecompany.com/manysymbols

In addition, the symbol path can contain several directories or symbol servers, separated by semicolons. This allows you to locate symbols from multiple locations (or even multiple symbol servers). If a binary has a mismatched symbol file, the debugger cannot locate it using the symbol server because it checks only for the exact parameters. However, the debugger may find a mismatched symbol file with the correct name, using the traditional symbol path, and successfully load it. Even though the file is technically not the correct symbol file, it might provide useful information.

Public Symbol Store

Microsoft has a Web site that makes Windows symbols publicly available. You can refer directly to this site in your symbol path:

set _NT_SYMBOL_PATH=srv*DownstreamStore*http://msdl.microsoft.com/download/symbols

When using the public symbol store, you should always use a downstream store. Otherwise you will end up downloading the same file several times!

You can add this address to your symbol path automatically by using the .symfix (Set Symbol Store Path) command. To append the public symbol store to your existing symbol path, use the following syntax:

.symfix+ DownstreamStore

Note To successfully access Microsoft's public symbol store, you will need a fast internet connection. If your internet connection is only 56 Kps or slower, you should install Windows symbols directly onto your hard drive. For details, see Installing Windows Symbol Files.

For more information on the public symbol store, see http://www.microsoft.com/ddk/debugging/symbols.asp.

Compressed Files

SymSrv is compatible with symbol stores that contain compressed files, as long as this compression has been done with the compress.exe tool that is distributed with the Platform SDK. Compressed files should have an underscore as the last character in their file extensions (for example, module1.pd_ or module2.db_). For details, see Using SymStore.

If the files on the store are compressed, you must use a downstream store. SymSrv will uncompress all files before caching them on the downstream store.

Deleting the Cache

If you are using a DownstreamStore as a cache, you can delete this directory at any time to save disk space.

It is possible to have a vast symbol store that includes symbol files for many different programs or Windows versions. If you upgrade the version of Windows used on your target computer, the cached symbol files will all match the earlier version. These cached files will not be of any further use, and therefore this might be a good time to delete the cache.

How SymSrv Locates Files

SymSrv creates a fully-qualified UNC path to the desired symbol file. This path begins with the path to the symbol store recorded in the _NT_SYMBOL_PATH environment variable. The SymbolServer routine is then used to identify the name of the desired file; this name is appended to the path as a directory name. Another directory name, consisting of the concatenation of the id, two, and three parameters passed to SymbolServer, is then appended. If any of these values is zero, they are omitted.

The resulting directory is searched for the symbol file, or a symbol store pointer file.

If this search is successful, SymbolServer passes the path to the caller and returns TRUE. If the file is not found, SymbolServer returns FALSE.


Using Other Symbol Servers

If you wish to use a different method for your symbol search, you can provide your own symbol server DLL rather than using SymSrv.

Setting the Symbol Path

When implementing a symbol server other than SymSrv, the debugger's symbol path is set in the same way as with SymSrv. See Using SymSrv for an explanation of the symbol path syntax. The only change you need to make is to replace the string symsrv.dll with the name of your own symbol server DLL.

If you wish, you are free to use a different syntax within the parameters to indicate the use of different technologies such as UNC paths, SQL database identifiers, or Internet specifications.

Implementing Your Own Symbol Server

The central portion of the server is the code that communicates with DbgHelp to find the symbols. Every time DbgHelp requires symbols for a newly loaded module, it calls the symbol server to locate the appropriate symbol files. The symbol server locates each file according to unique parameters such as the time stamp or image size. The server returns a validated path to the requested file. To implement this, the server must export the SymbolServer function. The server should also support the SymbolServerSetOptions and SymbolServerGetOptions functions.

Furthermore, DbgHelp will call the SymbolServerClose function, if it is exported by the server.

You must not change the actual symbol file name returned by your symbol server. DbgHelp stores the name of a symbol file in multiple locations. Therefore, the server must return a file of the same name as that specified when the symbol was requested. This restriction is needed to assure that the symbol names displayed during symbol loading are the ones that the programmer will recognize.

Restrictions on Multiple Symbol Servers

DbgHelp supports the use of only one symbol server at a time. Your symbol path can contain multiple instances of the same symbol server DLL, but not two different symbol server DLLs. This is not much of a restriction — since you are still free to include multiple instances of a symbol server in your symbol path, each pointing to a different symbol store. But if you want to switch between two different symbol server DLLs, you will have to change the symbol path each time.

Installing Your Symbol Server

The details of your symbol server installation will depend on your situation. You might wish to set up an installation process that copies your symbol server DLL and sets the _NT_SYMBOL_PATH environment variable automatically.

Depending on the technology used in your server, you may also need to install or access the symbol data itself.


Firewalls and Proxy Servers

If you are using SymSrv to access symbols, and your computer is on a network that uses a proxy server or the symbol store is outside your firewall, authentication may be required for data transmission to take place.

When SymSrv receives authentication requests, the debugger can either display the authentication request or automatically refuse the request, depending on how it has been configured.

SymSrv has integrated support for a proxy server. It can either use the default proxy server, or it can use another proxy server of your choice.

Authentication Requests

The debugger can be configured to allow authentication requests. When a firewall or proxy server requests authorization, a dialog box will appear. You will have to enter some sort of information (usually a user name and password) before the debugger can download symbols. If you enter incorrect information, the dialog box will be redisplayed. If you select the Cancel button, the dialog box will vanish and no symbol information will be transferred.

If the debugger is configured to refuse all authentication requests, no dialog box will appear, and no symbols will be transferred if authentication is required.

If you refuse an authentication request, or if the debugger automatically refuses an authentication request, SymSrv will make no further attempts to contact the symbol store. If you wish to renew contact, you must either restart the debugging session or use !symsrv close.

Note If you are using KD or CDB, the authentication dialog box may appear behind an open window. If this occurs, you may have to move or minimize some windows in order to find this dialog box.

In WinDbg, authentication requests are allowed by default. In KD and CDB, authentication requests are automatically refused by default.

To allow authentication requests, use either !sym prompts or .symopt-0x80000. To refuse all requests, use either !sym prompts off or .symopt+0x80000. To display the current setting, use !sym.

You must use .reload (Reload Module) after making any changes to the authentication permission status.

Choosing a Proxy Server

To select a default proxy server for Windows, open Internet Options in Control Panel, select the Connections tab, and then select the LAN Settings button. You can then enter the proxy server name and port number, or select Advanced to configure multiple proxy servers. For more details, see Internet Explorer's help file.

To select a specific proxy server for symsrv to use, set the _NT_SYMBOL_PROXY environment variable equal to the name or IP of the proxy server, followed by a colon and then the port number. For example:

set _NT_SYMBOL_PROXY=myproxyserver:80

When a proxy server is chosen in this way, it will be used by any debugger that is using SymSrv to access a symbol server. It will also be used by any other debugging tool that uses DbgHelp as its symbol handler. No other programs will be affected by this setting.


Using SymStore

SymStore (symstore.exe) is a tool for creating symbol stores. It is included in the Debugging Tools for Windows package.

SymStore stores symbols in a format that enables the debugger to look up the symbols based on the time stamp and size of the image (for a .dbg or executable file), or signature and age (for a .pdb file). The advantage of the symbol store over the traditional symbol storage format is that all symbols can be stored or referenced on the same server and retrieved by the debugger without any prior knowledge of which product contains the corresponding symbol.

Note that multiple versions of .pdb symbol files (for example, public and private versions) cannot be stored on the same server, because they each contain the same signature and age.

SymStore Transactions

Every call to SymStore is recorded as a transaction. There are two types of transactions: add and delete.

When the symbol store is created, a directory, called "000admin", is created under the root of the server. The 000admin directory contains one file for each transaction, as well as the log files server.txt and history.txt. The server.txt file contains a list of all transactions that are currently on the server. The history.txt file contains a chronological history of all transactions.

Each time SymStore stores or removes symbol files, a new transaction number is created. Then, a file, whose name is this transaction number, is created in 000admin. This file contains a list of all the files or pointers that have been added to the symbol store during this transaction. If a transaction is deleted, SymStore will read through its transaction file to determine which files and pointers it should delete.

The add and del options specify whether an add or delete transaction is to be performed. Including the /p option with an add operation specifies that a pointer is to be added; omitting the /p option specifies that the actual symbol file is to be added.

It is also possible to create the symbol store in two separate stages. In the first stage, you use SymStore with the /x option to create an index file. In the second stage, you use SymStore with the /y option to create the actual store of files or pointers from the information in the index file.

This can be a useful technique for a variety of reasons. For instance, this allows the symbol store to be easily recreated if the store is somehow lost, as long as the index file still exists. Or perhaps the computer containing the symbol files has a slow network connection to the computer on which the symbol store will be created. In this case, you can create the index file on the same machine as the symbol files, transfer the index file to the second machine, and then create the store on the second machine.

For a full listing of all SymStore parameters, see SymStore Command-Line Options.

Note SymStore does not support simultaneous transactions from multiple users. It is recommended that one user be designated "administrator" of the symbol store and be responsible for all add and del transactions.

Transaction Examples

Here are two examples of SymStore adding symbol pointers for build 2195 of Windows 2000 to \\foo\symsrv:

symstore add /r /p /f \\BuildServer\BuildShare\2195free\symbols\*.* /s \\foo\symsrv /t "Windows 2000" /v "Build 2195 x86 free" /c "Sample add"
symstore add /r /p /f \\BuildServer\BuildShare\2195free\symbols\*.* /s \\foo\symsrv /t "Windows 2000" /v "Build 2195 x86 checked" /c "Sample add"

In the following example, SymStore adds the actual symbol files for an application project in \\largeapp\appserver\bins to \\foo\symsrv:

symstore add /r /f \\largeapp\appserver\bins\*.* /s \\foo\symsrv /t "Large Application" /v "Build 432" /c "Sample add"

Here is an example of how an index file is used. First, SymStore creates an index file based on the collection of symbol files in \\largeapp\appserver\bins\. In this case, the index file is placed on a third computer, \\hubserver\hubshare. You use the /g option to specify that the file prefix "\\largeapp\appserver" might change in the future:

symstore add /r /p /g \\largeapp\appserver /f \\largeapp\appserver\bins\*.* /x \\hubserver\hubshare\myindex.txt

Now suppose you move all the symbol files off of the machine \\largeapp\appserver and put them on \\myarchive\appserver. You can then create the symbol store itself from the index file \\hubserver\hubshare\myindex.txt as follows:

symstore add /y \\hubserver\hubshare\myindex.txt /g \\myarchive\appserver /s \\foo\symsrv /p /t "Large Application" /v "Build 432" /c "Sample Add from Index"

Finally, here is an example of SymStore deleting a file added by a previous transaction. See the following section for an explanation of how to determine the transaction ID (in this case, 0000000096).

symstore del /i 0000000096 /s \\foo\symsrv

Compressed Files

SymStore can be used with compressed files in two different ways:

  1. Use SymStore with the /p option to store pointers to the symbol files. After SymStore finishes, compress the files that the pointers refer to.
  2. Use SymStore with the /x option to create an index file. After SymStore finishes, compress the files listed in the index file. Then, use SymStore with the /y option (and, if you wish, the /p option) to store the files or pointers to the files in the symbol store. (SymStore will not need to uncompress the files to perform this operation.)

Your symbol server will be responsible for uncompressing the files at the proper time.

If you are using SymSrv as your symbol server, any compression should be done using the compress.exe tool that is distributed with the Platform SDK. Compressed files should have an underscore as the last character in their file extensions (for example, module1.pd_ or module2.db_). For details, see Using SymSrv.

The server.txt and history.txt Files

When a transaction is added, several items of information are added to server.txt and history.txt for future lookup capability. The following is an example of a line in server.txt and history.txt for an add transaction:

0000000096,add,ptr,10/09/99,00:08:32,Windows NT 4.0 SP 4,x86 fre 1.156c-RTM-2,Added from \\mybuilds\symbols,

This is a comma-separated line. The fields are explained as follows:

Field | Description
0000000096 | Transaction ID number, as created by SymStore.
add | Type of transaction. This field can be either add or del.
ptr | Whether files or pointers were added. This field can be either file or ptr.
10/09/99 | Date when transaction occurred.
00:08:32 | Time when transaction started.
Windows NT | Product.
x86 fre | Version (optional).
Added from | Comment (optional)
Unused | (Reserved for later use.)

Here are some sample lines from the transaction file 0000000096. Each line records the directory and the location of the file or pointer that was added to the directory.

canon800.dbg\35d9fd51b000,\\mybuilds\symbols\sp4\dll\canon800.dbg
canonlbp.dbg\35d9fd521c000,\\mybuilds\symbols\sp4\dll\canonlbp.dbg
certadm.dbg\352bf2f48000,\\mybuilds\symbols\sp4\dll\certadm.dbg
certcli.dbg\352bf2f1b000,\\mybuilds\symbols\sp4\dll\certcli.dbg
certcrpt.dbg\352bf04911000,\\mybuilds\symbols\sp4\dll\certcrpt.dbg
certenc.dbg\352bf2f7f000,\\mybuilds\symbols\sp4\dll\certenc.dbg

If you use a del transaction to undo the original add transactions, these lines will be removed from server.txt, and the following line will be added to history.txt:

0000000105,del,0000000096

The fields for the delete transaction are described as follows.

Field | Description
0000000105 | Transaction ID number, as created by SymStore.
del | Type of transaction. This field can be either add or del.
0000000096 | Transaction that was deleted.

Symbol Storage Format

SymStore uses the file system itself as a database. It creates a large tree of directories, with directory names based on such things as the symbol file time stamps, signatures, age, and other data.

For example, after several different acpi.dbgs have been added to the server, the directories could look like this:

Directory of \\mybuilds\symsrv\acpi.dbg
10/06/1999  05:46p      <DIR>          .
10/06/1999  05:46p      <DIR>          ..
10/04/1999  01:54p      <DIR>          37cdb03962040
10/04/1999  01:49p      <DIR>          37cdb04027740
10/04/1999  12:56p      <DIR>          37e3eb1c62060
10/04/1999  12:51p      <DIR>          37e3ebcc27760
10/04/1999  12:45p      <DIR>          37ed151662060
10/04/1999  12:39p      <DIR>          37ed15dd27760
10/04/1999  11:33a      <DIR>          37f03ce962020
10/04/1999  11:21a      <DIR>          37f03cf7277c0
10/06/1999  05:38p      <DIR>          37fa7f00277e0
10/06/1999  05:46p      <DIR>          37fa7f01620a0

In this example, the lookup path for the acpi.dbg symbol file might look like this: \\mybuilds\symsrv\acpi.dbg\37cdb03962040.

Three files may exist inside the lookup directory:

  1. acpi.dbg, if the file was stored
  2. file.ptr with a path to the actual symbol file, if a pointer was stored
  3. refs.ptr, which contains a list of all the current locations for acpi.dbg with this timestamp and image size that are currently added to the symbol store

Displaying the directory listing of \\mybuilds\symsrv\acpi.dbg\37cdb03962040 gives the following:

10/04/1999  01:54p                  52 file.ptr
10/04/1999  01:54p                  67 refs.ptr

The file file.ptr contains the text string "\\mybuilds\symbols\x86\2128.chk\symbols\sys\acpi.dbg". Since there is no file called acpi.dbg in this directory, the debugger will try to find the file at \\mybuilds\symbols\x86\2128.chk\symbols\sys\acpi.dbg.

The contents of refs.ptr are used only by SymStore, not the debugger. This file contains a record of all transactions that have taken place in this directory. A sample line from refs.ptr might be:

0000000026,ptr,\\mybuilds\symbols\x86\2128.chk\symbols\sys\acpi.dbg

This shows that a pointer to \\mybuilds\symbols\x86\2128.chk\symbols\sys\acpi.dbg was added with transaction "0000000026".

Some symbol files stay constant through various products or builds or a particular product. One example of this is the Windows 2000 file msvcrt.pdb. Doing a directory of \\mybuilds\symsrv\msvcrt.pdb shows that only two versions of msvcrt.pdb have been added to the symbols server:

Directory of \\mybuilds\symsrv\msvcrt.pdb
10/06/1999  05:37p      <DIR>          .
10/06/1999  05:37p      <DIR>          ..
10/04/1999  11:19a      <DIR>          37a8f40e2
10/06/1999  05:37p      <DIR>          37f2c2272

However, doing a directory of \\mybuilds\symsrv\msvcrt.pdb\37a8f40e2 shows that refs.ptr has several pointers in it.

Directory of \\mybuilds\symsrv\msvcrt.pdb\37a8f40e2
10/05/1999  02:50p              54     file.ptr
10/05/1999  02:50p           2,039     refs.ptr

The contents of \\mybuilds\symsrv\msvcrt.pdb\37a8f40e2\refs.ptr are the following:

0000000001,ptr,\\mybuilds\symbols\x86\2137\symbols\dll\msvcrt.pdb
0000000002,ptr,\\mybuilds\symbols\x86\2137.chk\symbols\dll\msvcrt.pdb
0000000003,ptr,\\mybuilds\symbols\x86\2138\symbols\dll\msvcrt.pdb
0000000004,ptr,\\mybuilds\symbols\x86\2138.chk\symbols\dll\msvcrt.pdb
0000000005,ptr,\\mybuilds\symbols\x86\2139\symbols\dll\msvcrt.pdb
0000000006,ptr,\\mybuilds\symbols\x86\2139.chk\symbols\dll\msvcrt.pdb
0000000007,ptr,\\mybuilds\symbols\x86\2140\symbols\dll\msvcrt.pdb
0000000008,ptr,\\mybuilds\symbols\x86\2140.chk\symbols\dll\msvcrt.pdb
0000000009,ptr,\\mybuilds\symbols\x86\2136\symbols\dll\msvcrt.pdb
0000000010,ptr,\\mybuilds\symbols\x86\2136.chk\symbols\dll\msvcrt.pdb
0000000011,ptr,\\mybuilds\symbols\x86\2135\symbols\dll\msvcrt.pdb
0000000012,ptr,\\mybuilds\symbols\x86\2135.chk\symbols\dll\msvcrt.pdb
0000000013,ptr,\\mybuilds\symbols\x86\2134\symbols\dll\msvcrt.pdb
0000000014,ptr,\\mybuilds\symbols\x86\2134.chk\symbols\dll\msvcrt.pdb
0000000015,ptr,\\mybuilds\symbols\x86\2133\symbols\dll\msvcrt.pdb
0000000016,ptr,\\mybuilds\symbols\x86\2133.chk\symbols\dll\msvcrt.pdb
0000000017,ptr,\\mybuilds\symbols\x86\2132\symbols\dll\msvcrt.pdb
0000000018,ptr,\\mybuilds\symbols\x86\2132.chk\symbols\dll\msvcrt.pdb
0000000019,ptr,\\mybuilds\symbols\x86\2131\symbols\dll\msvcrt.pdb
0000000020,ptr,\\mybuilds\symbols\x86\2131.chk\symbols\dll\msvcrt.pdb
0000000021,ptr,\\mybuilds\symbols\x86\2130\symbols\dll\msvcrt.pdb
0000000022,ptr,\\mybuilds\symbols\x86\2130.chk\symbols\dll\msvcrt.pdb
0000000023,ptr,\\mybuilds\symbols\x86\2129\symbols\dll\msvcrt.pdb
0000000024,ptr,\\mybuilds\symbols\x86\2129.chk\symbols\dll\msvcrt.pdb
0000000025,ptr,\\mybuilds\symbols\x86\2128\symbols\dll\msvcrt.pdb
0000000026,ptr,\\mybuilds\symbols\x86\2128.chk\symbols\dll\msvcrt.pdb
0000000027,ptr,\\mybuilds\symbols\x86\2141\symbols\dll\msvcrt.pdb
0000000028,ptr,\\mybuilds\symbols\x86\2141.chk\symbols\dll\msvcrt.pdb
0000000029,ptr,\\mybuilds\symbols\x86\2142\symbols\dll\msvcrt.pdb
0000000030,ptr,\\mybuilds\symbols\x86\2142.chk\symbols\dll\msvcrt.pdb

This shows that the same msvcrt.pdb was used for multiple builds of symbols for Windows 2000 stored on \\mybuilds\symsrv.

Here is an example of a directory that contains a mixture of file and pointer additions:

Directory of E:\symsrv\dbghelp.dbg\38039ff439000
10/12/1999  01:54p         141,232     dbghelp.dbg
10/13/1999  04:57p              49     file.ptr
10/13/1999  04:57p             306     refs.ptr

In this case, refs.ptr has the following contents:

0000000043,file,e:\binaries\symbols\retail\dll\dbghelp.dbg
0000000044,file,f:\binaries\symbols\retail\dll\dbghelp.dbg
0000000045,file,g:\binaries\symbols\retail\dll\dbghelp.dbg
0000000046,ptr,\\foo\bin\symbols\retail\dll\dbghelp.dbg
0000000047,ptr,\\foo2\bin\symbols\retail\dll\dbghelp.dbg

Thus, transactions 43, 44, and 45 added the same file to the server, and transactions 46 and 47 added pointers. If transactions 43, 44, and 45 are deleted, then the file dbghelp.dbg will be deleted from the directory. The directory will then have the following contents:

Directory of e:\symsrv\dbghelp.dbg\38039ff439000
10/13/1999  05:01p                   49 file.ptr
10/13/1999  05:01p                 130 refs.ptr

Now file.ptr contains "\\foo2\bin\symbols\retail\dll\dbghelp.dbg", and refs.ptr contains

0000000046,ptr,\\foo\bin\symbols\retail\dll\dbghelp.dbg
0000000047,ptr,\\foo2\bin\symbols\retail\dll\dbghelp.dbg

Whenever the final entry in refs.ptr is a pointer, the file file.ptr will exist and contain the path to the associated file. Whenever the final entry in refs.ptr is a file, no file.ptr will exist in this directory. Therefore, any delete operation that removes the final entry in refs.ptr may result in file.ptr being created, deleted, or changed.


Using Other Symbol Stores

It is possible to write your own symbol store creation program, rather than using SymStore.

Since SymStore transactions are all logged in CSV-format text files, you can leverage any existing SymStore log files for use in your own database program.

If you plan to use the SymSrv program provided with Debugging Tools for Windows package, it is recommended that you use SymStore as well. Updates to these two programs will always be released together, and therefore their versions will always match.


Using SymChk

The Microsoft Symbol Checker tool (SymChk, symchk.exe) is a program that compares executable files to symbol files to verify that the correct symbols are available.

The basic syntax for SymChk is as follows:

symchk [/r] FileNames /s SymbolPath

FileNames specifies one or more program files whose symbols are needed. If FileNames is a directory and the /r flag is used, this directory is explored recursively, and SymChk will try to find symbols for all program files in this directory tree. SymbolPath specifies where SymChk is to search for symbols.

There are many more command-line optinos. For a full listing, see SymChk Command-Line Options.

The symbol path specified can include any number of local directories, UNC directories, or symbol servers. Local directories and UNC directories are not searched recursively. Only the specified directory and a subdirectory based on the executable's extension are searched. For example, the query

symchk thisdriver.sys /s g:\symbols

will search g:\mysymbols and g:\mysymbols\sys.

You can specify a symbol server by using either of the following syntaxes as part of your symbol path:

srv*DownstreamStore*\\Server\Share
srv*\\Server\Share

This is very similar to using a symbol server in the debugger's symbol path. For details on this, see Using Symbol Servers and Symbol Stores.

If a downstream store is specified, SymChk will make copies of all valid symbol files found by the symbol server and place them in the downstream store. Only symbol files that are complete matches are copied downstream.

SymChk always searches the downstream store before querying the symbol server. Therefore you should be careful about using a downstream store when someone else is maintaining the symbol store. If you run SymChk once and it finds symbol files, it will copy those to the downstream store. If you then run SymChk again after these files have been altered or deleted on the symbol store, SymChk will not notice this fact, since it will find what it is looking for on the downstream store and look no further.

Note SymChk always uses SymSrv (symsrv.dll) as its symbol server DLL. On the other hand, the debuggers can choose a symbol server DLL other than SymSrv if one is available. (SymSrv is the symbol server included in the Debugging Tools for Windows package.)

Examples

Here are some examples. The following command searches for symbols for the program myapp.exe:

e:\debuggers> symchk f:\myapp.exe /s f:\symbols\applications

SYMCHK: Myapp.exe           FAILED  - Myapp.pdb is missing

SYMCHK: FAILED files = 1
SYMCHK: PASSED + IGNORED files = 0

You can try again with a different symbol path:

e:\debuggers> symchk f:\myapp.exe /s f:\symbols\newdirectory

SYMCHK: FAILED files = 0
SYMCHK: PASSED + IGNORED files = 1

The search was successful this time. If the verbose option is not used, SymChk will only list files for which it failed to find symbols. So in this example no files were listed. You can tell that the search succeeded because there is now one file listed in the "passed" category and none in the "failed" category.

A program file is ignored if it contains no executable code. Many resource files are of this type.

If you prefer to see the file names of all program files, you can use the /v option to generate verbose output:

e:\debuggers> symchk /v f:\myapp.exe /s f:\symbols\newdirectory

SYMCHK: MyApp.exe           PASSED

SYMCHK: FAILED files = 0
SYMCHK: PASSED + IGNORED files = 1

The following command searches for a huge number of Windows symbols in a symbol server. There are a great variety of possible error messages:

e:\debuggers> symchk /r c:\windows\system32 /s srv*\\manysymbols\windows

SYMCHK: msisam11.dll         FAILED  - MSISAM11.pdb is missing
SYMCHK: msuni11.dll          FAILED  - msuni11link.pdb is missing
SYMCHK: msdxm.ocx            FAILED  - Image is split correctly, but msdxm.dbg i
s missing
SYMCHK: expsrv.dll           FAILED  - Checksum doesn't match with expsrv.DBG
SYMCHK: imeshare.dll         FAILED  - imeshare.opt.pdb is missing
SYMCHK: ir32_32.dll          FAILED  - Built with no debugging information
SYMCHK: author.dll           FAILED  - rpctest.pdb is missing
SYMCHK: msvcrt40.dll         FAILED  - Built with no debugging information
......
SYMCHK: FAILED files = 211
SYMCHK: PASSED + IGNORED files = 4809


Deferred Symbol Loading

By default, symbol information is not actually loaded when the target modules are loaded. Instead, symbols are loaded by the debugger as they are needed. This is called deferred symbol loading or lazy symbol loading.

When this option is turned off, process startup can be much slower, since all symbols will be read whenever a module is loaded.

Lazy symbol loading can be overridden by using the LD (Load Symbols) command or the .reload (Reload Module) command with the /f option. These force the specified symbols to be loaded immediately, but future symbols will still be deferred.

If the symbol path is changed, all already-loaded symbols are immediately reloaded, even if lazy symbol loading is active. See Setting Paths and Loading Files for information on how to change the symbol path.

The debugger default is for deferred symbol loading to be active. In CDB and KD, the -s command-line option will turn this option off. It can also be turned off in CDB by using the LazyLoad variable in the tools.ini file. Once the debugger is running, this option can be turned on or off by using .symopt+0x4 or .symopt-0x4, respectively.


Setting Symbol Options

A number of options are available to control how symbols are loaded and used. These options can be set through a variety of options.

The following table lists these options:

Flag | Option Name | Default
0x1 | SYMOPT_CASE_INSENSITIVE | On
0x2 | SYMOPT_UNDNAME | On
0x4 | SYMOPT_DEFERRED_LOADS | On
0x8 | SYMOPT_NO_CPP | Off
0x10 | SYMOPT_LOAD_LINES | Off in KD and CDB On in WinDbg
0x20 | SYMOPT_OMAP_FIND_NEAREST | On
0x40 | SYMOPT_LOAD_ANYTHING | Off
0x80 | SYMOPT_IGNORE_CVREC | Off
0x100 | SYMOPT_NO_UNQUALIFIED_LOADS | Off
0x200 | SYMOPT_FAIL_CRITICAL_ERRORS | On
0x400 | SYMOPT_EXACT_SYMBOLS | Off
0x800 | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS | Off
0x1000 | SYMOPT_IGNORE_NT_SYMPATH | Off
0x2000 | SYMOPT_INCLUDE_32BIT_MODULES | Off
0x4000 | SYMOPT_PUBLICS_ONLY | Off
0x8000 | SYMOPT_NO_PUBLICS | Off
0x10000 | SYMOPT_AUTO_PUBLICS | On
0x20000 | SYMOPT_NO_IMAGE_SEARCH | On
0x40000 | SYMOPT_SECURE | Off
0x80000 | SYMOPT_NO_PROMPTS | On in KD and CDB Off in WinDbg
0x80000000 | SYMOPT_DEBUG | Off

Changing the Symbol Option Settings

The .symopt (Set Symbol Options) command can be used to change or display the symbol option settings. In addition, a number of command-line parameters and commands are available to change these settings; these are listed in the individual SYMOPT_XXX sections.

You can also control all the settings at once with the -sflags command-line option. This option can be followed with a decimal number, or with a hexadecimal number prefixed by 0x. It is recommended that you use hexadecimal, since the symbol flags are aligned properly that way. Be cautious in using this method, since it sets the entire bitfield and will override all the symbol handler defaults. For example, -sflags 0x401 will not only turn on SYMOPT_EXACT_SYMBOLS and SYMOPT_CASE_INSENSITIVE, but will also turn off all the other options that normally are on by default!

The default value for the total flag bits is 0x30237 in WinDbg, and 0xB0227 in CDB and KD.

SYMOPT_CASE_INSENSITIVE

This symbol option causes all searches for symbol names to be case-insensitive.

This option is on by default. Once the debugger is running, it can be turned on or off by using .symopt+0x1 or .symopt-0x1, respectively.

SYMOPT_UNDNAME

This symbol option causes symbol names to be undecorated.

This option is on by default. Once the debugger is running, it can be turned on or off by using .symopt+0x2 or .symopt-0x2, respectively.

SYMOPT_DEFERRED_LOADS

This symbol option is called deferred symbol loading or lazy symbol loading. When it is active, symbols are not actually loaded when the target modules are loaded. Instead, symbols are loaded by the debugger as they are needed. See Deferred Symbol Loading for details.

This option is on by default. In CDB and KD, the -s command-line option will turn this option off. It can also be turned off in CDB by using the LazyLoad variable in the tools.ini file. Once the debugger is running, this option can be turned on or off by using .symopt+0x4 or .symopt-0x4, respectively.

SYMOPT_NO_CPP

This symbol option turns off C++ translation. When this symbol option is set, :: is replaced by __ in all symbols.

This option is off by default. It can be activated by using the -snc command-line option. Once the debugger is running, it can be turned on or off by using .symopt+0x8 or .symopt-0x8, respectively.

SYMOPT_LOAD_LINES

This symbol option allows line number information to be read from source files. This option must be on for source debugging to work correctly.

In KD and CDB, this option is off by default; in WinDbg, this option is on by default. In CDB and KD, the -lines command-line option will turn this option on. Once the debugger is running, it can be turned on or off by using .symopt+0x10 or .symopt-0x10, respectively. It can also be toggled on and off by using the .lines (Toggle Source Line Support) command.

SYMOPT_OMAP_FIND_NEAREST

When code has been optimized and there is no symbol at the expected location, this option causes the nearest symbol to be used instead.

This option is on by default. Once the debugger is running, it can be turned on or off by using .symopt+0x20 or .symopt-0x20, respectively.

SYMOPT_LOAD_ANYTHING

This symbol option reduces the pickiness of the symbol handler when it is attempting to match symbols.

This option is off by default. Once the debugger is running, it can be turned on or off by using .symopt+0x40 or .symopt-0x40, respectively.

SYMOPT_IGNORE_CVREC

This symbol option causes the symbol handler to ignore the CV record in the loaded image header when searching for symbols.

This option is off by default. It can be activated by using the -sicv command-line option. Once the debugger is running, it can be turned on or off by using .symopt+0x80 or .symopt-0x80, respectively.

SYMOPT_NO_UNQUALIFIED_LOADS

This symbol option disables the symbol handler's automatic loading of modules. When this option is set and the debugger attempts to match a symbol, it will only search modules which have already been loaded.

This option can be used as a defense against mistyping a symbol name. Normally, a mistyped symbol will cause the debugger to pause while it searches all unloaded symbol files. When this option is active, a mistyped symbol will not be found in the loaded modules, and then the search will terminate.

This option is off by default. It can be activated by using the -snul command-line option. Once the debugger is running, it can be turned on or off by using .symopt+0x100 or .symopt-0x100, respectively.

SYMOPT_FAIL_CRITICAL_ERRORS

This symbol option causes file access error dialog boxes to be suppressed.

If this option is off, file access errors, such as "drive not ready", encountered during symbol loading, will result in dialog boxes appearing. If this option is on, these boxes are suppressed and all access errors receive a "fail" response.

This option is on by default. It can be deactivated by using the -sdce command-line option. Once the debugger is running, it can be turned on or off by using .symopt+0x200 or .symopt-0x200, respectively.

SYMOPT_EXACT_SYMBOLS

This symbol option causes the debugger to perform a strict evaluation of all symbol files.

When this option is on, even the slightest discrepancy between the symbol files and the symbol handler's expectations will cause the symbols to be ignored.

This option is off by default. It can be activated by using the -ses command-line option. Once the debugger is running, it can be turned on or off by using .symopt+0x400 or .symopt-0x400, respectively.

The -failinc command-line option also turns on SYMOPT_EXACT_SYMBOLS. In addition, if you are debugging a user-mode minidump or a kernel-mode minidump, -failinc will prevent the debugger from loading any modules whose images can't be mapped.

SYMOPT_ALLOW_ABSOLUTE_SYMBOLS

This symbol option allows DbgHelp to read symbols that are stored at an absolute address in memory. This option is not needed in the vast majority of cases.

This option is off by default. Once the debugger is running, it can be turned on or off by using .symopt+0x800 or .symopt-0x800, respectively.

SYMOPT_IGNORE_NT_SYMPATH

This symbol option causes the debugger to ignore the environment variable settings for the symbol path and the executable image path.

This option is off by default. It can be activated by using the -sins command-line option. However, it cannot be controlled by .symopt once the debugger is running, because the environment variables are only read at startup.

SYMOPT_INCLUDE_32BIT_MODULES

This symbol option forces DbgHelp and ImageHlp to enumerate 32-bit modules on an IA-64 processor.

This option is off by default. Once the debugger is running, it can be turned on or off by using .symopt+0x2000 or .symopt-0x2000, respectively.

SYMOPT_PUBLICS_ONLY

This symbol option causes DbgHelp to ignore global, local, and scoped symbols. This emulates the behavior of DbgHelp before support for these types was added.

This option is off by default. Once the debugger is running, it can be turned on or off by using .symopt+0x4000 or .symopt-0x4000, respectively.

SYMOPT_NO_PUBLICS

This symbol option prevents DbgHelp from searching the public symbol table. This makes symbol enumeration and symbol searches much faster. If your target was built with full symbols, the global symbol table usually holds all the necessary information; in that case this option may be useful.

This option is off by default. Once the debugger is running, it can be turned on or off by using .symopt+0x8000 or .symopt-0x8000, respectively.

SYMOPT_AUTO_PUBLICS

This symbol option causes DbgHelp to search the public symbol table in a .pdb file only as a last resort. If any matches are found when searching the global symbol table, the public symbols will not be searched. This improves symbol search speed.

This option is on by default. It can be deactivated by using the -sup command-line option. Once the debugger is running, it can be turned on or off by using .symopt+0x10000 or .symopt-0x10000, respectively.

SYMOPT_NO_IMAGE_SEARCH

This symbol option prevents DbgHelp from searching the disk for a copy of the image when symbols are loaded.

This option is on by default. Once the debugger is running, it can be turned on or off by using .symopt+0x20000 or .symopt-0x20000, respectively.

SYMOPT_SECURE

(Kernel mode only) This symbol option indicates whether Secure Mode is active.

Secure Mode is off by default. It can be activated by using the -secure command-line option. If the debugger is running, is in dormant mode, and has not established any Debugging Servers, Secure Mode can be turned on by using .symopt+0x40000 or .secure (Activate Secure Mode).

Secure mode can never be turned off once it has been activated.

SYMOPT_NO_PROMPTS

This symbol option suppresses authentication dialog boxes from the proxy server. This may result in SymSrv being unable to access a symbol store on the internet.

For details, see Firewalls and Proxy Servers.

In KD and CDB, this option is on by default; in WinDbg, this option is off by default. Once the debugger is running, it can be turned on or off by using .symopt+0x80000 or .symopt-0x80000, respectively, followed by the .reload (Reload Module) command. It can also be turned on and off by using the !sym prompts off and !sym prompts extension commands, followed by the .reload (Reload Module) command.

SYMOPT_DEBUG

This symbol option turns on noisy symbol loading. This instructs the debugger to display information about its search for symbols.

The name of each symbol file will be displayed as it is loaded. If the debugger cannot load a symbol file, it will display an error message. Error messages for .pdb files will be displayed in text. Error messages for .dbg files will be in the form of an error code; these codes are explained in the winerror.h file.

If an image file is loaded solely to recover symbolic header information, this will be displayed as well.

This option is off by default. It can be activated by using the -n command-line option. Once the debugger is running, it can be turned on or off by using .symopt+0x80000000 or .symopt-0x80000000, respectively. It can also be turned on and off by using the !sym noisy and !sym quiet extension commands.


Symbol Syntax and Symbol Matching

Symbols allow you to directly manipulate tokens that are used by the program being debugged. For example, you can set a breakpoint at the function main with the command bp main, or display the integer variable MyInt with the command dd MyInt L1.

MASM Expressions and C++ Expressions

The debugger understands two different kinds of expressions: MASM expressions and C++ expressions. As far as symbols are concerned, these two forms of syntax differ as follows:

  • In MASM expressions, each symbol is interpreted as an address. Depending on what the symbol refers to, this will be the address of a global variable, local variable, function, segment, module, or any other recognized label.
  • In C++ expressions, each symbol is interpreted according to its type. Depending on what the symbol refers to, it may be interpreted as an integer, a data structure, a function pointer, or any other data type. A symbol that does not correspond to a C++ data type (such as an unmodified module name) will result in a syntax error.

For an explanation of when and how to use each type of syntax, see Evaluating Expressions.

Matching Wildcards and Ambiguous Symbols

A symbol name consists of one or more characters, but always begins with a letter, underscore (_), question mark (?), or dollar sign ($). In certain commands, the wildcard character (*) can be used as part of a symbol to match any combination of characters; you can use a question mark (?) to match any single character.

A symbol name may be qualified by a module name. An exclamation mark (!) separates the module name from the symbol (for instance, mymodule!main). If no module name is used, the symbol can still be prefixed with an exclamation mark.

If you are using MASM expression syntax, any symbol that could be interpreted as a hexadecimal number or as a register (e.g., BadFeed, ebX) should always be prefixed by an exclamation point. This makes sure the debugger recognizes it as a symbol.

Symbol names are completely case-insensitive. This means that the presence of a myInt and a MyInt in your program will not be correctly understood by the debuggers; any command that references one of these may access the other one, regardless of how the command is capitalized.

The debuggers attempt to match a symbol name in the following order:

  1. An exact match (Sym, sym, SYm).
  2. A match with a leading underscore (_Sym, _sym, _SYm).
  3. If symbol suffix matching is active, a match with a trailing A or W (SymA, symA, SYmA, or SymW, symW, SYmW).

Symbol Suffix Matching

The SS (Set Suffix) command can be used to set the symbol suffix. This instructs the debugger to automatically append "A" or "W" to any symbol name it cannot find otherwise.

Many Win32 routines exist in both ASCII and Unicode versions. These routines often have an "A" or "W" appended to the end of their names, respectively. Using a symbol suffix will aid the debugger when searching for these symbols.

Suffix matching is not active by default.


Symbol Status Abbreviations

Symbol file types and their loading status can be determined by using the LM (List Loaded Modules) command, the !lmi extension, or WinDbg's Debug | Modules menu command.

Each of these displays information about loaded modules and their symbols.

The following abbreviations are used in the displays generated by these commands:

Abbreviation | Meaning
deferred | The module has been loaded, but the debugger has not attempted to load the symbols. Symbols will be loaded when needed. See Deferred Symbol Loading for details.
# | There is a mismatch between the symbol file and the executable, either in their timestamps or in their checksums.
T | The timestamp is missing, not accessible, or equal to zero.
C | The checksum is missing, not accessible, or equal to zero.
DIA | Symbol files were loaded through Debug Interface Access (DIA).
Export | No actual symbol files were found, so symbol information was extracted from the binary file's export table.
M | There is a mismatch between the symbol file and the executable, either in their timestamps or in their checksums. However, symbol files have been loaded anyway due to the symbol option settings.
PERF | This binary contains performance-optimized code. Standard address arithmetic may not produce correct results.
Stripped | Debug information was stripped from the image file.
PDB | The symbols are in .pdb format.
COFF | The symbols are in common object file format (COFF) symbol format.


Performance-Optimized Code

Microsoft has certain techniques that it uses to re-arrange compiled and linked code so that it executes with more efficiency. These techniques optimize the component for memory hierarchies, and are based on training scenarios.

The resulting optimization reduces paging (and page faults), and increases spatial locality between code and data. It addresses a key performance bottleneck that would be introduced by poor positioning of the original code. A component that has gone through this optimization may have its code or data block within a function moved to different locations of the binary.

In modules that have been optimized by these techniques, the locations of code and data blocks will often be found at memory addresses different than the locations where they would reside after normal compilation and linking. Furthermore, functions may have been split into many non-contiguous blocks, in order that the most commonly-used code paths can be located close to each other on the same pages.

Therefore, a function (or any symbol) plus an offset will not necessarily have the same meaning it would have in non-optimized code.

Debugging Performance-Optimized Code

When debugging, you can see if a module has been performance-optimized by using the !lmi extension command on any module for which symbols have been loaded:

0:000> !lmi ntdll
Loaded Module Info: [ntdll]
         Module: ntdll
   Base Address: 77f80000
     Image Name: ntdll.dll
   Machine Type: 332 (I386)
     Time Stamp: 394193d2 Fri Jun 09 18:03:14 2000
       CheckSum: 861b1
Characteristics: 230e stripped perf
Debug Data Dirs: Type Size     VA  Pointer
                 MISC  110,     0,   76c00 [Data not mapped]
     Image Type: DBG      - Image read successfully from symbol server.
                 c:\symbols\dll\ntdll.dbg
    Symbol Type: DIA PDB  - Symbols loaded successfully from symbol server.
                 c:\symbols\dll\ntdll.pdb

In this output, notice the term perf on the "Characteristics" line. This indicates that this performance optimization has been applied to ntdll.dll.

The debugger is able to understand a function or other symbol without an offset; this allows you to set breakpoints on functions or other labels without any problem. However, the output of a dissassembly operation may be confusing, because this disassembly will reflect the changes made by the optimizer.

Since the debugger will try to stay close to the original code, you might see some amusing results. The rule of thumb when working with performance-optimized codes is simply that you cannot perform reliable address arithmetic on optimized code.

Here is an example:

kd> bl
 0 e f8640ca6     0001 (0001) tcpip!IPTransmit
 1 e f8672660     0001 (0001) tcpip!IPFragment

kd> u f864b4cb
tcpip!IPTransmit+e48:
f864b4cb f3a4             rep     movsb
f864b4cd 8b75cc           mov     esi,[ebp-0x34]
f864b4d0 8b4d10           mov     ecx,[ebp+0x10]
f864b4d3 8b7da4           mov     edi,[ebp-0x5c]
f864b4d6 8bc6             mov     eax,esi
f864b4d8 6a10             push    0x10
f864b4da 034114           add     eax,[ecx+0x14]
f864b4dd 57               push    edi

You can see from the breakpoint list that the address of IPTransmit is 0xF8640CA6.

When you unassemble a section of code within this function at 0xF864B4CB, the output indicates that this is 0xE48 bytes past the beginning of the function. However, if you subtract the base of the function from this address, the actual offset appears to be 0xA825.

What is happening is this: The debugger is indeed showing a disassembly of the binary instructions beginning at 0xF864B4CB. But instead of computing the offset by simple subtraction, the debugger displays — as best it can — the offset to the function entry as it existed in the original code before the optimizations were performed. That value is 0xE48.

On the other hand, if you try to look at IPTransmit+0xE48, you will see this:

kd> u tcpip!iptransmit+e48
tcpip!ARPTransmit+d8:
f8641aee 0856ff           or      [esi-0x1],dl
f8641af1 75fc             jnz     tcpip!ARPTransmit+0xd9 (f8641aef)
f8641af3 57               push    edi
f8641af4 e828eeffff       call    tcpip!ARPSendData (f8640921)
f8641af9 5f               pop     edi
f8641afa 5e               pop     esi
f8641afb 5b               pop     ebx
f8641afc c9               leave

What is happening here is that the debugger recognizes the symbol IPTransmit as equivalent to the address 0xF8640CA6, and the command parser performs a simple addition to find that 0xF8640CA6 + 0xE48 = 0xF8641AEE. This address is then used as the argument for the U (Unassemble) command. But once this location is analyzed, the debugger discovers that this is not IPTransmit plus an offset of 0xE48. Indeed, it is not part of this function at all. Rather, it corresponds to the function ARPTransmit plus an offset of 0xD8.

The reason this happens is that performance optimization is not reversible through address arithmetic. While the debugger can take an address and deduce its original symbol and offset, it does not have enough information to take a symbol and offset and translate it to the correct address. Consequently, disassembly is not useful in these cases.


Invalid or Missing Symbols

Invalid or missing symbols are one of the most common causes of debugger problems. When you see some sort of problem, you need to find out if you have some sort of symbol issue.

In some cases, the solution involves acquiring the correct symbol files. In other cases, you simply need to reconfigure the debugger to recognize symbol files you already have. But if you are not able to get the correct symbol files, you will need to work around this problem and debug the target in a more limited manner.

This section includes:

Verifying Symbols

Reading Symbols from Paged-Out Headers

Debugging User-Mode Processes Without Symbols


Verifying Symbols

Symbol problems can show up in a variety of ways. Perhaps a stack trace shows incorrect information or fails to identify the names of the functions in the stack. Or perhaps a debugger command failed to understand the name of a module, function, variable, structure, or data type.

If you suspect that the debugger is not loading symbols correctly, there are several steps you can take to investigate this problem.

First, use the LM (List Loaded Modules) command to display the list of loaded modules with symbol information. The most useful form of this command is the following:

0:000> lml

If you are using WinDbg, the Debug | Modules menu command will let you see this information as well.

Pay particular attention to any notes or abbreviations you may see in these displays. For an interpretation of these, see Symbol Status Abbreviations.

If you don't see the proper symbol files, the first thing to do is to check the symbol path:

0:000> .sympath
Current Symbol Path is: d:\MyInstallation\i386\symbols\retail

If your symbol path is wrong, fix it. If you are using the kernel debugger make sure your local %WINDIR% is not on your symbol path.

Then reload symbols using the .reload (Reload Module) command:

0:000> .reload ModuleName

If your symbol path is correct, you should activate noisy mode so you can see what symbol files dbghelp is loading. Then reload your module. See Setting Symbol Options for information on how to activate noisy mode.

Here is an example of a "noisy" reload of the Windows symbols:

kd> !sym noisy
kd> .reload nt
 1: Kernel Version 2081 MP Checked
 2: Kernel base = 0x80400000 PsLoadedModuleList = 0x80506fa0
 3: DBGHELP: FindExecutableImageEx-> Looking for D:\MyInstallation\i386\ntkrnlmp.exe...mismatched timestamp
 4: DBGHELP: No image file available for ntkrnlmp.exe
 5: DBGHELP: FindDebugInfoFileEx-> Looking for
 6: d:\MyInstallation\i386\symbols\retail\symbols\exe\ntkrnlmp.dbg... no file
 7: DBGHELP: FindDebugInfoFileEx-> Looking for
 8: d:\MyInstallation\i386\symbols\retail\symbols\exe\ntkrnlmp.pdb... no file
 9: DBGHELP: FindDebugInfoFileEx-> Looking for d:\MyInstallation\i386\symbols\retail\exe\ntkrnlmp.dbg... OK
10: DBGHELP: LocatePDB-> Looking for d:\MyInstallation\i386\symbols\retail\exe\ntkrnlmp.pdb... OK
11: *** WARNING: symbols checksum and timestamp is wrong 0x0036a4ea 0x00361a83 for ntkrnlmp.exe

The symbol handler first looks for an image that matches the module it is trying to load (lines three and four). The image itself is not always necessary, but if an incorrect one is present, the symbol handler will often fail. These lines show that the debugger found an image at D:\MyInstallation\i386\ntkrnlmp.exe, but the time-date stamp didn't match. Because the time-date stamp didn't match, the search continues. Next, the debugger looks for a .dbg file and .pdb file that match the loaded image. These are on lines from 6 through 10. Line 11 indicates that even though symbols were loaded, the time-date stamp for the image did not match (that is, the symbols were wrong).

If the symbol-search encountered a catastrophic failure, you would see a message of the form:

ImgHlpFindDebugInfo(00000000, module.dll, c:\foo;c:\bar, 0823345, 0) failed

This could be caused by items such as file system failures, network errors, and corrupt .dbg files.

Diagnosing Symbol Loading Errors

When in noisy mode, the debugger may print out error codes when it cannot load a symbol file. The error codes for .dbg files are listed in winerror.h. The .pdb error codes come from another source and the most common errors are printed in plain English text.

Some common error codes for .dbg files from winerror.h are:

0xB
ERROR_BAD_FORMAT
0x3
ERROR_PATH_NOT_FOUND
0x35
ERROR_BAD_NETPATH

It's possible that the symbol file cannot be loaded because of a networking error. If you see ERROR_BAD_FORMAT or ERROR_BAD_NETPATH and you are loading symbols from another machine on the network, try copying the symbol file to your host computer and put its path in your symbol path. Then try to reload the symbols.

Verifying Your Search Path and Symbols

Let "c:\foo;c:\bar" represent your symbol path. Where should you look for debug information?

In cases where the binary has been stripped of debug information, such as the free builds of Windows®, first look for a .dbg file in the following locations:

c:\foo\symbols\exe\ntoskrnl.dbg
c:\bar\symbols\exe\ntoskrnl.dbg
c:\foo\exe\ntoskrnl.dbg
c:\bar\exe\ntoskrnl.dbg
c:\foo\ntoskrnl.dbg
c:\bar\ntoskrnl.dbg
current-working-directory\ntoskrnl.dbg

Next, look for a .pdb file in the following locations:

c:\foo\symbols\exe\ntoskrnl.pdb
c:\foo\exe\ntoskrnl.pdb
c:\foo\ntoskrnl.pdb
c:\bar\symbols\exe\ntoskrnl.pdb
c:\bar\exe\ntoskrnl.pdb
c:\bar\ntoskrnl.pdb
current-working-directory\ntoskrnl.pdb

Note that in the search for the .dbg file, the debugger interleaves searching through the foo and bar directories, but in the .pdb search it does not.

Windows XP and Windows .NET Server 2003 do not use any .dbg symbol files. See Symbol Files: Overview for details.

Mismatched Builds

One of the most common problems in debugging failures on a machine that is often updated is mismatched symbols from different builds. Three common causes of this problem are: pointing at symbols for wrong build, using a privately built binary without the corresponding symbols, and using the uniprocessor hardware abstraction level (HAL) and kernel symbols on a multiprocessor machine. The first two are simply a matter of matching your binaries and symbols; the third can be corrected by renaming your hal*.dbg and ntkrnlmp.dbg to hal.dbg and ntoskrnl.dbg.

To find out what build of Windows is installed on the target computer, use the vertarget (Show Target Computer Version) command:

kd> vertarget
Windows XP Kernel Version 2505 UP Free x86 compatible
Built by: 2505.main.010626-1514
Kernel base = 0x804d0000 PsLoadedModuleList = 0x80548748
Debug session time: Mon Jul 02 14:41:11 2001
System Uptime: 0 days 0:04:53

Testing the Symbols

Testing the symbols is more difficult. It involves verifying a stack trace on the debugger and seeing if the debug output is correct. Here's one example to try:

kd> u videoprt!videoportfindadapter2
Loading symbols for 0xf2860000     videoprt.sys ->   videoprt.sys

VIDEOPRT!VideoPortFindAdapter2:
f2856f42 55               push    ebp
f2856f43 8bec             mov     ebp,esp
f2856f45 81ecb8010000     sub     esp,0x1b8
f2856f4b 8b4518           mov     eax,[ebp+0x18]
f2856f4e 53               push    ebx
f2856f4f 8365f400         and     dword ptr [ebp-0xc],0x
f2856f53 8065ff00         and     byte ptr [ebp-0x1],0x0
f2856f57 56               push    esi

The u command unassembles the videoportfindadapter string in videoprt.sys. The symbols are correct on the debugger because common stack commands like push and mov show up on the stack. Most functions begin with an add, sub, or push operation using either the base pointer (ebp) or the stack pointer (esp).

It's usually obvious when the symbols aren't working correctly. Glintmp.sys doesn't have symbols in this example because a function isn't listed next to Glintmp:

kd> kb
Loading symbols for 0xf28d0000     videoprt.sys ->   videoprt.sys
Loading symbols for 0xf9cdd000      glintmp.sys ->   glintmp.sys
*** ERROR: Symbols could not be loaded for glintmp.sys
ChildEBP RetAddr  Args to Child
f29bf1b0 8045b5fa 00000001 0000a100 00000030 ntoskrnl!RtlpBreakWithStatusInstruction
f29bf1b0 8044904e 00000001 0000a100 00000030 ntoskrnl!KeUpdateSystemTime+0x13e
f29bf234 f28d1955 f9b7d000 ffafb2dc f9b7d000 ntoskrnl!READ_REGISTER_ULONG+0x6
f29bf248 f9cde411 f9b7d000 f29bf2b0 f9ba0060 VIDEOPRT!VideoPortReadRegisterUlong+0x27
00000002 00000000 00000000 00000000 00000000 glintMP+0x1411 [No function listed.]

The wrong build symbols were loaded for this stack trace. Notice how there are no functions listed for the first two calls. This stack trace looks like a problem with win32k.sys drawing rectangles:

1: kd>
1: kd> kb                      [Local        9:50 AM]
Loading symbols for 0xf22b0000       agpcpq.sys ->   agpcpq.sys
*** WARNING: symbols checksum is wrong 0x0000735a 0x00000000 for agpcpq.sys
*** ERROR: Symbols could not be loaded for agpcpq.sys
Loading symbols for 0xa0000000       win32k.sys ->   win32k.sys
*** WARNING: symbols checksum is wrong 0x00191a41 0x001995a9 for win32k.sys
ChildEBP RetAddr  Args to Child
be682b18 f22b372b 82707128 f21c1ffc 826a70f8 agpCPQ+0x125b [No function listed.]
be682b4c a0140dd4 826a72f0 e11410a8 a0139605 agpCPQ+0x372b [No function listed.]
be682b80 a00f5646 e1145100 e1cee560 e1cee560 win32k!vPatCpyRect1_6x6+0x20b
00000001 00000000 00000000 00000000 00000000 win32k!RemoteRedrawRectangle+0x32

Here's the correct stack trace. The problem is really with AGP440.sys. The first item appearing on a stack trace is usually at fault. Notice that the win32k.sys rectangle error is gone:

1: kd> kb                      [Local        9:49 AM]
ChildEBP RetAddr  Args to Child
be682b18 f22b372b 82707128 f21c1ffc 826a70f8 agpCPQ!AgpReleaseMemory+0x88
be682b30 f20a385c 82703638 e183ec68 00000000 agpCPQ!AgpInterfaceReleaseMemory+0x8b
be682b4c a0140dd4 826a72f0 e11410a8 a0139605 VIDEOPRT!AgpReleasePhysical+0x44
be682b58 a0139605 e1cee560 e11410a8 a00e5f0a win32k!OsAGPFree+0x14
be682b64 a00e5f0a e1cee560 e11410a8 e1cee560 win32k!AGPFree+0xd
be682b80 a00f5646 e1145100 e1cee560 e1cee560 win32k!HeapVidMemFini+0x49
be682b9c a00f5c20 e1cee008 e1cee008 be682c0c win32k!vDdDisableDriver+0x3a
be682bac a00da510 e1cee008 00000000 be682c0c win32k!vDdDisableDirectDraw+0x2d
be682bc4 a00da787 00000000 e1843df8 e1843de8 win32k!PDEVOBJ__vDisableSurface+0x27
be682bec a00d59fb 00000000 e1843de8 00000000 win32k!PDEVOBJ__vUnreferencePdev+0x204
be682c04 a00d7421 e1cee008 82566a98 00000001 win32k!DrvDestroyMDEV+0x30
be682ce0 a00a9e7f e1843e10 e184a008 00000000 win32k!DrvChangeDisplaySettings+0x8b3
be682d20 a008b543 00000000 00000000 00000000 win32k!xxxUserChangeDisplaySettings+0x106
be682d48 8045d119 00000000 00000000 00000000 win32k!NtUserChangeDisplaySettings+0x48
be682d48 77e63660 00000000 00000000 00000000 ntkrnlmp!KiSystemService+0xc9

Useful Commands and Extensions

The following commands and extensions may be useful in tracking down symbol problems:

LM (List Loaded Modules)
Lists all modules and gives the loading status of all symbols in these modules.
!dh image-header-base
Displays header information for a loaded image beginning at image-header-base.
.reload /n
Reloads all kernel symbols.
.reload [image-name]
(CDB or WinDbg only) Reloads symbols for the image image-name. If no image-name is specified, reloads symbols for all images. (It is necessary to reload symbols after the symbol path has been changed.)
!sym noisy
Turns on verbose mode for symbol loads. This can be used to get information on the module loads. See Setting Symbol Options for details.
.sympath [new-symbol-path]
Sets a new symbol path, or displays the current symbol path. See Setting Paths and Loading Files for details.

If the kernel symbols are correct, but you aren't getting a complete stack, the following commands may also be useful:

X *!
This will list the modules which currently have symbols loaded. This is useful if the kernel symbols are correct.
.reload /user
This will attempt to reload all user-mode symbols. This is needed while performing kernel debugging if symbols were loaded while one process was running, and a break later occurred in another process. In this case, the user-mode symbols from the new process will not be loaded unless this command is executed.
X wdmaud!*start*
This will list only the symbols in the wdmaud module whose names contain the "start" string. This has the advantage that it forces the reloading of all the symbols in wdmaud, but only displays those with "start" in them. (This means a shorter listing, but since there are always some symbols with "start" in them, there will be some verification that the load has taken place.)

One other useful technique for verifying symbols is unassembling code. Most functions begin with an add, sub, or push operation using either the base pointer (ebp) or the stack pointer (esp or sp). Try unassembling (U <funct>) some of the functions on the stack (from offset zero) to verify the symbols.

Network and Port Problems

Problems will occur with the symbols files and while connecting to the debugger. Here are few things to keep in mind if you encounter problems:

  • Determine which COM port the debug cable is connected to on the test system.
  • Check the boot.ini settings of the test system. Look for the /debug switch and check the baud rate and COM port settings.
  • Network problems can interfere with debugging if the symbols files are accessed through the network.
  • .dll and .sys files with the same name (for example – mga64.sys and mga64.dll) will confuse the debugger if they aren't separated into the proper directories of the symbol tree.
  • The kernel debugger doesn't always like replacing the build symbol files with private symbol files. Double check the symbol path and do a .reload <filename> on the misbehaving symbol. The !dlls command is sometimes useful.

Questions and Misconceptions

Q: I've successfully loaded symbols, but the stack seems to be wrong. Is the debugger broken?

A: Not necessarily. The most likely cause of your problem is that you've got incorrect symbols. Go through the steps outlined in this section to determine whether you've loaded valid symbols or not. Do not assume that because some things work you have valid symbols. For example, you very well may be able to execute dd nt!ntbuildnumber or u nt!KeInitializeProcess with incorrect symbols. Verify that they are correct using the procedures outlined above.

Q: Will the debugger still work with incorrect symbols?

A: Yes and no. Often you can get away with symbols that don't strictly match. For example, symbols from a previous Windows® build will often work in certain cases, but there is no rule as to when this will work and when it will not.

Q: I'm stopped in the kernel debugger and I want to view symbols for my user-mode process. Can I do it?

A: Mostly. The support for this scenario is poor because the kernel debugger doesn't keep enough information around to track the module loads for each process, but there's a reasonable workaround. To load symbols for a user-mode module, execute a .reload -user command. This will load the user-mode modules for the current context.

Q: What does the following message mean?

*** WARNING: symbols checksum and timestamp is wrong 0x0036d6bf 0x0036ab55 for ntkrnlmp.exe

A: It means your symbols for ntkrnlmp.exe are wrong.


Reading Symbols from Paged-Out Headers

The kernel debugger must read the header for each loaded module's image in order to know which symbols correspond to that module.

If a module's header is paged out to disk, the debugger will not load symbols for this module. If this happens with a module that is essential to the debugging process, it can be a critical problem.

The following procedure can be used to solve this problem.

To acquire symbols for paged-out headers

  1. Make a second copy of the kernel itself. It is probably easiest to put this on a network share.
  2. Append the root directory of this share to the symbol path. See Setting Paths and Loading Files for the ways to change the symbol path.
  3. Use the .reload (Reload Module) command.
  4. Use the !sym noisy extension command to see more verbose output. If this is used, you will be able to see which symbols are loaded from the module images on the target computer, and which are loaded from the copy of the kernel modules.

This technique must be used with care, since the debugger has no way of verifying whether the file copies actually match the originals. So it is crucial that the version of Windows used on the network share matches the version used on the target computer.

This technique is only used for kernel-mode debugging. The operating system is capable of paging in any headers required during user-mode debugging (unless the disk holding the paging file is dismounted or otherwise inaccessible).

Here is an example of this technique being used:

kd> .reload
Connected to Windows XP 2268 x86 compatible target, ptr64 FALSE
Loading Kernel Symbols
..........Unable to read image header for dmload.sys at fe0be000 - NTSTATUS 0xC0000001
..........Unable to read image header for dmboot.sys at fda93000 - NTSTATUS 0xC0000001
.....................................Unable to read image header for fdc.sys at fdfc2000 - NTSTATUS 0xC0000001
...Unable to read image header for flpydisk.sys at fde4a000 - NTSTATUS 0xC0000001
.Unable to read image header for Fs_Rec.SYS at fe0c8000 - NTSTATUS 0xC0000001
.Unable to read image header for Null.SYS at fe2c4000 - NTSTATUS 0xC0000001
...................Unable to read image header for win32k.sys at a0000000 - NTSTATUS 0xC0000001
..Unable to read image header for dxg.sys at a0194000 - NTSTATUS 0xC0000001
.......Unable to read image header for ati2draa.dll at a01a4000 - NTSTATUS 0xC0000001
..Unable to read image header for ParVdm.SYS at fe116000 - NTSTATUS 0xC0000001
.......
Loading unloaded module list
..............
Loading User Symbols
Unable to retrieve the PEB address.  This is usually caused
by being in the wrong process context or by paging

Notice that many images have inaccessible headers. Check the symbols from one of these files (in this example, fs_rec.sys):

kd> x fs_rec!*
*** ERROR: Module load completed but symbols could not be loaded for fs_rec.sys

These headers are apparently paged out. So you need to add the proper images to the symbol path:

kd> .sympath+ \\myserver\myshare\symbols\x86fre\symbols
Symbol search path is: symsrv*symsrv.dll*\\symbols\symbols;\\myserver\myshare\symbols\x86fre\symbols

kd> .reload
Connected to Windows XP 2268 x86 compatible target, ptr64 FALSE
Loading Kernel Symbols
..........Unable to read image header for dmload.sys at fe0be000 - NTSTATUS 0xC0000001
..........Unable to read image header for dmboot.sys at fda93000 - NTSTATUS 0xC0000001
.....................................Unable to read image header for fdc.sys at fdfc2000 - NTSTATUS 0xC0000001
...Unable to read image header for flpydisk.sys at fde4a000 - NTSTATUS 0xC0000001
.Unable to read image header for Fs_Rec.SYS at fe0c8000 - NTSTATUS 0xC0000001
.Unable to read image header for Null.SYS at fe2c4000 - NTSTATUS 0xC0000001
...................Unable to read image header for win32k.sys at a0000000 - NTSTATUS 0xC0000001
..Unable to read image header for dxg.sys at a0194000 - NTSTATUS 0xC0000001
.......Unable to read image header for ati2draa.dll at a01a4000 - NTSTATUS 0xC0000001
..Unable to read image header for ParVdm.SYS at fe116000 - NTSTATUS 0xC0000001
.......
Loading unloaded module list
..............
Loading User Symbols
Unable to retrieve the PEB address.  This is usually caused
by being in the wrong process context or by paging

The same warnings have appeared, but the symbols themselves are now accessible:

kd> x fs_Rec!*
fe0c8358  Fs_Rec!_imp___allmul
fe0c8310  Fs_Rec!_imp__IoCreateDevice
fe0c835c  Fs_Rec!_imp___allshr
........
fe0c8360  Fs_Rec!ntoskrnl_NULL_THUNK_DATA
fe0c832c  Fs_Rec!_imp__KeSetEvent
fe0c9570  Fs_Rec!_NULL_IMPORT_DESCRIPTOR


Debugging User-Mode Processes Without Symbols

It is important to have symbols on the faulting machine before starting the debugger for a user-mode failure. However, sometimes the debugger is started without symbols. If the problem is easily reproducible, you can just copy symbols and rerun. If, however, the problem may not occur again, some information can be gleaned from the failure:

  1. To figure out what the addresses mean, you'll need a computer which matches the one with the error. It should have the same platform (x86, IA-64, or AMD64) and be loaded with the same version of Windows®.
  2. When you have the computer configured, copy the user-mode symbols and the binaries you want to debug onto the new machine.
  3. Start CDB or WinDbg on the symbol-less machine.
  4. If you don't know which application failed on the symbol-less machine, issue an | (Process Status) command. If that doesn't give you a name, break into KD on the symbol-less machine and do a !process 0 0, looking for the process ID given by the CDB command.
  5. When you have the two debuggers set up — one with symbols which hasn't hit the error, and one which has hit the error but is without symbols — issue a k (Display Stack Backtrace) command on the symbol-less machine.
  6. On the machine with symbols, issue a u (Unassemble) command for each address given on the symbol-less stack. This will give you the stack trace for the error on the symbol-less machine.
  7. By looking at a stack trace you can see the module and function names involved in the call.


Bug Checks (Blue Screens)

This section includes:

Blue Screen Data

General Troubleshooting Tips

Bug Check Code Reference


Blue Screen Data

When Microsoft® Windows® encounters a condition that compromises safe system operation, the system halts. This condition is called a bug check. It is also commonly referred to as a system crash, a kernel error, or a Stop error.

If crash dumps are enabled on the system, a crash dump file is created.

If a kernel debugger is attached and active, the system causes a break so the debugger can be used to investigate the crash.

If no debugger is attached, a blue text screen appears with information about the error. This screen is called a blue screen, a bug check screen, or a Stop screen.

The exact appearance of the blue screen depends on the cause of the error. The following is an example of one possible blue screen:

STOP: 0x00000079 (0x00000002, 0x00000001, 0x00000002, 0x00000000)

Mismatched kernel and hal image.

Beginning dump of physical memory
Physical memory dump complete. Contact your system administrator or
technical support group.

On the other hand, some blue screens look like this:

STOP: c000021a {Fatal System Error}

The Windows Logon Process system process terminated unexpectedly with
a status of 0x00000001 (0x00000000 0x00000000).
The system has been shut down.

The hexadecimal number following the word "STOP" is called the bug check code or Stop code. This is the most important item on the screen.

Each bug check code has four associated parameters. In the first blue screen shown here, all four parameters are displayed after the bug check code. However, in the second kind of blue screen, these parameters have been rearranged within the explanatory text. Regardless of the amount of rearrangement, they will always appear sequentially. If fewer than four parameters appear, the remaining parameters can be assumed to be zero.

The remainder of the text on the blue screen gives additional information. For some bug checks, this may be an explanation of what happened or suggestions for how you can deal with the problem. If a kernel-mode dump file has been written, this will usually be indicated as well.

Under some conditions, Windows will display only the first line of the blue screen. This can occur if the vital services needed for the display have been affected by the error.

Bug Check Symbolic Names

Each bug check code also has an associated symbolic name. These names usually do not appear on the blue screen. In these examples, the first screen shows bug check 0x79 (MISMATCHED_HAL), while the second shows bug check 0xC000021A (STATUS_SYSTEM_PROCESS_TERMINATED).

To deliberately cause a bug check from a kernel-mode driver, you need to pass the bug check's symbolic name to the KeBugCheck or KeBugCheckEx function. This should only be done in circumstances where no other option is available. For more details on these functions, see the Windows DDK.

Reading Bug Check Information from the Debugger

If a debugger is attached, a bug check will cause the target computer to break into the debugger. In this case, the blue screen might not appear, or might appear with less text; the full details on this crash will be sent to the debugger and appear in the debugger window. To see this information a second time, use the .bugcheck (Display Bug Check Data) command.

The debugger will also display additional information regarding the current problem. To see this information a second time, use the !analyze extension command.


General Troubleshooting Tips

When a bug check occurs as a result of code you have written, you should use the kernel debugger to analyze the problem, and then fix the bugs in your code. See the individual bug check code in the Bug Check Code Reference section for more details.

However, you might also encounter bug checks that are not caused by your own code. In this case, you probably will not be able to fix the actual cause of the problem, so your goal should be to work around the problem, and if possible isolate and remove the hardware or software component that is at fault.

Many problems can be resolved through basic troubleshooting procedures, such as verifying instructions, reinstalling key components, and verifying file dates. Also, diagnostic tools such as Winmsd, Network General Sniffer, and Microsoft® Windows® Resource Kit Tools Help might isolate and resolve these issues.

For general troubleshooting of Windows bug check codes, follow these suggestions:

  • If you recently added hardware to the system, try removing or replacing it. Or check with the manufacturer to see if any patches are available.
  • You can try running the hardware diagnostics supplied by the system manufacturer.
  • Check with the manufacturer to see if an updated system BIOS or firmware is available.
  • Make sure that any expansion board is properly seated and all cables are completely connected.
  • Confirm that any new hardware is listed on the Windows Hardware Compatibility List (HCL).
  • If new device drivers or system services have been added recently, try removing or updating them.

    Important Use Safe Mode when removing or disabling components. Using Safe Mode loads only the minimum required drivers and system services during the Windows startup. To enter Safe Mode, restart your computer, and press F8 at the character-mode menu that displays the operating system choices. At the resulting Windows Advanced Options menu, choose Safe Mode.

  • Run a virus detection program. Viruses can infect all types of hard disks formatted for Windows, and resulting disk corruption can generate system bug check codes. Make sure the virus detection program checks the Master Boot Record for infections.
  • Verify that the system has the latest Service Pack installed. To detect which Service Pack, if any, is installed on your system, click Start, click Run, type winver, and then press ENTER. The About Windows dialog box displays the Windows version number and the version number of the Service Pack, if one has been installed.
  • Disable BIOS memory options such as caching or shadowing.
  • Check the System Log and Application Log in Event Viewer to see if any additional error messages have been logged recently. These might pinpoint the cause of the error.

Kernel debugging is especially useful when other troubleshooting techniques fail, or for a recurring problem. Remember to capture the exact text in the bug check information section of the error message. To isolate a complex problem and develop a viable workaround or a program replacement, you must record the exact actions that lead to the failure.


Bug Check Code Reference

This section contains descriptions of the common bug checks, including the parameters passed to the blue screen.

It also describes how you can diagnose the fault which led to the bug check, and possible ways to deal with the error.

If a specific bug check code does not appear in this reference, use the !analyze extension command (in kernel mode) with the following syntax:

kd> !analyze -show Code

This will display information about the specified bug check code. If your default radix is not 16, you should prefix Code with "0x".


Bug Check 0x1: APC_INDEX_MISMATCH

The APC_INDEX_MISMATCH bug check has a value of 0x00000001. This indicates that there has been a mismatch in the APC state index.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The address of the system function (system call)
2 | The value of Thread->ApcStateIndex << 8 | Previous ApcStateIndex
3 | The value of Thread->KernelApcDisable
4 | The value of the previous KernelApcDisable

Cause

The most common cause of this bug check is when a file system has a mismatched sequence of KeEnterCriticalRegion calls and KeLeaveCriticalRegion calls.

Comments

This is a kernel internal error which can occur only on a checked build. This error occurs on exit from a system call.


Bug Check 0x2: DEVICE_QUEUE_NOT_BUSY

The DEVICE_QUEUE_NOT_BUSY bug check has a value of 0x00000002.

This bug check appears very infrequently.


Bug Check 0x3: INVALID_AFFINITY_SET

The INVALID_AFFINITY_SET bug check has a value of 0x00000003.

This bug check appears very infrequently.


Bug Check 0x4: INVALID_DATA_ACCESS_TRAP

The INVALID_DATA_ACCESS_TRAP bug check has a value of 0x00000004.

This bug check appears very infrequently.


Bug Check 0x5: INVALID_PROCESS_ATTACH_ATTEMPT

The INVALID_PROCESS_ATTACH_ATTEMPT bug check has a value of 0x00000005.

This bug check appears very infrequently.


Bug Check 0x6: INVALID_PROCESS_DETACH_ATTEMPT

The INVALID_PROCESS_DETACH_ATTEMPT bug check has a value of 0x00000006.

This bug check appears very infrequently.


Bug Check 0x7: INVALID_SOFTWARE_INTERRUPT

The INVALID_SOFTWARE_INTERRUPT bug check has a value of 0x00000007.

This bug check appears very infrequently.


Bug Check 0x8: IRQL_NOT_DISPATCH_LEVEL

The IRQL_NOT_DISPATCH_LEVEL bug check has a value of 0x00000008.

This bug check appears very infrequently.


Bug Check 0x9: IRQL_NOT_GREATER_OR_EQUAL

The IRQL_NOT_GREATER_OR_EQUAL bug check has a value of 0x00000009.

This bug check appears very infrequently.


Bug Check 0xA: IRQL_NOT_LESS_OR_EQUAL

The IRQL_NOT_LESS_OR_EQUAL bug check has a value of 0x0000000A. This indicates that Windows or a kernel-mode driver accessed paged memory at DISPATCH_LEVEL or above.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL at time of reference
3 | 0: Read 1: Write
4 | Address which referenced memory

Cause

This bug check is issued if paged memory (or invalid memory) is accessed when the IRQL is too high.

The error that generates this bug check usually occurs after the installation of a faulty device driver, system service, or BIOS.

If you encounter bug check 0xA while upgrading to a later version of Microsoft® Windows®, this error might be caused by a device driver, a system service, a virus scanner, or a backup tool that is incompatible with the new version.

Resolving the Problem

If a kernel debugger is available, obtain a stack trace.

To resolve an error caused by a faulty device driver, system service, or BIOS:

  1. Restart your computer.
  2. Press F8 at the character-based menu that displays the operating system choices.
  3. Select the Last Known Good Configuration option from the Windows Advanced Options menu. This option is most effective when only one driver or service is added at a time.

To resolve an error caused by an incompatible device driver, system service, virus scanner, or backup tool:

  1. Check the System Log in Event Viewer for error messages that might identify the device or driver that caused the error.
  2. Try disabling memory caching of the BIOS.
  3. Run the hardware diagnostics supplied by the system manufacturer, especially the memory scanner. For details on these procedures, see the owner's manual for your computer.
  4. Make sure the latest Service Pack is installed.
  5. If your system has small computer system interface (SCSI) adapters, contact the adapter manufacturer to obtain updated Windows drivers. Try disabling sync negotiation in the SCSI BIOS, checking the cabling and the SCSI IDs of each device, and confirming proper termination.
  6. For integrated device electronics (IDE) devices, define the onboard IDE port as Primary only. Also, check each IDE device for the proper master/slave/stand-alone setting. Try removing all IDE devices except for hard disks.

If the message appears during an installation of Windows, make sure that the computer and all installed peripherals are listed on the Microsoft Windows Hardware Compatibility List (HCL).

Here is a debugging example:

kd> .bugcheck       [Lists bugcheck data.]
Bugcheck code 0000000a
Arguments 00000000 0000001c 00000000 00000000

kd> kb       [Lists the stack trace.]
ChildEBP RetAddr  Args to Child
8013ed5c 801263ba 00000000 00000000 e12ab000 NT!_DbgBreakPoint
8013eecc 801389ee 0000000a 00000000 0000001c NT!_KeBugCheckEx+0x194
8013eecc 00000000 0000000a 00000000 0000001c NT!_KiTrap0E+0x256
8013ed5c 801263ba 00000000 00000000 e12ab000
8013ef64 00000246 fe551aa1 ff690268 00000002 NT!_KeBugCheckEx+0x194

kd> kv       [Lists the trap frames.]
ChildEBP RetAddr  Args to Child
8013ed5c 801263ba 00000000 00000000 e12ab000 NT!_DbgBreakPoint (FPO: [0,0,0])
8013eecc 801389ee 0000000a 00000000 0000001c NT!_KeBugCheckEx+0x194
8013eecc 00000000 0000000a 00000000 0000001c NT!_KiTrap0E+0x256 (FPO: [0,0] TrapFrame @ 8013eee8)
8013ed5c 801263ba 00000000 00000000 e12ab000
8013ef64 00000246 fe551aa1 ff690268 00000002 NT!_KeBugCheckEx+0x194

kd> .trap 8013eee8       [Gets the registers for the trap frame at the time of the fault.]
eax=dec80201 ebx=ffdff420 ecx=8013c71c edx=000003f8 esi=00000000 edi=87038e10
eip=00000000 esp=8013ef5c ebp=8013ef64 iopl=0         nv up ei pl nz na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010202
ErrCode = 00000000
00000000 ???????????????       [The current instruction pointer is NULL.]

kd> kb       [Gives the stack trace before the fault.]
ChildEBP RetAddr  Args to Child
8013ef68 fe551aa1 ff690268 00000002 fe5620d2 NT!_DbgBreakPoint
8013ef74 fe5620d2 fe5620da ff690268 80404690
NDIS!_EthFilterIndicateReceiveComplete+0x31
8013ef64 00000246 fe551aa1 ff690268 00000002 elnkii!_ElnkiiRcvInterruptDpc+0x1d0

Comments

Before upgrading to a new version of Windows, remove all third-party device drivers and system services, and disable any virus scanners. Contact the software manufacturers to obtain updates of these third-party tools.


Bug Check 0xB: NO_EXCEPTION_HANDLING_SUPPORT

The NO_EXCEPTION_HANDLING_SUPPORT bug check has a value of 0x0000000B.

This bug check appears very infrequently.


Bug Check 0xC: MAXIMUM_WAIT_OBJECTS_EXCEEDED

The MAXIMUM_WAIT_OBJECTS_EXCEEDED bug check has a value of 0x0000000C. This indicates that the current thread exceeded the permitted number of wait objects.

Parameters

None

Cause

This bug check results from the improper use of KeWaitForMultipleObjects.

The caller may pass a pointer to a buffer in this routine's WaitBlockArray parameter. The system will use this buffer to keep track of wait objects.

If a buffer is supplied, the Count parameter may not exceed MAXIMUM_WAIT_OBJECTS. If no buffer is supplied, the Count parameter may not exceed THREAD_WAIT_OBJECTS.

If the value of Count exceeds the allowable value, this bug check is issued.

For more details on KeWaitForMultipleObjects, see the Windows DDK.


Bug Check 0xD: MUTEX_LEVEL_NUMBER_VIOLATION

The MUTEX_LEVEL_NUMBER_VIOLATION bug check has a value of 0x0000000D.

This bug check appears very infrequently.


Bug Check 0xE: NO_USER_MODE_CONTEXT

The NO_USER_MODE_CONTEXT bug check has a value of 0x0000000E.

This bug check appears very infrequently.


Bug Check 0xF: SPIN_LOCK_ALREADY_OWNED

The SPIN_LOCK_ALREADY_OWNED bug check has a value of 0x0000000F.

This bug check appears very infrequently.


Bug Check 0x10: SPIN_LOCK_NOT_OWNED

The SPIN_LOCK_NOT_OWNED bug check has a value of 0x00000010.

This bug check appears very infrequently.


Bug Check 0x11: THREAD_NOT_MUTEX_OWNER

The THREAD_NOT_MUTEX_OWNER bug check has a value of 0x00000011.

This bug check appears very infrequently.


Bug Check 0x12: TRAP_CAUSE_UNKNOWN

The TRAP_CAUSE_UNKNOWN bug check has a value of 0x00000012. This indicates that an unknown exception has occurred.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The unexpected interrupt
2 | The unknown floating point exception
3 | The enabled and asserted status bits. See the processor definition for details.
4 | Reserved


Bug Check 0x13: EMPTY_THREAD_REAPER_LIST

The EMPTY_THREAD_REAPER_LIST bug check has a value of 0x00000013.

This bug check appears very infrequently.


Bug Check 0x14: CREATE_DELETE_LOCK_NOT_LOCKED

The CREATE_DELETE_LOCK_NOT_LOCKED bug check has a value of 0x00000014.

This bug check appears very infrequently.


Bug Check 0x15: LAST_CHANCE_CALLED_FROM_KMODE

The LAST_CHANCE_CALLED_FROM_KMODE bug check has a value of 0x00000015.

This bug check appears very infrequently.


Bug Check 0x16: CID_HANDLE_CREATION

The CID_HANDLE_CREATION bug check has a value of 0x00000016.

This bug check appears very infrequently.


Bug Check 0x17: CID_HANDLE_DELETION

The CID_HANDLE_DELETION bug check has a value of 0x00000017.

This bug check appears very infrequently.


Bug Check 0x18: REFERENCE_BY_POINTER

The REFERENCE_BY_POINTER bug check has a value of 0x00000018.

This bug check appears very infrequently.


Bug Check 0x19: BAD_POOL_HEADER

The BAD_POOL_HEADER bug check has a value of 0x00000019. This indicates that a pool header is corrupt.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of violation. The meaning of the other parameters depends on the value of Parameter 1.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x3 | The pool entry being checked | The read-back flink freelist value | The read-back blink freelist value | The pool freelist is corrupt. (In a healthy list, the values of Parameters 2, 3, and 4 should be identical.)
0x5 | One of the pool entries | Reserved | The other pool entry | A pair of adjacent pool entries have headers that contradict each other. At least one of them is corrupt.
0x6 | One incorrectly-calculated entry | Reserved | The bad entry that caused the miscalculation | The pool block header's previous size is too large.
0x7 | 0 | Reserved | The bad pool entry | The pool block header size is corrupt.
0x8 | 0 | Reserved | The bad pool entry | The pool block header size is zero.
0x9 | One incorrectly-calculated entry | Reserved | The bad entry that caused the miscalculation | The pool block header size is corrupt (it is too large).
0xA | The pool entry that should have been found | Reserved | The virtual address of the page that should have contained the pool entry | The pool block header size is corrupt.

Cause

The pool is already corrupt at the time of the current request.

This may or may not be due to the caller.

Resolving the Problem

The internal pool links must be walked to figure out a possible cause of the problem.

Then you can use special pool for the suspect pool tags, or use Driver Verifier on the suspect driver.


Bug Check 0x1A: MEMORY_MANAGEMENT

The MEMORY_MANAGEMENT bug check has a value of 0x0000001A. This indicates that a severe memory management error occurred.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 is the only parameter of interest; this identifies the exact violation.

Parameter 1 | Cause of Error
0x1 | The fork clone block reference count is corrupt. (This only occurs on checked builds of Windows.)
0x777 | The caller is unlocking a system cache address that is not currently locked. (This address was either never mapped or is being unlocked twice.)
0x778 | The system is using the very last system cache view address, instead of preserving it.
0x780 0x781 | The PTEs mapping the argument system cache view have been corrupted.
0x1000 | A caller of MmGetSystemAddressForMdl* tried to map a fully-cached physical page as non-cached. This action would cause a conflicting hardware translation buffer entry, and so it was refused by the operating system. Since the caller specified "bugcheck on failure" in the requesting MDL, the system had no choice but to bugcheck in this instance.
0x1010 | The caller is unlocking a pageable section that is not currently locked. (This section was either never locked or is being unlocked twice.)
0x1234 | The caller is trying lock a nonexistent pageable section.
0x1235 | The caller is trying to protect an MDL with an invalid mapping.
0x3451 | The PTEs of an outswapped kernel thread stack are corrupt.
0x8888 0x8889 | Internal memory management structures are corrupt.
0x41283 | The working set index encoded in the PTE is corrupt.
0x41284 | A PTE or the working set list is corrupt.
0x41286 | The caller is trying to free an invalid pool address.
0x41785 | The working set list is corrupt.
0x61940 | A PDE has been unexpectedly invalidated.
Other | An unknown memory management error occurred.


Bug Check 0x1B: PFN_SHARE_COUNT

The PFN_SHARE_COUNT bug check has a value of 0x0000001B.

This bug check appears very infrequently.


Bug Check 0x1C: PFN_REFERENCE_COUNT

The PFN_REFERENCE_COUNT bug check has a value of 0x0000001C.

This bug check appears very infrequently.


Bug Check 0x1D: NO_SPIN_LOCK_AVAILABLE

The NO_SPIN_LOCK_AVAILABLE bug check has a value of 0x0000001D.

This bug check appears very infrequently.


Bug Check 0x1E: KMODE_EXCEPTION_NOT_HANDLED

The KMODE_EXCEPTION_NOT_HANDLED bug check has a value of 0x0000001E. This indicates that a kernel-mode program generated an exception which the error handler did not catch.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The exception code that was not handled
2 | The address at which the exception occurred
3 | Parameter 0 of the exception
4 | Parameter 1 of the exception

Cause

This is a very common bug check. To interpret it, you must identify which exception was generated.

Common exception codes include:

  • 0x80000002: STATUS_DATATYPE_MISALIGNMENT

    An unaligned data reference was encountered.

  • 0x80000003: STATUS_BREAKPOINT

    A breakpoint or ASSERT was encountered when no kernel debugger was attached to the system.

  • 0xC0000005: STATUS_ACCESS_VIOLATION

    A memory access violation occurred. (Parameter 4 of the bug check is the address that the driver attempted to access.)

For a complete list of exception codes, see the ntstatus.h file located in the inc directory of the Windows DDK.

Resolving the Problem

If you are not equipped to debug this problem, you should use some basic troubleshooting techniques. If a driver is identified in the bug check message, disable the driver or check with the manufacturer for driver updates. Try changing video adapters. Check with your hardware vendor for any BIOS updates. Disable BIOS memory options such as caching or shadowing.

If you plan to debug this problem, you may find it difficult to obtain a stack trace. Parameter 2 (the exception address) should pinpoint the driver or function that caused this problem.

If exception code 0x80000003 occurs, this indicates that a hard-coded breakpoint or assertion was hit, but the system was started with the /NODEBUG switch. This problem should rarely occur. If it occurs repeatedly, make sure a kernel debugger is connected and the system is started with the /DEBUG switch.

If exception code 0x80000002 occurs, the trap frame will supply additional information.

If the specific cause of the exception is unknown, the following should be considered:

Hardware incompatibility. First, make sure that any new hardware installed is listed on the Microsoft Windows Hardware Compatibility List (HCL).

Faulty device driver or system service. In addition, a faulty device driver or system service might be responsible for this error. Hardware issues, such as BIOS incompatibilities, memory conflicts, and IRQ conflicts can also generate this error.

If a driver is listed by name within the bug check message, disable or remove that driver. Disable or remove any drivers or services that were recently added. If the error occurs during the startup sequence and the system partition is formatted with NTFS file system, you might be able to use Safe Mode to rename or delete the faulty driver. If the driver is used as part of the system startup process in Safe Mode, you need to start the computer by using the Recovery Console to access the file.

If the problem is associated with Win32k.sys, the source of the error might be a third-party remote control program. If such software is installed, the service can be removed by starting the system using the Recovery Console and deleting the offending system service file.

Check the System Log in Event Viewer for additional error messages that might help pinpoint the device or driver that is causing bug check 0x1E. Disabling memory caching of the BIOS might also resolve the error. You should also run hardware diagnostics, especially the memory scanner, supplied by the system manufacturer. For details on these procedures, see the owner's manual for your computer.

The error that generates this message can occur after the first restart during Windows Setup, or after Setup is finished. A possible cause of the error is a system BIOS incompatibility. BIOS problems can be resolved by upgrading the system BIOS version.

To get a stack trace if the normal stack tracing procedures fail:

  1. Use the KB (Display Stack Backtrace) command to display parameters in the stack trace. Look for the call to NT!PspUnhandledExceptionInSystemThread. (If this function is not listed, see the note below.)
  2. The first parameter to NT!PspUnhandledExceptionInSystemThread is a pointer to a structure, which contains pointers to an except statement:
    typedef struct _EXCEPTION_POINTERS {
    PEXCEPTION_RECORD ExceptionRecord;
    PCONTEXT ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;

ULONG
PspUnhandledExceptionInSystemThread(
    IN PEXCEPTION_POINTERS ExceptionPointers
    )

    Use the DD (Display Memory) command on that address to display the necessary data.

  3. The first retrieved value is an exception record and the second is a context record. Use the .exr (Display Exception Record) command and the .cxr (Display Context Record) command with these two values as their arguments, respectively.
  4. After the .cxr command executes, use the KB command to display a stack trace that is based on the context record information. This stack trace indicates the calling stack where the unhandled exception occurred.

Note This procedure assumes that you can locate NT!PspUnhandledExceptionInSystemThread. However, in some cases (such as an access violation crash) you will not be able to do this. In that case, look for ntoskrnl!KiDispatchException. The third parameter passed to this function is a trap frame address. Use the .trap (Display Trap Frame) command with this address to set the Register Context to the proper value. You can then perform stack traces and issue other commands.

Here is an example of bug check 0x1E on an x86 processor:

kd> .bugcheck                 get the bugcheck data
Bugcheck code 0000001e
Arguments c0000005 8013cd0a 00000000 0362cffff

kd> kb                        start with a stack trace
FramePtr  RetAddr   Param1   Param2   Param3   Function Name
8013ed5c  801263ba  00000000 00000000 fe40cb00 NT!_DbgBreakPoint
8013eecc  8013313c  0000001e c0000005 8013cd0a NT!_KeBugCheckEx+0x194
fe40cad0  8013318e  fe40caf8 801359ff fe40cb00 NT!PspUnhandledExceptionInSystemThread+0x18
fe40cad8  801359ff  fe40cb00 00000000 fe40cb00 NT!PspSystemThreadStartup+0x4a
fe40cf7c  8013cb8e  fe43a44c ff6ce388 00000000 NT!_except_handler3+0x47
00000000  00000000  00000000 00000000 00000000 NT!KiThreadStartup+0xe

kd> dd fe40caf8 L2            dump EXCEPTION_POINTERS structure
0xFE40CAF8  fe40cd88 fe40cbc4                   ..@...@.

kd> .exr fe40cd88             first DWORD is the exception record
Exception Record @ FE40CD88:
   ExceptionCode: c0000005
  ExceptionFlags: 00000000
  Chained Record: 00000000
ExceptionAddress: 8013cd0a
NumberParameters: 00000002
   Parameter[0]: 00000000
   Parameter[1]: 0362cfff

kd> .cxr fe40cbc4             second DWORD is the context record
CtxFlags: 00010017
eax=00087000 ebx=00000000 ecx=03ff0000 edx=ff63d000 esi=0362cfff edi=036b3fff
eip=8013cd0a esp=fe40ce50 ebp=fe40cef8 iopl=0         nv dn ei pl nz ac po cy
vip=0    vif=0
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010617
0x8013cd0a  f3a4             rep movsb

kd> kb                        kb gives stack for context record
ChildEBP RetAddr  Args to Child
fe40ce54 80402e09 ff6c4000 ff63d000 03ff0000 NT!_RtlMoveMemory@12+0x3e
fe40ce68 80403c18 ffbc0c28 ff6ce008 ff6c4000 HAL!_HalpCopyBufferMap@20+0x49
fe40ce9c fe43b1e4 ff6cef90 ffbc0c28 ff6ce009 HAL!_IoFlushAdapterBuffers@24+0x148
fe40ceb8 fe4385b4 ff6ce388 6cd00800 ffbc0c28 QIC117!_kdi_FlushDMABuffers@20+0x28
fe40cef8 fe439894 ff6cd008 ffb6c820 fe40cf4c QIC117!_cqd_CmdReadWrite@8+0x26e
fe40cf18 fe437d92 ff6cd008 ffb6c820 ff6e4e50 QIC117!_cqd_DispatchFRB@8+0x210
fe40cf30 fe43a4f5 ff6cd008 ffb6c820 00000000 QIC117!_cqd_ProcessFRB@8+0x134
fe40cf4c 80133184 ff6ce388 00000000 00000000 QIC117!_kdi_ThreadRun@4+0xa9
fe40cf7c 8013cb8e fe43a44c ff6ce388 00000000 NT!_PspSystemThreadStartup@8+0x40


Bug Check 0x1F: SHARED_RESOURCE_CONV_ERROR

The SHARED_RESOURCE_CONV_ERROR bug check has a value of 0x0000001F.

This bug check appears very infrequently.


Bug Check 0x20: KERNEL_APC_PENDING_DURING_EXIT

The KERNEL_APC_PENDING_DURING_EXIT bug check has a value of 0x00000020. This indicates that an asynchronous procedure call (APC) was still pending when a thread exited.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The address of the APC found pending during exit
2 | The thread's APC disable count
3 | The current IRQL
4 | Reserved

Cause

The key data item is the thread's APC disable count (Parameter 2). If this is non-zero, it will indicate the source of the problem.

The APC disable count is decremented each time a driver calls KeEnterCriticalRegion, KeInitializeMutex, or FsRtlEnterFileSystem. The APC disable count is incremented each time a driver calls KeLeaveCriticalRegion, KeReleaseMutex, or FsRtlExitFileSystem.

Since these calls should always be in pairs, this value should be zero when a thread exits. A negative value indicates that a driver has disabled APC calls without re-enabling them. A positive value indicates that the reverse is true.

If you ever see this error, be very suspicious of all drivers installed on the machine — especially unusual or non-standard drivers.

This current IRQL (Parameter 3) should be zero. If it is not, that a driver's cancellation routine may have caused this bug check by returning at an elevated IRQL. In this case, carefully note what was running (and what was closing) at the time of the crash, and note all of the installed drivers at the time of the crash. The cause in this case is usually a severe bug in a driver.


Bug Check 0x21: QUOTA_UNDERFLOW

The QUOTA_UNDERFLOW bug check has a value of 0x00000021.

This bug check appears very infrequently.


Bug Check 0x22: FILE_SYSTEM

The FILE_SYSTEM bug check has a value of 0x00000022.

This bug check appears very infrequently.


Bug Check 0x23: FAT_FILE_SYSTEM

The FAT_FILE_SYSTEM bug check has a value of 0x00000023. This indicates that a problem occurred in the FAT file system.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Specifies source file and line number information. The high 16 bits (the first four hexadecimal digits after the "0x") identify the source file by its identifier number. The low 16 bits identify the source line in the file where the bug check occurred.
2 | If FatExceptionFilter is on the stack, this parameter specifies the address of the exception record.
3 | If FatExceptionFilter is on the stack, this parameter specifies the address of the context record.
4 | Reserved

Cause

One possible cause of this bug check is disk corruption. Corruption in the file system or bad blocks (sectors) on the disk can induce this error. Corrupted SCSI and IDE drivers can also adversely affect the system's ability to read and write to the disk, thus causing the error.

Another possible cause is depletion of nonpaged pool memory. If the nonpaged pool memory is completely depleted, this error can stop the system. However, during the indexing process, if the amount of available nonpaged pool memory is very low, another kernel-mode driver requiring nonpaged pool memory can also trigger this error.

Resolving the Problem

To debug this problem: Use the .cxr (Display Context Record) command with Parameter 3, and then use kb (Display Stack Backtrace).

To resolve a disk corruption problem: Check Event Viewer for error messages from SCSI and FASTFAT (System Log) or Autochk (Application Log) that might help pinpoint the device or driver that is causing the error. Try disabling any virus scanners, backup programs, or disk defragmenter tools that continually monitor the system. You should also run hardware diagnostics supplied by the system manufacturer. For details on these procedures, see the owner's manual for your computer. Run Chkdsk /f /r to detect and resolve any file system structural corruption. You must restart the system before the disk scan begins on a system partition.

To resolve a nonpaged pool memory depletion problem: Either increase the amount of installed memory (which increases the quantity of nonpaged pool memory available to the kernel), or reduce the number of files on the SFM volume.


Bug Check 0x24: NTFS_FILE_SYSTEM

The NTFS_FILE_SYSTEM bug check has a value of 0x00000024. This indicates a problem occurred in ntfs.sys, the driver file that allows the system to read and write to NTFS drives.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Specifies source file and line number information. The high 16 bits (the first four hexadecimal digits after the "0x") identify the source file by its identifier number. The low 16 bits identify the source line in the file where the bug check occurred.
2 | If NtfsExceptionFilter is on the stack, this parameter specifies the address of the exception record.
3 | If NtfsExceptionFilter is on the stack, this parameter specifies the address of the context record.
4 | Reserved

Cause

One possible cause of this bug check is disk corruption. Corruption in the NTFS file system or bad blocks (sectors) on the hard disk can induce this error. Corrupted SCSI and IDE drivers can also adversely affect the system's ability to read and write to disk, thus causing the error.

Another possible cause is depletion of nonpaged pool memory. If the nonpaged pool memory is completely depleted, this error can stop the system. However, during the indexing process, if the amount of available nonpaged pool memory is very low, another kernel-mode driver requiring nonpaged pool memory can also trigger this error.

Resolving the Problem

To debug this problem: Use the .cxr (Display Context Record) command with Parameter 3, and then use kb (Display Stack Backtrace).

To resolve a disk corruption problem: Check Event Viewer for error messages from SCSI and FASTFAT (System Log) or Autochk (Application Log) that might help pinpoint the device or driver that is causing the error. Try disabling any virus scanners, backup programs, or disk defragmenter tools that continually monitor the system. You should also run hardware diagnostics supplied by the system manufacturer. For details on these procedures, see the owner's manual for your computer. Run Chkdsk /f /r to detect and resolve any file system structural corruption. You must restart the system before the disk scan begins on a system partition.

To resolve a nonpaged pool memory depletion problem: Either increase the amount of installed memory (which increases the quantity of nonpaged pool memory available to the kernel), or reduce the number of files on the SFM volume.


Bug Check 0x25: NPFS_FILE_SYSTEM

The NPFS_FILE_SYSTEM bug check has a value of 0x00000025. This indicates that a problem occurred in the NPFS file system.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Specifies source file and line number information. The high 16 bits (the first four hexadecimal digits after the "0x") identify the source file by its identifier number. The low 16 bits identify the source line in the file where the bug check occurred.
2 | Reserved
3 | Reserved
4 | Reserved

Cause

One possible cause of this bug check is depletion of nonpaged pool memory. If the nonpaged pool memory is completely depleted, this error can stop the system. However, during the indexing process, if the amount of available nonpaged pool memory is very low, another kernel-mode driver requiring nonpaged pool memory can also trigger this error.

Resolving the Problem

To resolve a nonpaged pool memory depletion problem: Either increase the amount of installed memory. This will increase the quantity of nonpaged pool memory available to the kernel.


Bug Check 0x26: CDFS_FILE_SYSTEM

The CDFS_FILE_SYSTEM bug check has a value of 0x00000026. This indicates that a problem occurred in the CD file system.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Specifies source file and line number information. The high 16 bits (the first four hexadecimal digits after the "0x") identify the source file by its identifier number. The low 16 bits identify the source line in the file where the bug check occurred.
2 | If CdExceptionFilter is on the stack, this parameter specifies the address of the exception record.
3 | If CdExceptionFilter is on the stack, this parameter specifies the address of the context record.
4 | Reserved

Cause

One possible cause of this bug check is disk corruption. Corruption in the file system or bad blocks (sectors) on the disk can induce this error. Corrupted SCSI and IDE drivers can also adversely affect the system's ability to read and write to the disk, thus causing the error.

Another possible cause is depletion of nonpaged pool memory. If the nonpaged pool memory is completely depleted, this error can stop the system. However, during the indexing process, if the amount of available nonpaged pool memory is very low, another kernel-mode driver requiring nonpaged pool memory can also trigger this error.

Resolving the Problem

To debug this problem: Use the .cxr (Display Context Record) command with Parameter 3, and then use kb (Display Stack Backtrace).

To resolve a disk corruption problem: Check Event Viewer for error messages from SCSI and FASTFAT (System Log) or Autochk (Application Log) that might help pinpoint the device or driver that is causing the error. Try disabling any virus scanners, backup programs, or disk defragmenter tools that continually monitor the system. You should also run hardware diagnostics supplied by the system manufacturer. For details on these procedures, see the owner's manual for your computer. Run Chkdsk /f /r to detect and resolve any file system structural corruption. You must restart the system before the disk scan begins on a system partition.

To resolve a nonpaged pool memory depletion problem: Either increase the amount of installed memory (which increases the quantity of nonpaged pool memory available to the kernel), or reduce the number of files on the SFM volume.


Bug Check 0x27: RDR_FILE_SYSTEM

The RDR_FILE_SYSTEM bug check has a value of 0x00000027. This indicates that a problem occurred in the SMB redirector file system.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The high 16 bits (the first four hexadecimal digits after the "0x") identify the type of problem. Possible values include: 0xCA550000 RDBSS_BUG_CHECK_CACHESUP 0xC1EE0000 RDBSS_BUG_CHECK_CLEANUP 0xC10E0000 RDBSS_BUG_CHECK_CLOSE 0xBAAD0000 RDBSS_BUG_CHECK_NTEXCEPT
2 | If RxExceptionFilter is on the stack, this parameter specifies the address of the exception record.
3 | If RxExceptionFilter is on the stack, this parameter specifies the address of the context record.
4 | Reserved

Cause

One possible cause of this bug check is depletion of nonpaged pool memory. If the nonpaged pool memory is completely depleted, this error can stop the system. However, during the indexing process, if the amount of available nonpaged pool memory is very low, another kernel-mode driver requiring nonpaged pool memory can also trigger this error.

Resolving the Problem

To debug this problem: Use the .cxr (Display Context Record) command with Parameter 3, and then use kb (Display Stack Backtrace).

To resolve a nonpaged pool memory depletion problem: Either increase the amount of installed memory. This will increase the quantity of nonpaged pool memory available to the kernel.


Bug Check 0x28: CORRUPT_ACCESS_TOKEN

The CORRUPT_ACCESS_TOKEN bug check has a value of 0x00000028.

This bug check appears very infrequently.


Bug Check 0x29: SECURITY_SYSTEM

The SECURITY_SYSTEM bug check has a value of 0x00000029.

This bug check appears very infrequently.


Bug Check 0x2A: INCONSISTENT_IRP

The INCONSISTENT_IRP bug check has a value of 0x0000002A. This indicates that an IRP was found to contain inconsistent information.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The address of the IRP that was found to be inconsistent
2 | Reserved
3 | Reserved
4 | Reserved

Cause

An IRP was discovered to be in an inconsistent state. Usually this means some field of the IRP was inconsistent with the remaining state of the IRP. An example would be an IRP that was being completed, but was still marked as being queued to a driver's device queue.

Comments

This bug check code is not currently being used in the system, but exists for debugging purposes.


Bug Check 0x2B: PANIC_STACK_SWITCH

The PANIC_STACK_SWITCH bug check has a value of 0x0000002B. This indicates that the kernel mode stack was overrun.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The trap frame
2 | Reserved
3 | Reserved
4 | Reserved

Cause

This error normally appears when a kernel-mode driver uses too much stack space. It can also appear when serious data corruption occurs in the kernel.


Bug Check 0x2C: PORT_DRIVER_INTERNAL

The PORT_DRIVER_INTERNAL bug check has a value of 0x0000002C.

This bug check appears very infrequently.


Bug Check 0x2D: SCSI_DISK_DRIVER_INTERNAL

The SCSI_DISK_DRIVER_INTERNAL bug check has a value of 0x0000002D.

This bug check appears very infrequently.


Bug Check 0x2E: DATA_BUS_ERROR

The DATA_BUS_ERROR bug check has a value of 0x0000002E. This typically indicates that a parity error in system memory has been detected.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Virtual address that caused the fault
2 | Physical address that caused the fault
3 | Processor status register (PSR)
4 | Faulting instruction register (FIR)

Cause

This error is almost always caused by a hardware problem — a configuration issue, defective hardware, or incompatible hardware.

The most common hardware problems that can cause this error are defective RAM, Level 2 (L2) RAM cache errors, or video RAM errors. Hard disk corruption can also cause this error. Most other hardware errors result in bug check 0x2E (DATA_BUS_ERROR).

This bug check can also be caused when a device driver attempts to access an address in the 0x8xxxxxxx range that does not exist (in other words, that does not have a physical address mapping).

Resolving the Problem

Resolving a hardware problem: If hardware has recently been added to the system, remove it to see if the error recurs.

If existing hardware has failed, remove or replace the faulty component. You should run hardware diagnostics supplied by the system manufacturer to determine which hardware component has failed. For details on these procedures, see the owner's manual for your computer. Check that all adapter cards in the computer are properly seated. Use an ink eraser or an electrical contact treatment, available at electronics supply stores, to ensure that adapter card contacts are clean.

If the problem occurs on a newly installed system, check the availability of updates for the BIOS, the SCSI controller or network cards. Updates of this kind are typically available on the web site or the bulletin board system (BBS) of the hardware manufacturer.

If the error occurs after installing a new or updated device driver, the driver should be removed or replaced. If, under this circumstance, the error occurs during startup and the system partition is formatted with NTFS, you might be able to use Safe Mode to rename or delete the faulty driver.

If the driver is used as part of the system startup process in Safe Mode, you need to start the computer using the Recovery Console in order to access the file.

For additional error messages that might help pinpoint the device or driver that is causing the error, check the System Log in Event Viewer. Disabling memory caching or shadowing in the BIOS might also resolve this error. In addition, check the system for viruses, using any up-to-date commercial virus scanning software that examines the Master Boot Record of the hard disk. All Windows file systems can be infected by viruses.

Resolving a hard disk corruption problem: Run Chkdsk /f /r on the system partition. You must restart the system before the disk scan begins. If you cannot start the system due to the error, use the Recovery Console and run Chkdsk /r.

Warning If your system partition is formatted with the file allocation table (FAT) file system, the long filenames used by Windows can be damaged if Scandisk or another MS-DOS–based hard disk tool is used to verify the integrity of your hard disk from an MS-DOS prompt. (An MS-DOS prompt is typically derived from an MS-DOS startup disk or from starting MS-DOS on a multiboot system.) Always use the version of Chkdsk that matches your Windows version.


Bug Check 0x2F: INSTRUCTION_BUS_ERROR

The INSTRUCTION_BUS_ERROR bug check has a value of 0x0000002F.

This bug check appears very infrequently.


Bug Check 0x30: SET_OF_INVALID_CONTEXT

The SET_OF_INVALID_CONTEXT bug check has a value of 0x00000030. This indicates that the stack pointer in a trap frame had an invalid value.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The new stack pointer
2 | The old stack pointer
3 | The trap frame address
4 | 0

Cause

This bug check occurs when some routine attempts to set the stack pointer in the trap frame to a lower value than the current stack pointer value.

If this error were not caught, it would cause the kernel to run with a stack pointer pointing to stack which is no longer valid.


Bug Check 0x31: PHASE0_INITIALIZATION_FAILED

The PHASE0_INITIALIZATION_FAILED bug check has a value of 0x00000031. This indicates that system initialization failed.

Parameters

None

Cause

System initialization failed at a very early stage.

Resolving the Problem

A debugger is required to analyze this.


Bug Check 0x32: PHASE1_INITIALIZATION_FAILED

The PHASE1_INITIALIZATION_FAILED bug check has a value of 0x00000032. This indicates that system initialization failed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The NT status code that describes why the system initialization failed
2 | Reserved
3 | Reserved
4 | Reserved


Bug Check 0x33: UNEXPECTED_INITIALIZATION_CALL

The UNEXPECTED_INITIALIZATION_CALL bug check has a value of 0x00000033.

This bug check appears very infrequently.


Bug Check 0x34: CACHE_MANAGER

The CACHE_MANAGER bug check has a value of 0x00000034. This indicates that a problem occurred in the file system's cache manager.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Specifies source file and line number information. The high 16 bits (the first four hexadecimal digits after the "0x") identify the source file by its identifier number. The low 16 bits identify the source line in the file where the bug check occurred.
2 | Reserved
3 | Reserved
4 | Reserved

Cause

One possible cause of this bug check is depletion of nonpaged pool memory. If the nonpaged pool memory is completely depleted, this error can stop the system. However, during the indexing process, if the amount of available nonpaged pool memory is very low, another kernel-mode driver requiring nonpaged pool memory can also trigger this error.

Resolving the Problem

To resolve a nonpaged pool memory depletion problem: Either increase the amount of installed memory. This will increase the quantity of nonpaged pool memory available to the kernel.


Bug Check 0x35: NO_MORE_IRP_STACK_LOCATIONS

The NO_MORE_IRP_STACK_LOCATIONS bug check has a value of 0x00000035. This bug check occurs when the IoCallDriver packet has no more stack locations remaining.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Address of the IRP
2 | Reserved
3 | Reserved
4 | Reserved

Cause

A higher-level driver has attempted to call a lower-level driver through the IoCallDriver interface, but there are no more stack locations in the packet. This will prevent the lower-level driver from accessing its parameters.

This is a disastrous situation, since the higher level driver is proceeding as if it has filled in the parameters for the lower level driver (as required). But since there is no stack location for the latter driver, the former has actually written off the end of the packet. This means that some other memory has been corrupted as well.


Bug Check 0x36: DEVICE_REFERENCE_COUNT_NOT_ZERO

The DEVICE_REFERENCE_COUNT_NOT_ZERO bug check has a value of 0x00000036. This indicates that a driver attempted to delete a device object that still had a positive reference count.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The address of the device object
2 | Reserved
3 | Reserved
4 | Reserved

Cause

A device driver has attempted to delete one of its device objects from the system, but the reference count for that object was non-zero.

This means there are still outstanding references to the device. (The reference count indicates the number of reasons why this device object cannot be deleted.)

This is a bug in the calling device driver.


Bug Check 0x37: FLOPPY_INTERNAL_ERROR

The FLOPPY_INTERNAL_ERROR bug check has a value of 0x00000037.

This bug check appears very infrequently.


Bug Check 0x38: SERIAL_DRIVER_INTERNAL

The SERIAL_DRIVER_INTERNAL bug check has a value of 0x00000038.

This bug check appears very infrequently.


Bug Check 0x39: SYSTEM_EXIT_OWNED_MUTEX

The SYSTEM_EXIT_OWNED_MUTEX bug check has a value of 0x00000039.

This bug check appears very infrequently.


Bug Check 0x3A: SYSTEM_UNWIND_PREVIOUS_USER

The SYSTEM_UNWIND_PREVIOUS_USER bug check has a value of 0x0000003A.

This bug check appears very infrequently.


Bug Check 0x3B: SYSTEM_SERVICE_EXCEPTION

The SYSTEM_SERVICE_EXCEPTION bug check has a value of 0x0000003B.

This bug check appears very infrequently.


Bug Check 0x3C: INTERRUPT_UNWIND_ATTEMPTED

The INTERRUPT_UNWIND_ATTEMPTED bug check has a value of 0x0000003C.

This bug check appears very infrequently.


Bug Check 0x3D: INTERRUPT_EXCEPTION_NOT_HANDLED

The INTERRUPT_EXCEPTION_NOT_HANDLED bug check has a value of 0x0000003D.

This bug check appears very infrequently.


Bug Check 0x3E: MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED

The MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED bug check has a value of 0x0000003E. This indicates that the system has multiple processors, but they are asymmetric in relation to one another.

Parameters

None

Cause

In order to be symmetric, all processors must be of the same type and level. This system contains processors of different types (for example, a Pentium processor and an 80486 processor).


Bug Check 0x3F: NO_MORE_SYSTEM_PTES

The NO_MORE_SYSTEM_PTES bug check has a value of 0x0000003F. This is the result of a system which has performed too many I/O actions. This has resulted in fragmented system page table entries (PTE).

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | 0: system expansion PTE type 1: nonpaged pool expansion PTE type
2 | Size of memory request
3 | Total free system PTEs
4 | Total system PTEs

Cause

In almost all cases, the system is not actually out of PTEs. Rather, a driver has requested a large block of memory, but there is no contiguous block of sufficient size to satisfy this request.

Often video drivers will allocate large amounts of kernel memory that must succeed. Some backup programs do the same.

Resolving the Problem

A possible work-around: Modify the registry to increase the total number of system PTEs. If this does not help, remove any recently-installed software, especially backup utilities or disk-intensive applications.

Debugging the problem: If you are running Windows 2000 or later, the following method can be used to debug bug check 0x3F.

First, get a stack trace, and use the !sysptes 3 extension command.

Then set HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\TrackPtes equal to DWORD 1, and reboot. This will cause the system to save stack traces.

This allows you to display more detailed information about the PTE owners. For example:

0: kd> !sysptes 4

0x2c47 System PTEs allocated to mapping locked pages

VA       MDL     PageCount  Caller/CallersCaller
f0e5db48 eb6ceef0        1 ntkrpamp!MmMapLockedPages+0x15/ntkrpamp!IopfCallDriver+0x35
f0c3fe48 eb634bf0        1 netbt!NbtTdiAssociateConnection+0x1f/netbt!DelayedNbtProcessConnect+0x17c
f0db38e8 eb65b880        1 mrxsmb!SmbMmAllocateSessionEntry+0x89/mrxsmb!SmbCepInitializeExchange+0xda
f8312568 eb6df880        1 rdbss!RxCreateFromNetRoot+0x3d7/rdbss!RxCreateFromNetRoot+0x93
f8363908 eb685880        1 mrxsmb!SmbMmAllocateSessionEntry+0x89/mrxsmb!SmbCepInitializeExchange+0xda
f0c54248 eb640880        1 rdbss!RxCreateFromNetRoot+0x3d7/rdbss!RxCreateFromNetRoot+0x93
f0ddf448 eb5f3160        1 mrxsmb!MrxSmbUnalignedDirEntryCopyTail+0x387/mrxsmb!MRxSmbCoreInformation+0x36
f150bc08 eb6367b0        1 mrxsmb!MrxSmbUnalignedDirEntryCopyTail+0x387/mrxsmb!MRxSmbCoreInformation+0x36
f1392308 eb6fba70        1 netbt!NbtTdiOpenAddress+0x1fb/netbt!DelayedNbtProcessConnect+0x17c
eb1bee64 edac5000      200 VIDEOPRT!pVideoPortGetDeviceBase+0x118/VIDEOPRT!VideoPortMapMemory+0x45
f139b5a8 edd4b000       12 rdbss!FsRtlCopyWrite2+0x34/rdbss!RxDriverEntry+0x149
eb41f400 ede92000       20 VIDEOPRT!pVideoPortGetDeviceBase+0x139/VIDEOPRT!VideoPortGetDeviceBase+0x1b
eb41f198 edf2a000       20 NDIS!NdisReadNetworkAddress+0x3a/NDIS!NdisFreeSharedMemory+0x58
eb41f1e4 eb110000       10 VIDEOPRT!pVideoPortGetDeviceBase+0x139/VIDEOPRT!VideoPortGetDeviceBase+0x1b
......

If the system runs out of PTEs again after the TrackPtes registry value has been set, bug check 0xD8 (DRIVER_USED_EXCESSIVE_PTES) will be issued instead of 0x3F. The name of the driver causing this error will be displayed as well.


Bug Check 0x40: TARGET_MDL_TOO_SMALL

The TARGET_MDL_TOO_SMALL bug check has a value of 0x00000040. This indicates that a driver has improperly used IoBuildPartialMdl.

Parameters

None

Cause

This is a driver bug. A driver has called the IoBuildPartialMdl function and passed it an MDL to map part of a source MDL, but the target MDL is not large enough to map the entire range of addresses requested.

The source and target MDLs, as well as the address range length to be mapped, are the arguments to the IoBuildPartialMdl function:

    IoBuildPartialMdl(
        IN PMDL SourceMdl,
        IN OUT PMDL TargetMdl,
        IN PVOID VirtualAddress,
        IN ULONG Length
        )


Bug Check 0x41: MUST_SUCCEED_POOL_EMPTY

The MUST_SUCCEED_POOL_EMPTY bug check has a value of 0x00000041. This indicates that a kernel-mode thread has requested too much must-succeed pool.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The size of the request that could not be satisfied
2 | The number of pages used from nonpaged pool
3 | The number of requests from nonpaged pool larger than PAGE_SIZE
4 | The number of pages available

Cause

In Windows NT 4.0 and Windows 2000, only a small amount of must-succeed pool is permitted. In Windows XP and later, no driver is permitted to request must-succeed pool.

If a must-succeed request cannot be filled, this bug check is issued.

Resolving the Problem

Replace or rewrite the driver which is making the request. A driver should not request must-succeed pool. Instead, it should ask for normal pool and gracefully handle the scenario where the pool is temporarily empty.

The KB (Display Stack Backtrace) command will show the guilty driver.

Additionally, it is possible that a second component has depleted the must-succeed pool. To determine if this is the case, first use the KB command. Then use !vm 1 to display total pool usage, !poolused 2 to display per-tag nonpaged pool usage, and !poolused 4 to display per-tag paged pool usage. The component associated with the tag using the most pool is probably the culprit.


Bug Check 0x42: ATDISK_DRIVER_INTERNAL

The ATDISK_DRIVER_INTERNAL bug check has a value of 0x00000042.

This bug check appears very infrequently.


Bug Check 0x43: NO_SUCH_PARTITION

The NO_SUCH_PARTITION bug check has a value of 0x00000043.

This bug check appears very infrequently.


Bug Check 0x44: MULTIPLE_IRP_COMPLETE_REQUESTS

The MULTIPLE_IRP_COMPLETE_REQUESTS bug check has a value of 0x00000044. This indicates that a driver has tried to requested an IRP be completed that is already complete.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The address of the IRP
2 | Reserved
3 | Reserved
4 | Reserved

Cause

A driver has called IoCompleteRequest to ask that an IRP be completed, but the packet has already been completed.

Resolving the Problem

This is a tough bug to find because the simplest case — a driver that attempted to complete its own packet twice — is usually not the source of the problem. More likely, two separate drivers each believe that they own the packet, and each has attempted to complete it. The first request succeeds, and the second fails, resulting in this bug check.

Tracking down which drivers in the system caused the error is difficult, because the trail of the first driver has been covered by the second. However, the driver stack for the current request can be found by examining the DeviceObject fields in each of the stack locations.


Bug Check 0x45: INSUFFICIENT_SYSTEM_MAP_REGS

The INSUFFICIENT_SYSTEM_MAP_REGS bug check has a value of 0x00000045.

This bug check appears very infrequently.


Bug Check 0x46: DEREF_UNKNOWN_LOGON_SESSION

The DEREF_UNKNOWN_LOGON_SESSION bug check has a value of 0x00000046.

This bug check appears very infrequently.


Bug Check 0x47: REF_UNKNOWN_LOGON_SESSION

The REF_UNKNOWN_LOGON_SESSION bug check has a value of 0x00000047.

This bug check appears very infrequently.


Bug Check 0x48: CANCEL_STATE_IN_COMPLETED_IRP

The CANCEL_STATE_IN_COMPLETED_IRP bug check has a value of 0x00000048. This indicates that an I/O request packet (IRP) was completed, and then was subsequently cancelled.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Pointer to the IRP
2 | Reserved
3 | Reserved
4 | Reserved

Cause

An IRP that had a Cancel routine set was completed normally, without cancellation. But after it was complete, a driver called the IRP's Cancel routine.

This could be caused by a driver that completed the IRP and then attempted to cancel it.

It could also be caused by two drivers each trying to access the same IRP in an illegitimate way.


Bug Check 0x49: PAGE_FAULT_WITH_INTERRUPTS_OFF

The PAGE_FAULT_WITH_INTERRUPTS_OFF bug check has a value of 0x00000049.

This bug check appears very infrequently.


Bug Check 0x4A: IRQL_GT_ZERO_AT_SYSTEM_SERVICE

The IRQL_GT_ZERO_AT_SYSTEM_SERVICE bug check has a value of 0x0000004A. This indicates that a thread is returning to user mode from a system call when its IRQL is still above PASSIVE_LEVEL.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The address of the system function (system call routine)
2 | The current IRQL
3 | 0
4 | 0


Bug Check 0x4B: STREAMS_INTERNAL_ERROR

The STREAMS_INTERNAL_ERROR bug check has a value of 0x0000004B.

This bug check appears very infrequently.


Bug Check 0x4C: FATAL_UNHANDLED_HARD_ERROR

The FATAL_UNHANDLED_HARD_ERROR bug check has a value of 0x0000004C.

This bug check appears very infrequently.


Bug Check 0x4D: NO_PAGES_AVAILABLE

The NO_PAGES_AVAILABLE bug check has a value of 0x0000004D. This indicates that no free pages are available to continue operations.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The total number of dirty pages
2 | The number of dirty pages destined for the page file
3 | The size of the nonpaged pool available at time of bug check (in pages)
4 | The number of transition pages that are currently stranded

Cause

To see general memory statistics, use the !vm 3 extension.

This bug check can occur for any of the following reasons:

  • A driver has blocked, deadlocking the modified or mapped page writers. Examples of this include mutex deadlocks or accesses to paged out memory in file system drivers or filter drivers. This indicates a driver bug.

    If Parameter 1 or 2 is large, then this is a possibility. Use !vm 3.

  • A storage driver is not processing requests. Examples of this are stranded queues and non-responding drives. This indicates a driver bug.

    If Parameter 1 or 2 is large, then this is a possibility. Use !process 0 7.

  • Not enough pool is available for the storage stack to write out modified pages. This indicates a driver bug.

    If Parameter 3 is small, then this is a possibility. Use !vm and !poolused 2.

  • A high-priority realtime thread has starved the balance set manager from trimming pages, or starved the modified writer from writing them out. This indicates a bug in the component that created this thread.

    This situation is difficult to analyze. Try using !ready.

  • All the processes have been trimmed to their minimums and all modified pages written, but still no memory is available. The freed memory must be stuck in transition pages with non-zero reference counts — thus they cannot be put on the freelist.

    A driver is neglecting to unlock the pages preventing the reference counts from going to zero which would free the pages. This may be due to transfers that never finish, causing the driver routines to run endlessly, or to other driver bugs.

    If Parameter 4 is large, then this is a possibility. But it is very hard to find the driver. Try the !process 0 1 extension and look for any drivers that have a lot of locked pages.

If the problem cannot be found, then try booting with a kernel debugger attached from the beginning, and monitor the situation.


Bug Check 0x4E: PFN_LIST_CORRUPT

The PFN_LIST_CORRUPT bug check has a value of 0x0000004E. This indicates that the page frame number (PFN) list is corrupt.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of violation. The meaning of the other parameters depends on the value of Parameter 1.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x01 | The ListHead value which was corrupt | The number of pages available | 0 | The list head was corrupt
0x02 | The entry in the list being removed | The highest physical page number | The reference count of the entry being removed | A list entry was corrupt
0x07 | The page frame number | The current share count | 0 | A driver has unlocked a page more times than it locked it
0x8F | New page number | Old page number | 0 | The free or zeroed page listhead is corrupt
0x99 | Page frame number | Current page state | 0 | A PTE or PFN is corrupt

Cause

This error is typically caused by drivers passing bad memory descriptor lists. For example, a driver might have called MmUnlockPages twice with the same list.

If a kernel debugger is available, examine the stack trace.


Bug Check 0x4F: NDIS_INTERNAL_ERROR

The NDIS_INTERNAL_ERROR bug check has a value of 0x0000004F.

This bug check appears very infrequently.


Bug Check 0x50: PAGE_FAULT_IN_NONPAGED_AREA

The PAGE_FAULT_IN_NONPAGED_AREA bug check has a value of 0x00000050. This indicates that invalid system memory has been referenced.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read operation 1: Write operation
3 | Address that referenced memory (if known)
4 | Reserved

If the driver responsible for the error can be identified, its name is printed on the blue screen and stored in memory at the location (PUNICODE_STRING) KiBugCheckDriver.

Cause

Bug check 0x50 usually occurs after the installation of faulty hardware or in the event of failure of installed hardware (usually related to defective RAM, be it main memory, L2 RAM cache, or video RAM).

Another common cause is the installation of a faulty system service.

Antivirus software can also trigger this error, as can a corrupted NTFS volume.

Resolving the Problem

Resolving a faulty hardware problem: If hardware has been added to the system recently, remove it to see if the error recurs. If existing hardware has failed, remove or replace the faulty component. You should run hardware diagnostics supplied by the system manufacturer. For details on these procedures, see the owner's manual for your computer.

Resolving a faulty system service problem: Disable the service and confirm that this resolves the error. If so, contact the manufacturer of the system service about a possible update. If the error occurs during system startup, restart your computer, and press F8 at the character-mode menu that displays the operating system choices. At the resulting Windows Advanced Options menu, choose the Last Known Good Configuration option. This option is most effective when only one driver or service is added at a time.

Resolving an antivirus software problem: Disable the program and confirm that this resolves the error. If it does, contact the manufacturer of the program about a possible update.

Resolving a corrupted NTFS volume problem: Run Chkdsk /f /r to detect and repair disk errors. You must restart the system before the disk scan begins on a system partition. If the hard disk is SCSI, check for problems between the SCSI controller and the disk.

Finally, check the System Log in Event Viewer for additional error messages that might help pinpoint the device or driver that is causing the error. Disabling memory caching of the BIOS might also resolve it.

Comments

Typically, this address is in freed memory or is simply invalid.

This cannot be protected by try - except; it can only be protected by a probe.


Bug Check 0x51: REGISTRY_ERROR

The REGISTRY_ERROR bug check has a value of 0x00000051. This indicates that a severe registry error has occurred.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Reserved
2 | Reserved
3 | The pointer to the hive (if available)
4 | If the hive is corrupt, the return code of HvCheckHive (if available)

Cause

Something has gone badly wrong with the registry. If a kernel debugger is available, get a stack trace.

This error may indicate that the registry encountered an I/O error while trying to read one of its files. This can be caused by hardware problems or file system corruption.

It may also occur due to a failure in a refresh operation, which is used only in by the security system, and then only when resource limits are encountered.


Bug Check 0x52: MAILSLOT_FILE_SYSTEM

The MAILSLOT_FILE_SYSTEM bug check has a value of 0x00000052.

This bug check appears very infrequently.


Bug Check 0x53: NO_BOOT_DEVICE

The NO_BOOT_DEVICE bug check has a value of 0x00000053.

This bug check appears very infrequently.


Bug Check 0x54: LM_SERVER_INTERNAL_ERROR

The LM_SERVER_INTERNAL_ERROR bug check has a value of 0x00000054.

This bug check appears very infrequently.


Bug Check 0x55: DATA_COHERENCY_EXCEPTION

The DATA_COHERENCY_EXCEPTION bug check has a value of 0x00000055.

This bug check appears very infrequently.


Bug Check 0x56: INSTRUCTION_COHERENCY_EXCEPTION

The INSTRUCTION_COHERENCY_EXCEPTION bug check has a value of 0x00000056.

This bug check appears very infrequently.


Bug Check 0x57: XNS_INTERNAL_ERROR

The XNS_INTERNAL_ERROR bug check has a value of 0x00000057.

This bug check appears very infrequently.


Bug Check 0x58: FTDISK_INTERNAL_ERROR

The FTDISK_INTERNAL_ERROR bug check has a value of 0x00000058. This is issued if the system is booted from the wrong copy of a mirrored partition.

Parameters

None

Cause

The hives are indicating that the mirror is valid, but it is not. The hives should actually be pointing to the shadow partition.

This is almost always caused by the primary partition being revived.

Resolving the Problem

Reboot the system from the shadow partition.


Bug Check 0x59: PINBALL_FILE_SYSTEM

The PINBALL_FILE_SYSTEM bug check has a value of 0x00000059. This indicates that a problem occurred in the Pinball file system.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Specifies source file and line number information. The high 16 bits (the first four hexadecimal digits after the "0x") identify the source file by its identifier number. The low 16 bits identify the source line in the file where the bug check occurred.
2 | Reserved
3 | Reserved
4 | Reserved

Cause

One possible cause of this bug check is depletion of nonpaged pool memory. If the nonpaged pool memory is completely depleted, this error can stop the system. However, during the indexing process, if the amount of available nonpaged pool memory is very low, another kernel-mode driver requiring nonpaged pool memory can also trigger this error.

Resolving the Problem

To resolve a nonpaged pool memory depletion problem: Either increase the amount of installed memory. This will increase the quantity of nonpaged pool memory available to the kernel.


Bug Check 0x5A: CRITICAL_SERVICE_FAILED

The CRITICAL_SERVICE_FAILED bug check has a value of 0x0000005A.

This bug check appears very infrequently.


Bug Check 0x5B: SET_ENV_VAR_FAILED

The SET_ENV_VAR_FAILED bug check has a value of 0x0000005B.

This bug check appears very infrequently.


Bug Check 0x5C: HAL_INITIALIZATION_FAILED

The HAL_INITIALIZATION_FAILED bug check has a value of 0x0000005C.

This bug check appears very infrequently.


Bug Check 0x5D: UNSUPPORTED_PROCESSOR

The UNSUPPORTED_PROCESSOR bug check has a value of 0x0000005D. This indicates that the computer is attempting to run Windows on an unsupported processor.

Parameters

None

Cause

Windows requires a higher-grade processor than the one you are using.


Bug Check 0x5E: OBJECT_INITIALIZATION_FAILED

The OBJECT_INITIALIZATION_FAILED bug check has a value of 0x0000005E.

This bug check appears very infrequently.


Bug Check 0x5F: SECURITY_INITIALIZATION_FAILED

The SECURITY_INITIALIZATION_FAILED bug check has a value of 0x0000005F.

This bug check appears very infrequently.


Bug Check 0x60: PROCESS_INITIALIZATION_FAILED

The PROCESS_INITIALIZATION_FAILED bug check has a value of 0x00000060.

This bug check appears very infrequently.


Bug Check 0x61: HAL1_INITIALIZATION_FAILED

The HAL1_INITIALIZATION_FAILED bug check has a value of 0x00000061.

This bug check appears very infrequently.


Bug Check 0x62: OBJECT1_INITIALIZATION_FAILED

The OBJECT1_INITIALIZATION_FAILED bug check has a value of 0x00000062.

This bug check appears very infrequently.


Bug Check 0x63: SECURITY1_INITIALIZATION_FAILED

The SECURITY1_INITIALIZATION_FAILED bug check has a value of 0x00000063.

This bug check appears very infrequently.


Bug Check 0x64: SYMBOLIC_INITIALIZATION_FAILED

The SYMBOLIC_INITIALIZATION_FAILED bug check has a value of 0x00000064.

This bug check appears very infrequently.


Bug Check 0x65: MEMORY1_INITIALIZATION_FAILED

The MEMORY1_INITIALIZATION_FAILED bug check has a value of 0x00000065.

This bug check appears very infrequently.


Bug Check 0x66: CACHE_INITIALIZATION_FAILED

The CACHE_INITIALIZATION_FAILED bug check has a value of 0x00000066.

This bug check appears very infrequently.


Bug Check 0x67: CONFIG_INITIALIZATION_FAILED

The CONFIG_INITIALIZATION_FAILED bug check has a value of 0x00000067. This indicates that the registry configuration failed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Reserved
2 | The location selector
3 | The NT status code
4 | Reserved

Cause

The registry couldn't allocate the pool needed to contain the registry files. This should never happen, since it is early enough in system initialization that there should be plenty of paged pool available.


Bug Check 0x68: FILE_INITIALIZATION_FAILED

The FILE_INITIALIZATION_FAILED bug check has a value of 0x00000068.

This bug check appears very infrequently.


Bug Check 0x69: IO1_INITIALIZATION_FAILED

The IO1_INITIALIZATION_FAILED bug check has a value of 0x00000069. This indicates that the initialization of the I/O system failed for some reason.

Parameters

None

Cause

There is very little information available to analyze this error.

Most likely, the setup routine made some very poor decisions about the installation of the system, or the user has reconfigured the system.


Bug Check 0x6A: LPC_INITIALIZATION_FAILED

The LPC_INITIALIZATION_FAILED bug check has a value of 0x0000006A.

This bug check appears very infrequently.


Bug Check 0x6B: PROCESS1_INITIALIZATION_FAILED

The PROCESS1_INITIALIZATION_FAILED bug check has a value of 0x0000006B. This indicates that the Windows initialization failed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The NT status code that caused the failure
2 | Reserved
3 | Reserved
4 | Reserved

Cause

This error can be caused by any part of the disk subsystem, including bad disks, bad or incorrect cables, mixing different ATA-type devices on the same chain, or drives that are not available due to hardware regeneration.

It can also be caused by a missing file from the boot partition, or by a driver file that has been disabled from the Drivers tab by mistake.


Bug Check 0x6C: REFMON_INITIALIZATION_FAILED

The REFMON_INITIALIZATION_FAILED bug check has a value of 0x0000006C.

This bug check appears very infrequently.


Bug Check 0x6D: SESSION1_INITIALIZATION_FAILED

The SESSION1_INITIALIZATION_FAILED bug check has a value of 0x0000006D. This indicates that the Windows initialization failed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The NT status code that caused the initialization failure
2 | 0
3 | 0
4 | 0


Bug Check 0x6E: SESSION2_INITIALIZATION_FAILED

The SESSION2_INITIALIZATION_FAILED bug check has a value of 0x0000006E. This indicates that the Windows initialization failed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The NT status code that caused Windows to conclude that initialization failed
2 | 0
3 | 0
4 | 0


Bug Check 0x6F: SESSION3_INITIALIZATION_FAILED

The SESSION3_INITIALIZATION_FAILED bug check has a value of 0x0000006F. This indicates that the Windows initialization failed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The NT status code that caused Windows to conclude that initialization failed
2 | 0
3 | 0
4 | 0


Bug Check 0x70: SESSION4_INITIALIZATION_FAILED

The SESSION4_INITIALIZATION_FAILED bug check has a value of 0x00000070. This indicates that the Windows initialization failed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The NT status code that caused Windows to conclude that initialization failed
2 | 0
3 | 0
4 | 0


Bug Check 0x71: SESSION5_INITIALIZATION_FAILED

The SESSION5_INITIALIZATION_FAILED bug check has a value of 0x00000071. This indicates that the Windows initialization failed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The NT status code that caused Windows to conclude that initialization failed
2 | 0
3 | 0
4 | 0


Bug Check 0x72: ASSIGN_DRIVE_LETTERS_FAILED

The ASSIGN_DRIVE_LETTERS_FAILED bug check has a value of 0x00000072.

This bug check appears very infrequently.


Bug Check 0x73: CONFIG_LIST_FAILED

The CONFIG_LIST_FAILED bug check has a value of 0x00000073. This indicates that one of the core system hives cannot be linked in the registry tree.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | 1
2 | The NT status code that tripped Windows into thinking that it had failed to load the hive
3 | The index of the hive in the hive list
4 | A pointer to a UNICODE_STRING containing the filename of the hive

Cause

The registry hive in question can be either SAM, SECURITY, SOFTWARE or DEFAULT. The hive is certainly valid, since it was loaded successfully.

Examine Parameter 2 to see why the hive could not be linked in the registry tree. One common cause of this error is that Windows is out of disk space on the system drive (in which case this parameter is 0xC000017D, STATUS_NO_LOG_SPACE). Another common problem is that an attempt to allocate pool has failed (in which case this parameter is 0xC000009A, STATUS_INSUFFICIENT_RESOURCES). Other status codes must be individually investigated.


Bug Check 0x74: BAD_SYSTEM_CONFIG_INFO

The BAD_SYSTEM_CONFIG_INFO bug check has a value of 0x00000074. This indicates that there is an error in the registry.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Reserved
2 | Reserved
3 | Reserved
4 | The NT status code (if available)

Cause

This error will occur if the SYSTEM hive is corrupt. However, this cause is unlikely, since the OS Loader or the NTLDR will check a hive for corruption when loading it.

This error can also occur if some critical registry keys and values are not present. This could be the result of someone manually editing the registry.

Resolving the Problem

Try booting by selecting "last known good configuration" in the boot options.

If this does not work, it means the registry damage is too extensive. You will then need to reinstall or use the Emergency Repair Disk.


Bug Check 0x75: CANNOT_WRITE_CONFIGURATION

The CANNOT_WRITE_CONFIGURATION bug check has a value of 0x00000075. This indicates that the SYSTEM registry hive file cannot be converted to a mapped file.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | 1
2 | The NT status code that tripped Windows into thinking that it had failed to convert the hive
3 | Reserved
4 | Reserved

Cause

This error usually happens if the system is out of pool and Windows cannot reopen the hive.

This error should almost never occur, since the conversion happens quite early during system initialization, so enough pool should be available.


Bug Check 0x76: PROCESS_HAS_LOCKED_PAGES

The PROCESS_HAS_LOCKED_PAGES bug check has a value of 0x00000076. This indicates that a driver failed to release locked pages after an I/O operation.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | 0
2 | Process address
3 | Number of locked pages
4 | Pointer to driver stacks (if enabled); otherwise 0

Cause

Some driver failed to release pages that it locked.

Resolving the Problem

The guilty driver can be detected by editing the registry. In the \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management registry key, create or edit the TrackLockedPages value, and set it equal to DWORD 1. Then reboot. The system will then save stack traces. If the driver commits the same error, bug check 0xCB (DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS) will be issued, and the name of the driver causing this error will be displayed.


Bug Check 0x77: KERNEL_STACK_INPAGE_ERROR

The KERNEL_STACK_INPAGE_ERROR bug check has a value of 0x00000077. This indicates that the requested page of kernel data from the paging file could not be read into memory.

Parameters

The four parameters listed in the message can have two possible meanings.

If the first parameter is 0, 1, or 2, the parameters have the following meaning:

Parameter | Description
1 | 0: Indicates that the page was retrieved from page cache 1: Indicates that the page was retrieved from a disk 2: Indicates that the page was retrieved from a disk, the storage stack returned SUCCESS, but Status.Information is not equal to PAGE_SIZE
2 | Value actually found in the stack where the signature should be
3 | 0
4 | Address of the signature on the kernel stack

If the first parameter is any other value, the parameters have the following meaning:

Parameter | Description
1 | Status code
2 | I/O status code
3 | Page file number
4 | Offset into page file

Cause

If the first parameters is 0, 1, or 2, the stack signature in the kernel stack was not found. This error is probably caused by defective hardware, such as a RAM error.

If the first parameter is another value, the cause of this error can be determined from the I/O status code (the second parameter). Some common status codes are:

  • 0xC000009A, or STATUS_INSUFFICIENT_RESOURCES, is caused by lack of nonpaged pool resources. This indicates a driver bug in the storage stack, since the storage stack should always be able to retrieve this data, regardless of software resource availability.
  • 0xC000009C, or STATUS_DEVICE_DATA_ERROR, is typically due to bad blocks (sectors) on the hard disk.
  • 0xC000009D, or STATUS_DEVICE_NOT_CONNECTED, indicates defective or loose cabling, termination, or the controller not seeing the hard disk.
  • 0xC000016A, or STATUS_DISK_OPERATION_FAILED, is typically due to bad blocks (sectors) on the hard disk.
  • 0xC0000185, or STATUS_IO_DEVICE_ERROR, is caused by improper termination or defective cabling on SCSI devices, or two devices attempting to use the same IRQ.

These codes are the most common ones for which specific causes have been determined. For information about other possible status codes that can be returned, see the file ntstatus.h in the Windows DDK.

This bug check can also be caused by a virus infection.

Resolving the Problem

Resolving a bad block problem: If you can restart the system after the error, Autochk runs automatically and attempts to map the bad sector to prevent it's further use.

If Autochk does not scan the hard disk for errors, you can manually launch the disk scanner. Run Chkdsk /f /r on the system partition. You must restart the system before the disk scan begins. If you cannot start the system due to the error, use the Recovery Console and run Chkdsk /r.

Warning If your system partition is formatted with the FAT file system, the long filenames used by Windows can be damaged if Scandisk or another MS-DOS–based hard disk tool is used to verify the integrity of your hard disk from an MS-DOS prompt. (An MS-DOS prompt is typically derived from an MS-DOS startup disk or from starting MS-DOS on a multiboot system.) Always use the version of Chkdsk that matches your Windows version.

Resolving a defective hardware problem: If the I/O status is C0000185 and the paging file is on an SCSI disk, the disk cabling and SCSI termination should be checked for problems.

Resolving a failing RAM problem: Run the hardware diagnostics supplied by the system manufacturer, especially the memory scanner. For details on these procedures, see the owner's manual for your computer.

Check that all the adapter cards in the computer are properly seated. Use an ink eraser or an electrical contact treatment, available at electronics supply stores, to ensure adapter card contacts are clean.

Check the System Log in Event Viewer for additional error messages that might help pinpoint the device that is causing the error. Disabling memory caching of the BIOS might also resolve this error.

Make sure that the latest Windows Service Pack is installed.

If the preceding steps fail to resolve the error, take the system motherboard to a repair facility for diagnostic testing. A crack, a scratched trace, or a defective component on the motherboard can cause this error.

Resolving a virus infection: You should check your computer for viruses using any up-to-date, commercial virus scanning software that examines the Master Boot Record of the hard disk. All Windows file systems can be infected by viruses.

See Also

Bug Check 0x7A (KERNEL_DATA_INPAGE_ERROR)


Bug Check 0x78: PHASE0_EXCEPTION

The PHASE0_EXCEPTION bug check has a value of 0x00000078.

This bug check appears very infrequently.


Bug Check 0x79: MISMATCHED_HAL

The MISMATCHED_HAL bug check has a value of 0x00000079. This indicates that the Hardware Abstraction Layer (HAL) revision level or configuration does not match that of the kernel or the machine.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of mismatch.

Parameter 1 | Parameter 2 | Parameter 3 | Cause of Error
1 | Major PRCB level of ntoskrnl.exe | Major PRCB level of hal.dll | PRCB release level mismatch
2 | Build type of ntoskrnl.exe | Build type of hal.dll | Build type mismatch

When Parameter 1 equals two, the following build type codes are used:

  • 0: Multiprocessor-enabled free build
  • 1: Multiprocessor-enabled checked build
  • 2: Single-processor free build

Cause

This error often results from the user manually updating either ntoskrnl.exe or hal.dll.

The error can also indicate that one of those two files is out of date. For example, the HAL might be designed for Microsoft Windows NT® 4.0 while the kernel is designed for Windows 2000. Or the machine might erroneously have a multiprocessor HAL and a single-processor kernel installed, or vice versa.

The kernel file ntoskrnl.exe is for single-processor systems and ntkrnlmp.exe is for multiprocessor systems. However, these filenames correspond to the files on the installation media; after Windows has been installed, the file is renamed to ntoskrnl.exe, regardless of the source file used. The HAL file also uses the name hal.dll after installation, but there are several possible HAL files on the installation media. For more details, see "Installing the Checked Build" in the Windows DDK.

Resolving the Problem

Restart the computer using either the product CD or the Windows Setup disks. At the Welcome screen, press F10 to start the Recovery Console. Use the Copy command to copy either the correct HAL or kernel file from the original CD into the appropriate folder on the hard disk. The Copy command detects whether the file to be copied is in the Microsoft compressed file format. If so, it automatically expands the file copied on the target drive.


Bug Check 0x7A: KERNEL_DATA_INPAGE_ERROR

The KERNEL_DATA_INPAGE_ERROR bug check has a value of 0x0000007A. This indicates that the requested page of kernel data from the paging file could not be read into memory.

Parameters

The four parameters listed in the message can have two possible meanings. If the first parameter is one, two, or three, the following definitions should be used:

Parameter | Description
1 | Lock type that was held (1, 2, or 3)
2 | Error status (usually an I/O status code)
3 | If Lock Type is 1 or 2: current process If Lock Type is 3: virtual address
4 | Virtual address that could not be paged into memory

Otherwise, use the following definitions:

Parameter | Description
1 | Page Table Entry (PTE) address
2 | Error status (usually an I/O status code)
3 | Virtual address
4 | Virtual address that could not be paged into memory

Cause

Frequently, the cause of this error can be determined from the error status (Parameter 2). Some common status codes are:

  • 0xC000009A, or STATUS_INSUFFICIENT_RESOURCES, is caused by lack of nonpaged pool resources.
  • 0xC000009C, or STATUS_DEVICE_DATA_ERROR, is typically due to bad blocks (sectors) on the hard disk.
  • 0xC000009D, or STATUS_DEVICE_NOT_CONNECTED, indicates defective or loose cabling, termination, or the controller not seeing the hard disk.
  • 0xC000016A, or STATUS_DISK_OPERATION_FAILED, is also caused by bad blocks (sectors) on the hard disk.
  • 0xC0000185, or STATUS_IO_DEVICE_ERROR, is caused by improper termination or defective cabling on SCSI devices, or two devices attempting to use the same IRQ.

These codes are the most common ones for which specific causes have been determined. For information about other possible status codes that can be returned, see the file ntstatus.h in the Windows DDK.

Another common cause of this error message is defective hardware or failing RAM.

This bug check can also be caused by a virus infection.

Resolving the Problem

Resolving a bad block problem: An I/O status code of 0xC000009C or 0xC000016A normally indicates that the data could not be read from the disk due to a bad block (sector). If you can restart the system after the error, Autochk runs automatically and attempts to map the bad sector to prevent it's further use.

If Autochk does not scan the hard disk for errors, you can manually launch the disk scanner. Run Chkdsk /f /r on the system partition. You must restart the system before the disk scan begins. If you cannot start the system due to the error, use the Recovery Console and run Chkdsk /r.

Warning If your system partition is formatted with the FAT file system, the long filenames used by an NT-based operating system can be damaged if Scandisk or another MS-DOS-based hard disk tool is used to verify the integrity of your hard disk from an MS-DOS prompt. (An MS-DOS prompt is typically derived from an MS-DOS startup disk or from starting MS-DOS on a multiboot system.) Always use the version of Chkdsk that matches your Windows version.

Resolving a defective hardware problem: If the I/O status is C0000185 and the paging file is on an SCSI disk, the disk cabling and SCSI termination should be checked for problems.

Resolving a failing RAM problem: Run the hardware diagnostics supplied by the system manufacturer, especially the memory scanner. For details on these procedures, see the owner's manual for your computer.

Check that all the adapter cards in the computer are properly seated. Use an ink eraser or an electrical contact treatment, available at electronics supply stores, to ensure adapter card contacts are clean.

Check the System Log in Event Viewer for additional error messages that might help pinpoint the device that is causing the error. Disabling memory caching of the BIOS might also resolve this error.

Make sure that the latest Windows Service Pack is installed.

If the preceding steps fail to resolve the error, take the system motherboard to a repair facility for diagnostic testing. A crack, a scratched trace, or a defective component on the motherboard can cause this error.

Resolving a virus infection: You should check your computer for viruses using any up-to-date, commercial virus scanning software that examines the Master Boot Record of the hard disk. All Windows file systems can be infected by viruses.

See Also

Bug Check 0x77 (KERNEL_STACK_INPAGE_ERROR)


Bug Check 0x7B: INACCESSIBLE_BOOT_DEVICE

The INACCESSIBLE_BOOT_DEVICE bug check has a value of 0x0000007B. This indicates that Windows has lost access to the system partition during startup.

Parameters

The four parameters listed in the message are defined, in order of appearance, as follows:

Parameter | Description
1 | Address of a UNICODE_STRING structure, or address of the device object that could not be mounted
2 | 0
3 | 0
4 | 0

To determine the meaning of Parameter 1, look at the data it points to. If the first word (USHORT) at this address is even, it is the beginning of a Unicode string. If the first word (USHORT) at this address is 0x3, this is the first field (Type) of a device object.

  • If this points to a device object, this indicates the file system that was supposed to read the boot device failed to initialize, or simply did not recognize the data on the boot device as a file system structure. In this case, the specified device object is the object that could not be mounted.
  • If this points to a Unicode string, you need to read the first 8 bytes at this address. These form the UNICODE_STRING structure, which is defined as follows:
    USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;

    The Length field gives the actual length of the string. The Buffer field points to the beginning of the string; this will always be at least 0x80000000.

    The actual string contains the Advanced RISC Computing (ARC) specification name of the device from which the boot was being attempted. ARC names are a generic method of identifying devices within the ARC environment.

Cause

This error often results from a boot device failure. During I/O system initialization, the boot device driver might have failed to initialize the boot device (typically a hard disk). File system initialization might have failed because it did not recognize the data on the boot device. Also, repartitioning the system partition or installing a new SCSI adapter or disk controller might induce this error.

This error can also result from incompatible disk hardware. If the error occurred at the initial setup of the system, the system might have been installed on an unsupported disk or SCSI controller. Some controllers are supported only by drivers that are in the Windows Driver Library (WDL), which requires the user to do a custom installation.

Resolving the Problem

This error always occurs while the system is starting. This will often happen before the debugger connection is established, making debugging difficult or impossible.

Resolving a failed boot device problem: If this happens on an x86 system, the boot.ini file must be edited. On an IA-64 system you must edit the OsLoadOptions in the non-volatile RAM. See Configuring Software on the Target Computer for details.

Resolving an incompatible disk hardware problem: If Setup autodetected the controller, you might need to skip detection and use a specific manufacturer's diskette to load the driver. Also, check the availability of updates for the system BIOS and SCSI controller firmware. Updates of this kind are typically available on the web site or BBS of the hardware manufacturer.

Remove any recently added hardware, especially hard disks or controllers, to see if the error is resolved. If the offending piece of hardware was a hard disk, the disk firmware version might be incompatible with your version of Windows. Contact the manufacturer for updates. If the removal of another piece of hardware resolved the error, IRQ or I/O port conflicts likely exist. Reconfigure the new device according to the manufacturer's instructions.

Confirm that all hard disks, hard disk controllers, and SCSI adapters are listed on the Microsoft Windows Hardware Compatibility List (HCL).

If a driver was recently added, restart your computer, and press F8 at the character-based menu that displays the operating system choices. At the resulting Windows Advanced Options menu, choose the Last Known Good Configuration option. This option is most effective when only one driver or service is added at a time.

In addition, check your computer for viruses using any up-to-date, commercial virus scanning software that examines the Master Boot Record of the hard disk. All Windows file systems can be infected by viruses.

This error can also be a result of hard disk corruption. Run Chkdsk /f /r on the system partition. You must restart the system before the disk scan begins. If you cannot start the system due to the error, use the Recovery Console and run Chkdsk /r.

If you are unable to boot the system to the last known good configuration, you should try to boot off the Windows CD-ROM. Then you can run Chkdsk from the Repair Console.

Warning If your system partition is formatted with the FAT file system, the long filenames used by all NT-based operating systems can be damaged if Scandisk or another MS-DOS®–based hard disk tool is used to verify the integrity of your hard disk from an MS-DOS prompt. (An MS-DOS prompt is typically derived from an MS-DOS startup disk or from starting MS-DOS on a multiboot system.) Always use the version of Chkdsk that matches your Windows version.

If your system has SCSI adapters, contact the adapter manufacturer to obtain updated Windows drivers. Try disabling sync negotiation in the SCSI BIOS, checking the cabling and the SCSI IDs of each device, and confirming proper termination. For IDE devices, define the onboard IDE port as Primary only. Also check each IDE device for the proper master/slave/stand alone setting. Try removing all IDE devices except for hard disks. Finally, check the System Log in Event Viewer for additional error messages that might help pinpoint the device or driver that is causing the error.

To analyze this error: Execute an LM (List Loaded Modules) command in the debugger. Verify that the following drivers were loaded: disk, classpnp, ftdisk, partmgr, and either FAT or NTFS.

kd> lm

start    end        module name
80001000 80016000   hal          (deferred)
80016000 80018c40   bootvid      (deferred)
80019000 8001dfc0   pciidex      (deferred)
8001e000 8001ff60   dmload       (deferred)
80086000 80086980   pciide       (deferred)
802c1000 802cc000   pci          (deferred)
802cc000 802d39a0   isapnp       (deferred)
802d4000 802ed000   ftdisk       (deferred)
802ed000 802f3820   mountmgr     (deferred)
802f4000 802fad40   fdc          (deferred)
802fb000 802fdc20   partmgr      (deferred)
802fe000 802fef00   wmilib       (deferred)
8039b000 803b8000   dmio         (deferred)
803b8000 803cb000   atapi        (deferred)
803cb000 803d1560   disk         (deferred)
803d2000 803d8e80   classpnp     (deferred)
803d9000 803fa000   fastfat      (deferred)
80400000 80540000   nt           (pdb symbols)   \\localsymbols\symbols\exe\ntoskrnl.dbg
80540000 80546f20   ksecdd       (deferred)
80547000 80554620   cnss         (deferred)
80555000 80579000   ndis         (deferred)

You'll probably need pci or isapnp loaded. Also make sure your controller drivers were loaded — atapi.sys with the channel drivers (pciide and pciidex or intelid) or scsiport.sys with the appropriate miniport driver.

It's always helpful to know as much as possible about the boot device Windows was installed on. Useful ways to investigate include:

  • Find out what type of controller the boot device is connected to (SCSI, IDE, 1394, etc). Try to find out the manufacturer of non-IDE controllers (Adaptec, Symbios, and so on).
  • Note the SCSI ID of the boot device if you're using SCSI.
  • Indicate if other devices are attached to the same controller the boot device is on (CD-ROMs, zip drives, and so on).
  • Note the file system used on the drive.

The !devnode extension will give you more information, as long as you know what your boot devices are. Usually Plug and Play couldn't assign resources to the boot device. You can verify this by finding an entry for the service. If the status flags include DNF_INSUFFICIENT_RESOURCES and/or don't include DNF_STARTED or DNF_ENUMERATED, then you've confirmed the problem. Try !devnode 0 1 scsi or !devnode 0 1 atapi to save some time instead of dumping the whole device tree.


Bug Check 0x7C: BUGCODE_NDIS_DRIVER

The BUGCODE_NDIS_DRIVER bug check has a value of 0x0000007C. This indicates that a problem occurred with an NDIS driver.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of violation. The meaning of the other parameters depends on the value of Parameter 1.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x01 | Address of the miniport block | Number of bytes requested | Current IRQL | A driver called NdisMAllocateSharedMemory at a raised IRQL.
0x02 | Address of the miniport block | Shared memory page that was corrupted | Address of the NDIS_WRAPPER_CONTEXT that keeps track of the driver's shared memory allocations | During a call to NdisMAllocateSharedMemory, NDIS detected that a previously-allocated shared memory page had been corrupted.
0x03 | Address of the miniport block | Page containing the shared memory | Virtual address of the shared memory | A driver called NdisMFreeSharedMemory[Async] with a shared memory pointer that had already been freed.
0x04 | Address of the NDIS_M_DRIVER_BLOCK | Address of the DRIVER_OBJECT | 0 | AddDevice was called with a driver that is not on the list of drivers that are registered with NDIS. (Only enabled on special instrumented NDIS.)
0x05 0x06 | Address of the miniport block | Address of the packet descriptor used by the driver | Address of the packet array that contained this packet descriptor | An Ethernet driver indicated receiving a packet by using a packet descriptor that is currently in use by the protocol stack.
0x07 | Address of the miniport block | Address of the packet descriptor used by the driver | Address of the packet array that contained this packet descriptor | An FDDI driver indicated receiving a packet by using a packet descriptor that is currently in use by the protocol stack.
0x08 | Address of the miniport block | Address of the NDIS_MINIPORT_INTERRUPT | 0 | A miniport driver did not deregister its interrupt during the halt process.
0x09 | Address of the miniport block | Address of the miniport's timer queue (NDIS_MINIPORT_TIMER) | 0 | A miniport driver halted without successfully canceling all its timers.
0x0A | Address of the NDIS_M_DRIVER_BLOCK | Address of the DRIVER_OBJECT | The ref count for the miniport driver | A miniport driver is getting unloaded prematurely.
0x0B | Address of the miniport block | Address of the NDIS_MINIPORT_INTERRUPT | 0 | A miniport driver failed its initialization without deregistering its interrupt.
0x0C | Address of the miniport block | Address of the miniport's timer queue (NDIS_MINIPORT_TIMER) | 0 | A miniport driver failed its initialization without successfully canceling all its timers.
0x0D | Address of the miniport block | Address of the NDIS_MINIPORT_INTERRUPT | 0 | A miniport driver did not deregister its interrupt during the halt process. (The halt was called from the initialize routine after the miniport driver returned success from its initialize handler.)
0x0E | Address of the miniport block | Address of the miniport's timer queue (NDIS_MINIPORT_TIMER) | 0 | A miniport driver halted without successfully canceling all its timers. (The halt was called from the initialize routine after the miniport driver returned success from its initialize handler.)
0x0F | Address of the miniport block | Reset status | AddressingReset (BOOLEAN) | A miniport driver called NdisMResetComplete without any pending reset request.
0x10 | Address of the miniport block | Address of the NDIS_MINIPORT_INTERRUPT | 0 | After resuming from a low power state, a miniport driver failed its initialization without deregistering its interrupt.
0x11 | Address of the miniport block | Address of the miniport's timer queue (NDIS_MINIPORT_TIMER) | 0 | After resuming from a low power state, a miniport driver failed its initialization without successfully canceling all its timers.
0x12 | Address of the miniport block | Address of the packet descriptor used by the driver | Address of the packet array that contained this packet descriptor | A miniport driver indicated receiving a packet by using a packet descriptor that is currently in use by the protocol stack.
0x13 | Address of the miniport block | Address of the packet descriptor used by the driver | Address of the packet array that contained this packet descriptor | A Token-Ring miniport driver indicated receiving a packet by using a packet descriptor that is currently in use by the protocol stack.

Cause

The specific cause of the error is indicated by Parameter 1.

If one of the bug check parameters specifies the address of the miniport block, you can obtain more information by using !ndiskd.miniport with this address.

If one of the bug check parameters specifies the address of the packet descriptor used by the driver, you can obtain more information by using !ndiskd.pkt with this address.

Comments

This bug check code only occurs on Windows .NET Server 2003 and later. In Windows 2000 and Windows XP, the corresponding code is bug check 0xD2 (BUGCODE_ID_DRIVER).


Bug Check 0x7D: INSTALL_MORE_MEMORY

The INSTALL_MORE_MEMORY bug check has a value of 0x0000007D. This indicates that there is not enough memory to boot Windows.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The number of physical pages found
2 | The lowest physical page
3 | The highest physical page
4 | 0

Cause

Windows does not have sufficient memory to complete the boot process.

Resolving the Problem

Install more memory.


Bug Check 0x7E: SYSTEM_THREAD_EXCEPTION_NOT_HANDLED

The SYSTEM_THREAD_EXCEPTION_NOT_HANDLED bug check has a value of 0x0000007E. This indicates that a system thread generated an exception which the error handler did not catch.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The exception code that was not handled
2 | The address at which the exception occurred
3 | The address of the exception record
4 | The address of the context record

Cause

This is a very common bug check. To interpret it, you must identify which exception was generated.

Common exception codes include:

  • 0x80000002: STATUS_DATATYPE_MISALIGNMENT

    An unaligned data reference was encountered.

  • 0x80000003: STATUS_BREAKPOINT

    A breakpoint or ASSERT was encountered when no kernel debugger was attached to the system.

  • 0xC0000005: STATUS_ACCESS_VIOLATION

    A memory access violation occurred.

For a complete list of exception codes, see the ntstatus.h file located in the inc directory of the Windows DDK.

Resolving the Problem

If you are not equipped to debug this problem, you should use some basic troubleshooting techniques. Make sure you have enough disk space. If a driver is identified in the bug check message, disable the driver or check with the manufacturer for driver updates. Try changing video adapters. Check with your hardware vendor for any BIOS updates. Disable BIOS memory options such as caching or shadowing.

If you plan to debug this problem, you may find it difficult to obtain a stack trace. Parameter 2 (the exception address) should pinpoint the driver or function that caused this problem.

If exception code 0x80000003 occurs, this indicates that a hard-coded breakpoint or assertion was hit, but the system was started with the /NODEBUG switch. This problem should rarely occur. If it occurs repeatedly, make sure a kernel debugger is connected and the system is started with the /DEBUG switch.

If exception code 0x80000002 occurs, the trap frame will supply additional information.

If the specific cause of the exception is unknown, the following should be considered:

Hardware incompatibility. First, make sure that any new hardware installed is listed on the Microsoft Windows Hardware Compatibility List (HCL).

Faulty device driver or system service. In addition, a faulty device driver or system service might be responsible for this error. Hardware issues, such as BIOS incompatibilities, memory conflicts, and IRQ conflicts can also generate this error.

If a driver is listed by name within the bug check message, disable or remove that driver. Disable or remove any drivers or services that were recently added. If the error occurs during the startup sequence and the system partition is formatted with NTFS file system, you might be able to use Safe Mode to rename or delete the faulty driver. If the driver is used as part of the system startup process in Safe Mode, you need to start the computer by using the Recovery Console to access the file.

If the problem is associated with Win32k.sys, the source of the error might be a third-party remote control program. If such software is installed, the service can be removed by starting the system using the Recovery Console and deleting the offending system service file.

Check the System Log in Event Viewer for additional error messages that might help pinpoint the device or driver that is causing bug check 0x1E. Disabling memory caching of the BIOS might also resolve the error. You should also run hardware diagnostics, especially the memory scanner, supplied by the system manufacturer. For details on these procedures, see the owner's manual for your computer.

The error that generates this message can occur after the first restart during Windows Setup, or after Setup is finished. A possible cause of the error is lack of disk space for installation and system BIOS incompatibilities. For problems during Windows installation that are associated with lack of disk space, reduce the number of files on the target hard disk. Check for and delete any unneeded temporary files, Internet cache files, application backup files, and .chk files containing saved file fragments from disk scans. You can also use another hard disk with more free space for the installation. BIOS problems can be resolved by upgrading the system BIOS version.


Bug Check 0x7F: UNEXPECTED_KERNEL_MODE_TRAP

The UNEXPECTED_KERNEL_MODE_TRAP bug check has a value of 0x0000007F. This indicates that a trap was generated by the Intel CPU and the kernel failed to catch this trap.

This could be either a bound trap (a trap the kernel is not permitted to catch) or a double fault (a fault that occurred while processing an earlier fault, which always results in a system crash).

Parameters

The first parameter displayed on the blue screen specifies the trap number.

Here are some of the most common trap codes:

  • 0x00000000, or Divide by Zero Error, is caused when a DIV instruction is executed and the divisor is zero. Memory corruption, other hardware problems, or software failures can cause this error.
  • 0x00000004, or Overflow, occurs when the processor executes a call to an interrupt handler when the overflow (OF) flag is set.
  • 0x00000005, or Bounds Check Fault, is generated when the processor, while executing a BOUND instruction, finds the operand exceeds the specified limits. A BOUND instruction is used to ensure that a signed array index is within a certain range.
  • 0x00000006, or Invalid Opcode, is generated when the processor attempts to execute an invalid instruction. This is generally caused when the instruction pointer has become corrupted and is pointing to the wrong location. The most common cause of this is hardware memory corruption.
  • 0x00000008, or Double Fault, is when an exception occurs while trying to call the handler for a prior exception. Normally, the two exceptions can be handled serially. However, there are several exceptions that cannot be handled serially, and in this situation the processor signals a double fault. There are two common causes of a double fault:
    1. A kernel stack overflow. This occurs when a guard page is hit, and then the kernel tries to push a trap frame. Since there is no stack left, a stack overflow results, causing the double fault. If you suspect this has occurred, use !thread to determine the stack limits, and then use KB (Display Stack Backtrace) with a large parameter (for example, kb 100) to display the full stack.
    2. A hardware problem.

The less-common trap codes include:

  • 0x00000001 — A system-debugger call
  • 0x00000003 — A debugger breakpoint
  • 0x00000007 — A hardware coprocessor instruction with no coprocessor present
  • 0x0000000A — A corrupted Task State Segment
  • 0x0000000B — An access to a memory segment that was not present
  • 0x0000000C — An access to memory beyond the limits of a stack
  • 0x0000000D — An exception not covered by some other exception; a protection fault that pertains to access violations for applications

For other trap numbers, consult an Intel architecture manual.

Cause

Bug check 0x7F usually occurs after the installation of faulty or mismatched hardware (especially memory) or in the event that installed hardware fails.

A double fault can occur when the kernel stack overflows. This can happen if multiple drivers are attached to the same stack. For example, two file system filter drivers can be attached to the same stack and then the file system can recurse back in, overflowing the stack.

Resolving the Problem

Debugging: Always begin with the !analyze extension.

If this is not sufficient, use the KV (Display Stack Backtrace) debugger command.

  • If KV shows a taskGate, then use the .tss (Display Task State Segment) command on the part before the colon.
  • If KV shows a trap frame, then use the .trap (Display Trap Frame) command to format the frame.
  • Otherwise, use the .trap (Display Trap Frame) command on the appropriate frame. (On x86 platforms, this frame is associated with the procedure NT!KiTrap.)

After this, use KV again to display the new stack.

Troubleshooting: If hardware was recently added to the system, remove it to see if the error recurs. If existing hardware has failed, remove or replace the faulty component. Run hardware diagnostics supplied by the system manufacturer, to determine which hardware component has failed. The memory scanner is especially important; faulty or mismatched memory can cause this bug check. For details on these procedures, see the owner's manual for your computer. Check that all adapter cards in the computer are properly seated. Use an ink eraser or an electrical contact treatment, available at electronics supply stores, to ensure adapter card contacts are clean.

If the error appears on a newly installed system, check the availability of updates for the BIOS, the SCSI controller or network cards. Updates of this kind are typically available on the web site or BBS of the hardware manufacturer.

Confirm that all hard disks, hard disk controllers, and SCSI adapters are listed on the Microsoft Windows Hardware Compatibility List (HCL).

If the error occurred after the installation of a new or updated device driver, the driver should be removed or replaced. If, under this circumstance, the error occurs during the startup sequence and the system partition is formatted with NTFS, you might be able to use Safe Mode to rename or delete the faulty driver. If the driver is used as part of the system startup process in Safe Mode, you need to start the computer using the Recovery Console in order to access the file. Also try restarting your computer, and press F8 at the character-based menu that displays the operating system choices. At the resulting Windows Advanced Options menu, choose the Last Known Good Configuration option. This option is most effective when only one driver or service is added at a time.

Overclocking (setting the CPU to run at speeds above the rated specification) can cause this error. If this has been done to the computer experiencing the error, return the CPU to the default clock speed setting.

Check the System Log in Event Viewer for additional error messages that might help pinpoint the device or driver that is causing the error. Disabling memory caching of the BIOS might also resolve it.

If you encountered this error while upgrading to a new version of Windows, it might be caused by a device driver, a system service, a virus scanner, or a backup tool that is incompatible with the new version. If possible, remove all third-party device drivers and system services and disable any virus scanners prior to upgrading. Contact the software manufacturer to obtain updates of these tools. Also make sure that you have installed the latest Windows Service Pack.

Finally, if all the above steps fail to resolve the error, take the system motherboard to a repair facility for diagnostic testing. A crack, a scratched trace, or a defective component on the motherboard can also cause this error.


Bug Check 0x80: NMI_HARDWARE_FAILURE

The NMI_HARDWARE_FAILURE bug check has a value of 0x00000080. This indicates that a hardware malfunction has occurred.

Parameters

None

Cause

This can be caused by a variety of hardware malfunctions. The exact cause is difficult to determine.

Resolving the Problem

Remove any hardware or drivers that have been recently installed. Make sure that all memory modules are of the same type.


Bug Check 0x81: SPIN_LOCK_INIT_FAILURE

The SPIN_LOCK_INIT_FAILURE bug check has a value of 0x00000081.

This bug check appears very infrequently.


Bug Check 0x82: DFS_FILE_SYSTEM

The DFS_FILE_SYSTEM bug check has a value of 0x00000082.

This bug check appears very infrequently.


Bug Check 0x85: SETUP_FAILURE

The SETUP_FAILURE bug check has a value of 0x00000085. This indicates that a fatal error occurred during setup.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of violation. Parameter 4 is not used. The meaning of the other parameters depends on the value of Parameter 1.

Parameter 1 | Parameter 2 | Parameter 3 | Cause of Error
0x0 0 0 The OEM HAL font is not a valid .fon format file, and so setup is unable to display text.

This indicates that vgaxxx.fon on the boot floppy or CD-ROM is damaged.

0x1 The precise video initialization failure:

0: NtCreateFile of \device\video0

1: IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES

2: IOCTL_VIDEO_QUERY_AVAIL_MODES

3: The desired video mode is not supported. This is indicative of an internal setup error.

4: IOCTL_VIDEO_SET_CURRENT_MODE (unable to set video mode)

5: IOCTL_VIDEO_MAP_VIDEO_MEMORY

6: IOCTL_VIDEO_LOAD_AND_SET_FONT

The status code from the NT API call, if appropriate Video initialization failed.

This may indicate that the disk containing vga.sys (or other video driver appropriate to the machine) is damaged, or that machine has video hardware that Windows cannot communicate with.

0x2 | 0 | 0 | Out of memory.
0x3 The precise keyboard initialization failure:

0: NtCreateFile of \device\KeyboardClass0 failed. (Setup did not find a keyboard connected to the computer.)

1: Unable to load keyboard layout DLL. (Setup could not load the keyboard layout file This indicates that the CD or floppy is missing a file — kbdus.dll for the U.S. release, or another layout DLL for localized releases.)

0 Keyboard initialization failed.

This may indicate that the disk containing the keyboard driver (i8042prt.sys or kbdclass.sys) is damaged, or that the machine has keyboard hardware that Windows cannot communicate with. It may also mean that the keyboard layout DLL could not be loaded.

0x4 0 0 Setup was unable to resolve the ARC device pathname of the device from which setup was started.

This is an internal setup error.

0x5 Reserved Reserved Partitioning sanity check failed.

This indicates a bug in a disk driver.


Bug Check 0x8B: MBR_CHECKSUM_MISMATCH

The MBR_CHECKSUM_MISMATCH bug check has a value of 0x0000008B. This indicates that a mismatch has occurred in the MBR checksum.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The disk signature from MBR
2 | The MBR checksum calculated by the OS Loader
3 | The MBR checksum calculated by the system
4 | Reserved

Cause

This error occurs during the boot process when the MBR checksum that Windows calculates does not match the checksum passed in by the loader.

This is usually an indication of a virus.

Resolving the Problem

There are many forms of viruses and not all can be detected. The newer ones usually can only be detected by a virus scanner that has recently been upgraded. You should boot with a write-protected disk containing a virus scanner and attempt to clean out the infection.


Bug Check 0x8E: KERNEL_MODE_EXCEPTION_NOT_HANDLED

The KERNEL_MODE_EXCEPTION_NOT_HANDLED bug check has a value of 0x0000008E. This indicates that a kernel-mode program generated an exception which the error handler did not catch.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The exception code that was not handled
2 | The address at which the exception occurred
3 | The trap frame
4 | Reserved

Cause

This is a very common bug check. To interpret it, you must identify which exception was generated.

Common exception codes include:

  • 0x80000002: STATUS_DATATYPE_MISALIGNMENT

    An unaligned data reference was encountered.

  • 0x80000003: STATUS_BREAKPOINT

    A breakpoint or ASSERT was encountered when no kernel debugger was attached to the system.

  • 0xC0000005: STATUS_ACCESS_VIOLATION

    A memory access violation occurred.

For a complete list of exception codes, see the ntstatus.h file located in the inc directory of the Windows DDK.

Resolving the Problem

If you are not equipped to debug this problem, you should use some basic troubleshooting techniques. Make sure you have enough disk space. If a driver is identified in the bug check message, disable the driver or check with the manufacturer for driver updates. Try changing video adapters. Check with your hardware vendor for any BIOS updates. Disable BIOS memory options such as caching or shadowing.

If you plan to debug this problem, you may find it difficult to obtain a stack trace. Parameter 2 (the exception address) should pinpoint the driver or function that caused this problem.

If exception code 0x80000003 occurs, this indicates that a hard-coded breakpoint or assertion was hit, but the system was started with the /NODEBUG switch. This problem should rarely occur. If it occurs repeatedly, make sure a kernel debugger is connected and the system is started with the /DEBUG switch.

If exception code 0x80000002 occurs, the trap frame will supply additional information.

If the specific cause of the exception is unknown, the following should be considered:

Hardware incompatibility. First, make sure that any new hardware installed is listed on the Microsoft Windows Hardware Compatibility List (HCL).

Faulty device driver or system service. In addition, a faulty device driver or system service might be responsible for this error. Hardware issues, such as BIOS incompatibilities, memory conflicts, and IRQ conflicts can also generate this error.

If a driver is listed by name within the bug check message, disable or remove that driver. Disable or remove any drivers or services that were recently added. If the error occurs during the startup sequence and the system partition is formatted with NTFS file system, you might be able to use Safe Mode to rename or delete the faulty driver. If the driver is used as part of the system startup process in Safe Mode, you need to start the computer by using the Recovery Console to access the file.

If the problem is associated with Win32k.sys, the source of the error might be a third-party remote control program. If such software is installed, the service can be removed by starting the system using the Recovery Console and deleting the offending system service file.

Check the System Log in Event Viewer for additional error messages that might help pinpoint the device or driver that is causing bug check 0x1E. Disabling memory caching of the BIOS might also resolve the error. You should also run hardware diagnostics, especially the memory scanner, supplied by the system manufacturer. For details on these procedures, see the owner's manual for your computer.

The error that generates this message can occur after the first restart during Windows Setup, or after Setup is finished. A possible cause of the error is lack of disk space for installation and system BIOS incompatibilities. For problems during Windows installation that are associated with lack of disk space, reduce the number of files on the target hard disk. Check for and delete any unneeded temporary files, Internet cache files, application backup files, and .chk files containing saved file fragments from disk scans. You can also use another hard disk with more free space for the installation. BIOS problems can be resolved by upgrading the system BIOS version.


Bug Check 0x8F: PP0_INITIALIZATION_FAILED

The PP0_INITIALIZATION_FAILED bug check has a value of 0x0000008F. This indicates that the Plug and Play Manager could not be initialized.

Parameters

None

Cause

An error occurred during Phase 0 initialization of the kernel-mode Plug and Play Manager.


Bug Check 0x90: PP1_INITIALIZATION_FAILED

The PP1_INITIALIZATION_FAILED bug check has a value of 0x00000090. This indicates that the Plug and Play Manager could not be initialized.

Parameters

None

Cause

An error occurred during Phase 1 initialization of the kernel-mode Plug and Play Manager.

Phase 1 is where most of the initialization is done, including setting up the registry files and other environment settings for drivers to call during the subsequent I/O initialization.


Bug Check 0x92: UP_DRIVER_ON_MP_SYSTEM

The UP_DRIVER_ON_MP_SYSTEM bug check has a value of 0x00000092. This indicates that a uniprocessor-only driver has been loaded on a multiprocessor system.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The base address of the driver
2 | Reserved
3 | Reserved
4 | Reserved

Cause

A driver that was compiled to only work on uniprocessor machines has been loaded, but Windows is running on a multiprocessor system with more than one active processor.


Bug Check 0x93: INVALID_KERNEL_HANDLE

The INVALID_KERNEL_HANDLE bug check has a value of 0x00000093. This indicates that an invalid or protected handle was passed to NtClose.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The handle passed to NtClose
2 | 0: the caller tried to close a protected handle 1: the caller tried to close an invalid handle
3 | Reserved
4 | Reserved

Cause

This error indicates that some kernel code (for example, a server, redirector, or another driver) attempted to close an invalid handle or a protected handle.


Bug Check 0x94: KERNEL_STACK_LOCKED_AT_EXIT

The KERNEL_STACK_LOCKED_AT_EXIT bug check has a value of 0x00000094. This indicates that a thread exited while its kernel stack was marked as not swappable

Parameters

None


Bug Check 0x96: INVALID_WORK_QUEUE_ITEM

The INVALID_WORK_QUEUE_ITEM bug check has a value of 0x00000096. This indicates that a queue entry was removed that contained a null pointer.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The address of the queue entry whose flink or blink field is NULL
2 | The address of the queue being referenced. Usually this is an ExWorkerQueue.
3 | The base address of the ExWorkerQueue array. (This will help determine if the queue in question is indeed an ExWorkerQueue. If it is, the offset from this parameter will isolate the queue.)
4 | Assuming the queue is an ExWorkerQueue, this is the address of the worker routine that would have been called if the work item had been valid. (This can be used to isolate the driver that is misusing the work queue.)

Cause

This error occurs when KeRemoveQueue removes a queue entry whose flink or blink field is NULL.

Any queue misuse can cause this, but most commonly this results from the misuse of worker thread work items.

The rule is that an entry on a queue may only be inserted on the list once. When an item is removed from a queue, its flink field is set to NULL. Then the second time this item is removed, this bug check occurs.

In most cases, the queue being referenced is an ExWorkerQueue (executive worker queue). To help identify the guilty driver, the address of the worker routine that would have been called if this work item had been valid is displayed as Parameter 4. However, if the queue being referenced is not an ExWorkerQueue, then this parameter will not be useful.


Bug Check 0x97: BOUND_IMAGE_UNSUPPORTED

The BOUND_IMAGE_UNSUPPORTED bug check has a value of 0x00000097.

This bug check appears very infrequently.


Bug Check 0x98: END_OF_NT_EVALUATION_PERIOD

The END_OF_NT_EVALUATION_PERIOD bug check has a value of 0x00000098. This indicates that the Windows trial period has ended.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The low-order 32 bits of the installation date
2 | The high-order 32 bits of the installation date
3 | The trial period (in minutes)
4 | Reserved

Cause

Your Windows installation is an evaluation unit with an expiration date. The trial period is over.


Bug Check 0x99: INVALID_REGION_OR_SEGMENT

The INVALID_REGION_OR_SEGMENT bug check has a value of 0x00000099. This indicates that ExInitializeRegion or ExInterlockedExtendRegion was called with an invalid set of parameters.

Parameters

None


Bug Check 0x9A: SYSTEM_LICENSE_VIOLATION

The SYSTEM_LICENSE_VIOLATION bug check has a value of 0x0000009A. This indicates that a violation of the software license agreement has occurred.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of violation. The meaning of the other parameters depends on the value of Parameter 1.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x00 | 0: The product should be WinNT 1: The product should be LanmanNT or ServerNT | A partial serial number | The first two characters of the product type from the product options | Offline product type changes have been attempted
0x01 | The registered evaluation time from source 1 | A partial serial number | The registered evaluation time from an alternate source | Offline changes to the NT evaluation unit time period have been attempted
0x02 | The status code associated with the open failure | 0 | 0 | The setup key could not be opened
0x03 | The status code associated with the key lookup failure | 0 | 0 | The SetupType value from the setup key is missing, so GUI setup mode could not be detected
0x04 | The status code associated with the key lookup failure | 0 | 0 | The SystemPrefix value from the setup key is missing
0x05 | (See the setup code) | An invalid value was found in licensed processors | The officially licensed number of processors | Offline changes to the number of licensed processors have been attempted
0x06 | The status code associated with the open failure | 0 | 0 | The ProductOptions key could not be opened
0x07 | The status code associated with the read failure | 0 | 0 | The ProductType value could not be read
0x08 | The status code associated with the Change Notify failure | 0 | 0 | Change Notify on ProductOptions failed
0x09 | The status code associated with the Change Notify failure | 0 | 0 | Change Notify on SystemPrefix failed
0x0A | 0 | 0 | 0 | An NTW system was converted to an NTS system
0x0B | The status code associated with the change failure | 0 | 0 | The reference of the setup key failed
0x0C | The status code associated with the change failure | 0 | 0 | The reference of the product options key failed
0x0D | The status code associated with the failure | 0 | 0 | The attempt to open ProductOptions in the worker thread failed
0x0F | The status code associated with the failure | 0 | 0 | The attempt to open the setup key failed
0x10 | The status code associated with the failure | 0: set value failed 1: Change Notify failed | 0 | A failure occured in the setup key worker thread
0x11 | The status code associated with the failure | 0: set value failed 1: Change Notify failed |  | A failure occured in the product options key worker thread
0x12 | The status code associated with the failure | 0 | 0 | Unable to open the LicenseInfoSuites key for the suite
0x13 | The status code associated with the failure | 0 | 0 | Unable to query the LicenseInfoSuites key for the suite
0x14 | The size of the memory allocation | 0 | 0 | Unable to allocate memory
0x15 | The status code associated with the failure | 0 | 0 | Unable to reset the ConcurrentLimit value for the suite key
0x16 | The status code associated with the failure | 0 | 0 | Unable to open the license key for a suite product
0x17 | The status code associated with the failure | 0 | 0 | Unable to reset the ConcurrentLimit value for a suite product
0x18 | The status code associated with the open failure | 0 | 0 | Unable to start the Change Notify for the LicenseInfoSuites
0x19 | 0 | 0 | 0 | A suite is running on a system that must be PDC
0x1A | The status code associated with the failure | 0 | 0 | A failure occurred when enumerating the suites

Cause

Windows has detected a violation of the software license agreement.

The user may have attempted to change the product type of an offline system, or change the trial period of an evaluation unit of Windows. See the parameter list for the precise violation.


Bug Check 0x9B: UDFS_FILE_SYSTEM

The UDFS_FILE_SYSTEM bug check has a value of 0x0000009B. This indicates that a problem occurred in the UDF file system.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Specifies source file and line number information. The high 16 bits (the first four hexadecimal digits after the "0x") identify the source file by its identifier number. The low 16 bits identify the source line in the file where the bug check occurred.
2 | If UdfExceptionFilter is on the stack, this parameter specifies the address of the exception record.
3 | If UdfExceptionFilter is on the stack, this parameter specifies the address of the context record.
4 | Reserved.

Cause

One possible cause of this bug check is disk corruption. Corruption in the file system or bad blocks (sectors) on the disk can induce this error. Corrupted SCSI and IDE drivers can also adversely affect the system's ability to read and write to the disk, thus causing the error.

Another possible cause is depletion of nonpaged pool memory. If the nonpaged pool memory is completely depleted, this error can stop the system. However, during the indexing process, if the amount of available nonpaged pool memory is very low, another kernel-mode driver requiring nonpaged pool memory can also trigger this error.

Resolving the Problem

To debug this problem: Use the .cxr (Display Context Record) command with Parameter 3, and then use kb (Display Stack Backtrace).

To resolve a disk corruption problem: Check Event Viewer for error messages from SCSI and FASTFAT (System Log) or Autochk (Application Log) that might help pinpoint the device or driver that is causing the error. Try disabling any virus scanners, backup programs, or disk defragmenter tools that continually monitor the system. You should also run hardware diagnostics supplied by the system manufacturer. For details on these procedures, see the owner's manual for your computer. Run Chkdsk /f /r to detect and resolve any file system structural corruption. You must restart the system before the disk scan begins on a system partition.

To resolve a nonpaged pool memory depletion problem: Either increase the amount of installed memory (which increases the quantity of nonpaged pool memory available to the kernel), or reduce the number of files on the SFM volume.


Bug Check 0x9C: MACHINE_CHECK_EXCEPTION

The MACHINE_CHECK_EXCEPTION bug check has a value of 0x0000009C. This indicates that a fatal machine check exception has occurred.

Parameters

The four parameters listed in the message have different meanings, depending on the processor type.

If the processor is based on x86 architecture, and has the MCE feature but not the MCA feature — for example, the Intel Pentium processor— the parameters have the following meaning.

Parameter | Description
1 | The low 32 bits of P5_MC_TYPE MSR
2 | Reserved
3 | The high 32 bits of P5_MC_ADDR MSR
4 | The low 32 bits of P5_MC_ADDR MSR

If the processor is based on x86 architecture, and has the MCA feature in addition to the MCE feature — for example, the Intel Pentium Pro processor— the parameters have the following meaning.

Parameter | Description
1 | The bank number
2 | The address field of MCi_ADDR MSR for the MCA bank that had the error
3 | The high 32 bits of MCi_STATUS MSR for the MCA bank that had the error
4 | The low 32 bits of MCi_STATUS MSR for the MCA bank that had the error

If the processor is based on IA-64 architecture— for example, the Intel Itanium processor — the parameters have the following meaning. Parameter 1 indicates the type of violation.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x1 | Address of the log | Size of the log | 0 |
0x2 | Address of the log | Size of the log | Error code | SAL returned an error for SAL_GET_STATEINFO while processing MCA.
0x3 | Address of the log | Size of the log | Error code | SAL returned an error for SAL_CLEAR_STATEINFO while processing MCA.
0x4 | Address of the log | Size of the log | 0 | FW reported a fatal MCA.
0x5 | Address of the log | Size of the log | 0 | Two possible causes: SAL reported a recoverable MCA, but this recovery is not currently supported; SAL generated an MCA but was unable to produce an error record.
0xB11 | Address of the log | Size of the log | 0 |
0xC | Address of the log | Size of the log | Error code | SAL returned an error for SAL_GET_STATEINFO while processing an INIT event.
0xD | Address of the log | Size of the log | Error code | SAL returned an error for SAL_CLEAR_STATEINFO while processing an INIT event.
0xE | Address of the log | Size of the log | 0 |


Bug Check 0x9F: DRIVER_POWER_STATE_FAILURE

The DRIVER_POWER_STATE_FAILURE bug check has a value of 0x0000009F. This indicates that the driver is in an inconsistent or invalid power state.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of violation.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x1 | Target (optional) | DeviceObject | DriverObject | The device object being freed still has an outstanding power request which it has not completed
0x2 | Target (optional) | DeviceObject | DriverObject | The device object completed the IRP for the system power state request, but failed to call PoStartNextPowerIrp
0x3 | Pointer to the target device object | Pointer to the device object | The IRP | The device driver did not properly set the IRP as "pending" or complete the IRP
0x100 | Pointer to the nonpaged device object | Pointer to the target device object | Pointer to the device object to notify | The device objects in the devnode were inconsistent in their use of DO_POWER_PAGABLE
0x101 | Child device object (FDO) | Child device object (PDO) | Parent device object | A parent device object has detected that a child device has not set the DO_POWER_PAGABLE bit

Cause

See the description of each code in the Parameters section for a description of the cause.

The errors that result in a Parameter 1 value of 0x3, 0x100, or 0x101 only exist in Windows 2000. In Windows XP and Windows .NET Server 2003, these errors have been superseded by Driver Verifier tests. For details, see the Driver Verifier section of the Windows DDK.


Bug Check 0xA0: INTERNAL_POWER_ERROR

The INTERNAL_POWER_ERROR bug check has a value of 0x000000A0. This indicates that the power policy manager experienced a fatal error.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 is the only parameter of interest; this identifies the exact violation.

Parameter 1 | Cause of Error
0x1 | An error handling a power IRP
0x2 | An unhandled exception
0x3 | Failure writing the processor context record to the hibernation file
0x4 | Failure writing the I/O context to the hibernation file
0x5 | Failure writing the checksum to the hibernation file

Cause

For the precise cause, look at the value of Parameter 1.

Resolving the Problem

If Parameter 1 is equal to 0x2, an unhandled exception occurred. To debug this, take the following actions.

Debugging a Bug Check 0xA0, Subcode 0x2:

  1. Dump the stack. Look for the function ntoskrnl!PopExceptionFilter. The first argument to this function is of type PEXCEPTION_POINTERS. Record the value of this argument.
  2. In the debugger, use the DT (Display Type) command:
    dt nt!_EXCEPTION_POINTERS argument

    where argument is the value found in the previous step. This will display the structure; record the value of the context record.

  3. Then use the .cxr (Display Context Record) command:
    .cxr record

    where record is the context record found in the previous step. This will set the Register Context to the proper value.

  4. Now you can use a variety of commands to analyze the source of the error. Start with KB (Display Stack Backtrace) .


Bug Check 0xA1: PCI_BUS_DRIVER_INTERNAL

The PCI_BUS_DRIVER_INTERNAL bug check has a value of 0x000000A1. This indicates that the PCI Bus driver detected inconsistency problems in its internal structures and could not continue.

Parameters

None


Bug Check 0xA2: MEMORY_IMAGE_CORRUPT

The MEMORY_IMAGE_CORRUPT bug check has a value of 0x000000A2. This indicates that corruption has been detected in the image of an executable in memory.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of violation. The meaning of the other parameters depends on the value of Parameter 1.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x02 | If Parameter 3 is zero: The page number in the table page which failed If Parameter 3 is nonzero: The page number with the failing page run index | Zero, or the index which failed to match the run | 0 | A table page check failure occurred
0x03 | The starting physical page number of the range | The length (in pages) of the range | The page number of the table page containing this run | The checksum for the range of memory listed is incorrect

Cause

A cyclic redundancy check (CRC) check on the memory range has failed.

On a system wake operation, various regions of memory may be CRC'd to guard against memory failures.


Bug Check 0xA3: ACPI_DRIVER_INTERNAL

The ACPI_DRIVER_INTERNAL bug check has a value of 0x000000A3. This indicates that the ACPI driver detected an internal inconsistency.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Reserved
2 | Reserved
3 | Reserved
4 | Reserved

Cause

An inconsistency in the ACPI driver is so severe that continuing to run would cause serious problems.

One possible source of this problem is a BIOS error.


Bug Check 0xA4: CNSS_FILE_SYSTEM_FILTER

The CNSS_FILE_SYSTEM_FILTER bug check has a value of 0x000000A4. This indicates that a problem occurred in the CNSS file system filter.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Specifies source file and line number information. The high 16 bits (the first four hexadecimal digits after the "0x") identify the source file by its identifier number. The low 16 bits identify the source line in the file where the bug check occurred.
2 | Reserved
3 | Reserved
4 | Reserved

One possible cause of this bug check is depletion of nonpaged pool memory. If the nonpaged pool memory is completely depleted, this error can stop the system. However, during the indexing process, if the amount of available nonpaged pool memory is very low, another kernel-mode driver requiring nonpaged pool memory can also trigger this error.

Resolving the Problem

To resolve a nonpaged pool memory depletion problem: Either increase the amount of installed memory. This will increase the quantity of nonpaged pool memory available to the kernel.


Bug Check 0xA5: ACPI_BIOS_ERROR

The ACPI_BIOS_ERROR bug check has a value of 0x000000A5. This indicates that the ACPI BIOS of the computer is not fully compliant with the ACPI specification.

Parameters

The four bug check parameters are displayed on the blue screen. Parameter 1 indicates the nature of the incompatibility. The meaning of the other parameters depends on the value of Parameter 1.

If the BIOS incompatibility is related to Plug and Play or Power Management, the following parameters are used:

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x01 | ACPI's deviceExtension | ACPI's ResourceList | 0: No resource list found 1: No IRQ resource found in list | ACPI cannot find the SCI Interrupt vector in the resources handed to it when ACPI is started.
0x02 |  |  |  | (See the table later on this page)
0x03 | The ACPI object that was being run | The return value from the interpreter | The name of the control method (in ULONG format) | ACPI tried to run a control method while creating device extensions to represent the ACPI namespace, but this control method failed.
0x04 | The ACPI extension to which the _PRW belongs | Pointer to the method | The DataType returned (see amli.h) | ACPI evaluated a _PRW and expected to find an integer as a package element.
0x05 | The ACPI extension to which the _PRW belongs | Pointer to the _PRW | The number of elements in the _PRW | ACPI evaluated a _PRW, and the package that came back failed to contain at least two elements. The ACPI specification requires that two elements always be present in a _PRW.
0x06 | The ACPI Extension to which the _PRx belongs | Pointer to the _PRx | Pointer to the name of the object to look for | ACPI tried to find a named object, but could not find it.
0x07 | The ACPI extension to which the method belongs | Pointer to the method | The DataType returned (see amli.h) | ACPI evaluated a method and expected to receive a buffer in return. However, the method returned some other data type.
0x08 | The ACPI extension to which the method belongs | Pointer to the method | The DataType returned (see amli.h) | ACPI evaluated a method and expected to receive an integer in return. However, the method returned some other data type.
0x09 | The ACPI extension to which the method belongs | Pointer to the method | The DataType returned (see amli.h) | ACPI evaluated a method and expected to receive a package in return. However, the method returned some other data type.
0x0A | The ACPI Extension to which the method belongs | Pointer to the method | The DataType returned (see amli.h) | ACPI evaluated a method and expected to receive a string in return. However, the method returned some other data type.
0x0B | The ACPI Extension to which which the _EJD belongs | The status returned by the interpreter | The name of the object ACPI is trying to find | ACPI cannot find the object referenced by an _EJD string.
0x0C | The ACPI extension for which ACPI found a dock device | Pointer to the _EJD method | 0: BIOS does not claim system is dockage 1: Duplicate device extensions for dock device | ACPI provides faulty or insufficient information for dock support.
0x0D | The ACPI extension that ACPI needs the object for | The (ULONG) name of the method ACPI looked for | 0: Base case 1: Conflict | ACPI could not find a required method or object in the namespace This bug check code is used if there is no _HID or _ADR present.
0x0E | The NS PowerResource that ACPI needs the object for | The (ULONG) name of the method ACPI looked for | 0: Base case | ACPI could not find a required method or object in the namespace for a power resource (or entity other than a "device"). This bug check code is used if there is no _ON, _OFF, or _STA present for a power resource.
0x0F | The current buffer that ACPI was parsing | The buffer's tag | The specified length of the buffer | ACPI could not parse the resource descriptor.
0x10 |  |  |  | (See the table later on this page)
0x11 |  |  |  | (See the table later on this page)

If an interrupt routing failure or incompatibility has occurred, the following parameters are used:

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x2001 | InterruptModel (integer) | The return value from the interpreter | Pointer to the PIC control method | ACPI tried to evaluate the PIC control method and but failed.
0x10001 | Pointer to the device object | Pointer to the parent of the device object | Pointer to the _PRT object (See Comments below) | ACPI tried to do interrupt routing, but failed.
0x10002 | Pointer to the device object | Pointer to the string name ACPI was are looking for, but could not find | Pointer to the _PRT object (See Comments below) | ACPI could not find the link node referenced in a _PRT.
0x10003 | Pointer to the device object | The Device ID / function number. This DWORD is encoded as follows: bits 5:0 are the PCI device number, and bits 8:6 are the PCI function number | Pointer to the _PRT object (See Comments below) | ACPI could not find a mapping in the _PRT package for a device.
0x10005 | Pointer to the _PRT object (See Comments below) | Pointer to the current _PRT element (This is an index into the _PRT) | The Device ID / function number. This DWORD is encoded as follows: bits 15:0 are the PCI function number, and bits 31:16 are the PCI device number | ACPI found an entry in the _PRT for which the function ID is not all F's. (The generic format for a _PRT entry is that the device number is specified, but the function number is not.)
0x10006 | Pointer to the link node (This device is missing the _DIS method) | 0 | 0 | ACPI found a link node, but cannot disable it. (Link nodes must be disabled to allow for reprogramming.)
0x10007 | The vector that couldn't be found | 0 | 0 | The _PRT contained a reference to a vector not described in the I/O APIC entry's MAPIC table.

If a miscellaneous failure or incompatibility has occurred, the following parameters are used:

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x20000 | The I/O port in the Fixed Table | 0 | 0 | The PM_TMR_BLK entry in the Fixed ACPI Description Table does not point to a working ACPI timer block.

If Parameter 1 equals 0x02, this means that the ACPI BIOS could not process the resource list for the PCI root buses. In this case, Parameter 3 specifies the exact problem, and the remaining parameters can be interpreted as follows:

Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
The ACPI extension for the PCI bus | 0x0 | Pointer to the QUERY_RESOURCES IRP | ACPI cannot convert the BIOS' resource list into the proper Windows format. This probably represents a flaw in the BIOS' list encoding procedure.
The ACPI extension for the PCI bus | 0x1 | Pointer to the QUERY_RESOURCE_REQUIREMENTS IRP | ACPI cannot convert the BIOS' resource list into the proper Windows format. This probably represents a flaw in the BIOS' list encoding procedure.
The ACPI extension for the PCI bus | 0x2 | 0 | ACPI found an empty resource list.
The ACPI extension for the PCI bus | 0x3 | Pointer to the PNP CRS descriptor | ACPI could not find the current bus number in the CRS.
The ACPI extension for the PCI bus | Pointer to the resource list for PCI | Pointer to the E820 memory table | There is an overlap between the list of resources that PCI claims to decode and the list of memory regions reported by the E820 BIOS interface. (This kind of conflict is never permitted.)

If Parameter 1 equals 0x10, this means that the ACPI BIOS could not determine the system-to-device-state mapping correctly. In this case, Parameter 3 specifies the exact problem, and the remaining parameters can be interpreted as follows:

Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
The ACPI extension whose mapping is needed | 0x0 | The DEVICE_POWER_STATE (this is "x+1") | The _PRx was mapped back to a non-supported S-state.
The ACPI extension whose mapping is needed | 0x1 | The SYSTEM_POWER_STATE that cannot be mapped | ACPI cannot find a D-state to associate with the S-state.
The ACPI extension whose mapping is needed | 0x2 | The SYSTEM_POWER_STATE that cannot be mapped | The device claims to be able to wake the system when the system is in this S-state, but the system doesn't actually support this S-state.

If Parameter 1 equals 0x11, this means that the system could not enter ACPI mode. In this case, Parameter 2 specifies the exact problem, and the remaining parameters can be interpreted as follows:

Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x0 | 0 | 0 | System could not initialize AML interpreter.
0x1 | 0 | 0 | System could not find RSDT.
0x2 | 0 | 0 | System could not allocate critical driver structures.
0x3 | 0 | 0 | System could not load RSDT.
0x4 | 0 | 0 | System could not load DDBs.
0x5 | 0 | 0 | System cannot connect Interrupt vector.
0x6 | 0 | 0 | SCI_EN never becomes set in PM1 Control Register.
0x7 | Pointer to the table that had a bad checksum | Creator revision | Table checksum is incorrect.
0x8 | Pointer to the table that ACPI failed to load | Creator revision | Failed to load DDB.
0x9 | FADT version | 0 | Unsupported firmware version.
0xA | 0 | 0 | System could not find MADT.
0xB | 0 | 0 | System could not find any valid Local SAPIC structures in the MADT.

Cause

The error is indicated by the value of Parameter 1.

Resolving the Problem

If you are debugging this error, use the !analyze -v extension. This will display all the relevant data — device extensions, nsobjects, or whatever is appropriate to the specific error.

If you are not performing debugging, this error indicates that you need to obtain a new BIOS. Contact your vendor or visit the web to get a new BIOS.

If you are unable to obtain an updated BIOS, or the latest BIOS supplied by your vendor is still not ACPI compliant, you can turn off ACPI mode during text-mode setup. To do this, simply press the F7 key when you are prompted to install storage drivers. The system will not notify you that the F7 key was pressed, but it will silently disable ACPI and allow you to continue your installation.

Comments

A PCI routing table (_PRT) is the ACPI BIOS object that specifies how all the PCI devices are connected to the interrupt controllers. A machine with multiple PCI busses may have multiple _PRTs.

A _PRT can be displayed in the debugger by using the !acpikd.nsobj extension with the address of the _PRT object as its argument.


Bug Check 0xA7: BAD_EXHANDLE

The BAD_EXHANDLE bug check has a value of 0x000000A7. This indicates that the kernel-mode handle table detected an inconsistent handle table entry state.

Parameters

None


Bug Check 0xAB: SESSION_HAS_VALID_POOL_ON_EXIT

The SESSION_HAS_VALID_POOL_ON_EXIT bug check has a value of 0x000000AB. This indicates that a session unload occurred while a session driver still held memory.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The session ID
2 | The number of paged pool bytes that are leaking
3 | The number of nonpaged pool bytes that are leaking
4 | The total number of paged and nonpaged allocations that are leaking. (The number of nonpaged allocations are in the upper half of this word, and paged allocations are in the lower half of this word.)

Cause

This error is caused by a session driver not freeing its pool allocations prior to a session unload. This indicates a bug in win32k.sys, atmfd.dll, rdpdd.dll, or a video driver.


Bug Check 0xAC: HAL_MEMORY_ALLOCATION

The HAL_MEMORY_ALLOCATION bug check has a value of 0x000000AC. This indicates that the hardware abstraction layer (HAL) was unable to obtain sufficient memory.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The allocation size
2 | 0
3 | A pointer to a string containing the file name
4 | Reserved

Cause

The HAL was unable to obtain non-paged memory pool for a system critical requirement.

These critical memory allocations are made early in system initialization, and this bug check is not expected. It probably indicates some other critical error such as pool corruption or massive consumption.


Bug Check 0xB4: VIDEO_DRIVER_INIT_FAILURE

The VIDEO_DRIVER_INIT_FAILURE bug check has a value of 0x000000B4. This indicates that Windows was unable to enter graphics mode.

Parameters

None

Cause

The system was not able to go into graphics mode because no display drivers were able to start.

This usually occurs when no video miniport drivers are able to load successfully.


Bug Check 0xB8: ATTEMPTED_SWITCH_FROM_DPC

The ATTEMPTED_SWITCH_FROM_DPC bug check has a value of 0x000000B8. This indicates that an illegal operation was attempted by a delayed procedure call (DPC) routine.

Parameters

None

Cause

A wait operation, attach process, or yield was attempted from a DPC routine. This is an illegal operation.

Resolving the Problem

The stack track will lead to the offending code and original DPC routine.


Bug Check 0xB9: CHIPSET_DETECTED_ERROR

The CHIPSET_DETECTED_ERROR bug check has a value of 0x000000B9.

This bug check appears very infrequently.


Bug Check 0xBA: SESSION_HAS_VALID_VIEWS_ON_EXIT

The SESSION_HAS_VALID_VIEWS_ON_EXIT bug check has a value of 0x000000BA. This indicates that a session driver still had mapped views when the session unloaded.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The session ID
2 | The number of mapped views that are leaking
3 | The address of this session's mapped views table
4 | The size of this session's mapped views table

Cause

This error is caused by a session driver not unmapping its mapped views prior to a session unload. This indicates a bug in win32k.sys, atmfd.dll, rdpdd.dll, or a video driver.


Bug Check 0xBB: NETWORK_BOOT_INITIALIZATION_FAILED

The NETWORK_BOOT_INITIALIZATION_FAILED bug check has a value of 0x000000BB. This indicates that Windows failed to successfully boot off a network.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 The part of network initialization that failed. Possible values are:

1: Failure while updating the registry.

2: Failure while starting the network stack. Windows sends IOCTLs to the redirector and datagram receiver, then waits for the redirector to be ready. If it is not ready within a certain period of time, this error is issued.

3: Failure while sending the DHCP IOCTL to TCP. This is how Windows informs the transport of its IP address.

2 | The failure status
3 | Reserved
4 | Reserved

Cause

This error is caused when Windows is booting off a network, and a critical function fails during I/O initialization.


Bug Check 0xBC: NETWORK_BOOT_DUPLICATE_ADDRESS

The NETWORK_BOOT_DUPLICATE_ADDRESS bug check has a value of 0x000000BC. This indicates that a duplicate IP address was assigned to this machine while booting off a network.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The IP address, shown as a DWORD. An address of the form aa.bb.cc.dd will appear as 0xDDCCBBAA.
2 | The hardware address of the other machine. (For an Ethernet connection, see the following note.)
3 | The hardware address of the other machine. (For an Ethernet connection, see the following note.)
4 | The hardware address of the other machine. (For an Ethernet connection, this will be zero.)

Note When Parameter 4 equals zero, this indicates an Ethernet connection. In that case, the MAC address will be stored in Parameter 2 and Parameter 3. An Ethernet MAC address of the form aa-bb-cc-dd-ee-ff will cause Parameter 2 to equal 0xAABBCCDD, and Parameter 3 to equal 0xEEFF0000.

Cause

This error indicates that when TCP/IP sent out an ARP for its IP address, it got a response from another machine indicating a duplicate IP address.

When Windows is booting off a network, this is a fatal error.


Bug Check 0xBE: ATTEMPTED_WRITE_TO_READONLY_MEMORY

The ATTEMPTED_WRITE_TO_READONLY_MEMORY bug check has a value of 0x000000BE. This is issued if a driver attempts to write to a read-only memory segment.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Virtual address of attempted write
2 | PTE contents
3 | Reserved
4 | Reserved

If the driver responsible for the error can be identified, its name is printed on the blue screen and stored in memory at the location (PUNICODE_STRING) KiBugCheckDriver.


Bug Check 0xBF: MUTEX_ALREADY_OWNED

The MUTEX_ALREADY_OWNED bug check has a value of 0x000000BF. This indicates that a thread attempted to acquire ownership of a mutex it already owned.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The address of the mutex
2 | The thread that caused the error
3 | 0
4 | Reserved


Bug Check 0xC1: SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION

The SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION bug check has a value of 0x000000C1. This indicates that the driver wrote to an invalid section of the special memory pool.

Parameters

The following parameters are displayed on the blue screen. Parameter 4 indicates the type of violation.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
Address that the driver tried to free | Reserved | 0 | 0x20 | A driver attempted to free pool which was not allocated
Address that the driver tried to free | Bytes requested | Bytes calculated (actually given to the caller) | 0x21, 0x22 | A driver attempted to free a bad address
Address that the driver tried to free | Address where bits are corrupted | Reserved | 0x23 | A driver freed an address while nearby bytes on same page have been corrupted
Address that the driver tried to free | Address where bits are corrupted | Reserved | 0x24 | A driver freed an address when bytes after end of allocation have been overwritten
Current IRQL | Pool type | Number of bytes | 0x30 | A driver attempted to allocate pool at incorrect IRQL
Current IRQL | Pool type | Address that the driver tried to free | 0x31 | A driver attempted to free pool at incorrect IRQL

The _POOL_TYPE codes are enumerated in ntddk.h. In particular, zero indicates nonpaged pool and one indicates paged pool.

Cause

A driver has written to an invalid section of the special memory pool.

Resolving the Problem

Obtain a backtrace of the current thread. This backtrace will usually reveal the source of the error.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.


Bug Check 0xC2: BAD_POOL_CALLER

The BAD_POOL_CALLER bug check has a value of 0x000000C2. This indicates that the current thread is making a bad pool request.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of violation.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x00 | 0 | Pool type | Pool tag | The current thread requested a zero-byte pool allocation.
0x01, 0x02, or 0x04 | Pointer to pool header | First part of pool header contents | 0 | The pool header has been corrupted.
0x06 | Reserved | Pointer to pool header | Pool header contents | The current thread attempted to free pool which was already freed.
0x07 | Reserved | Memory contents of the pool block | Pointer to pool header | The current thread attempted to free pool which was already freed.
0x08 | Current IRQL | Pool type | Size of allocation, in bytes | The current thread attempted to allocate pool at an invalid IRQL.
0x09 | Current IRQL | Pool type | Address of pool | The current thread attempted to free pool at an invalid IRQL.
0x0A | Address of pool | Allocator's tag | Tag being used in the attempted free | The current thread attempted to free pool memory using the wrong tag. (The memory may belong to another component.)
0x0B, 0x0C, or 0x0D | Address of pool | Pool allocation's tag | Bad quota process pointer | The current thread attempted to release a quota on a corrupted pool allocation.
0x40 | Starting address | Start of system address space | 0 | The current thread attempted to free kernel pool at user-mode address.
0x41 | Starting address | Physical page frame | Highest physical page frame | The current thread attempted to free a nonallocated nonpaged pool address.
0x42 or 0x43 | Address being freed | 0 | 0 | The current thread attempted to free a virtual address that was never in any pool.
0x50 | Starting address | Start offset in pages from beginning of paged pool | Size of paged pool, in bytes | The current thread attempted to free a nonallocated paged pool address.
0x60 | Starting address | 0 | 0 | The current thread attempted to free an invalid contiguous memory address. (The caller of MmFreeContiguousMemory is passing a bad pointer.)
0x99 | Address being freed | 0 | 0 | The current thread attempted to free pool with an invalid address. (This code can also indicate corruption in pool header.)
0x9A | Pool type | Number of bytes requested | Pool tag | The current thread marked an allocation request MUST_SUCCEED. (This pool type is no longer supported.)
0x9B | Pool type | Number of bytes requested | Caller's address | The current thread attempted to allocate a pool with a tag of zero. (This would be untrackable, and possibly corrupt the existing tag tables.)
0x9C | Pool type | Number of bytes requested | Caller's address | The current thread attempted to allocate a pool with a tag of "BIG". (This would be untrackable, and possibly corrupt the existing tag tables.)

The _POOL_TYPE codes are enumerated in ntddk.h. In particular, zero indicates nonpaged pool and one indicates paged pool.

Cause

A bad pool request has been made by the current thread.

Resolving the Problem

Activate Driver Verifier to obtain more information about these errors. For details, see the Driver Verifier section of the Windows DDK.


Bug Check 0xC4: DRIVER_VERIFIER_DETECTED_VIOLATION

The DRIVER_VERIFIER_DETECTED_VIOLATION bug check has a value of 0x000000C4. This is the general bug check code for fatal errors found by Driver Verifier.

Parameters

The four bug check parameters are displayed on the blue screen. Parameter 1 identifies the type of violation.

The following parameters are general Driver Verifier violation codes:

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x00 | Current IRQL | Pool type | 0 | The driver requested a zero-byte pool allocation.
0x01 | Current IRQL | Pool type | Size of allocation, in bytes | The driver attempted to allocate paged memory at an IRQL above APC_LEVEL.
0x02 | Current IRQL | Pool type | Size of allocation, in bytes | The driver attempted to allocate nonpaged memory at an IRQL above DISPATCH_LEVEL.
0x10 | Bad Address | 0 | 0 | The driver attempted to free an address that was not returned from an allocate call.
0x11 | Current IRQL | Pool type | Address of pool | The driver attempted to free paged pool at an IRQL above APC_LEVEL.
0x12 | Current IRQL | Pool type | Address of pool | The driver attempted to free nonpaged pool at an IRQL above DISPATCH_LEVEL.
0x13 or 0x14 | Reserved | Pointer to pool header | Pool header contents | The driver attempted to free memory pool which was already freed.
0x15 | Timer entry | Pool type (-1 for special pool) | Pool address being freed | The driver attempted to free pool which contains an active timer.
0x16 | Reserved | Pool address | 0 | The driver attempted to free pool at a bad address (or passed invalid parameters to a memory routine).
0x17 | Resource entry | Pool type (-1 for special pool) | Pool address being freed | The driver attempted to free pool which contains an active ERESOURCE.
0x30 | Current IRQL | Requested IRQL | 0 | The driver passed an invalid parameter to KeRaiseIrql. (The parameter was either a value lower than the current IRQL, or a value higher than HIGH_LEVEL. This may be the result of using an uninitialized parameter.)
0x31 | Current IRQL | Requested IRQL | 0 | The driver passed an invalid parameter to KeLowerIrql. (The parameter was either a value higher than the current IRQL, or a value higher than HIGH_LEVEL. This may be the result of using an uninitialized parameter.)
0x32 | Current IRQL | Spin lock address | 0 | The driver called KeReleaseSpinLock at an IRQL other than DISPATCH_LEVEL. (This may be due to a double-release of a spin lock.)
0x33 | Current IRQL | Fast mutex address | 0 | The driver attempted to acquire fast mutex at an IRQL above APC_LEVEL.
0x34 | Current IRQL | Fast mutex address | 0 | The driver attempted to release fast mutex at an IRQL other than APC_LEVEL.
0x35 | Current IRQL | Spin lock address | Old IRQL | The kernel released a spin lock when not at DISPATCH_LEVEL.
0x36 | Current IRQL | Spin lock number | Old IRQL | The kernel released a queued spin lock when not at DISPATCH_LEVEL.
0x37 | Current IRQL | Thread APC disable count | Resource | The driver tried to acquire a resource, but APCs are not disabled.
0x38 | Current IRQL | Thread APC disable count | Resource | The driver tried to release a resource, but APCs are not disabled.
0x39 | Current IRQL | Thread APC disable count | Mutex | The driver tried to acquire a mutex "unsafe", but the IRQL was not APC_LEVEL on entry.
0x3A | Current IRQL | Thread APC disable count | Mutex | The driver tried to release a mutex "unsafe", but the IRQL was not APC_LEVEL on entry.
0x3B | Current IRQL | Object to wait on | Timeout parameter | The driver called KeWaitXxx at an IRQL of DISPATCH_LEVEL or higher. (This is permitted only if the driver already owns the DISPATCHER lock and it passes a timeout value of zero to the routine.)
0x3C | Handle passed to routine | Object type | 0 | The driver called ObReferenceObjectByHandle with a bad handle.
0x3D | 0 | 0 | Address of the bad resource | The driver passed a bad (unaligned) resource to ExAcquireResourceExclusive.
0x40 | Current IRQL | Spin lock address | 0 | The driver called KeAcquireSpinLockAtDpcLevel at an IRQL other than DISPATCH_LEVEL.
0x41 | Current IRQL | Spin lock address | 0 | The driver called KeReleaseSpinLockFromDpcLevel at an IRQL other than DISPATCH_LEVEL.
0x42 | Current IRQL | Spin lock address | 0 | The driver called KeAcquireSpinLock at an IRQL above DISPATCH_LEVEL.
0x6F | MDL address | Physical page being locked | Highest physical page in the system | The driver passed a page to MmProbeAndLockPages that was not in the PFN database. (This often results from a driver that attempts to lock its own private dualport RAM. Such behavior can corrupt memory on machines with noncontiguous physical RAM.)
0x70 | Current IRQL | MDL address | Access mode | The driver called MmProbeAndLockPages at an IRQL above DISPATCH_LEVEL.
0x71 | Current IRQL | MDL address | Process address | The driver called MmProbeAndLockProcessPages at an IRQL above DISPATCH_LEVEL.
0x72 | Current IRQL | MDL address | Process address | The driver called MmProbeAndLockSelectedPages at an IRQL above DISPATCH_LEVEL.
0x73 | Current IRQL | Low 32 bits of the physical address (all 64 bits in Win64) | Number of bytes | The driver called MmMapIoSpace at an IRQL above DISPATCH_LEVEL.
0x74 | Current IRQL | MDL address | Access mode | The driver called MmMapLockedPages in kernel mode at an IRQL above DISPATCH_LEVEL.
0x75 | Current IRQL | MDL address | Access mode | The driver called MmMapLockedPages in user mode at an IRQL above APC_LEVEL.
0x76 | Current IRQL | MDL address | Access mode | The driver called MmMapLockedPagesSpecifyCache in kernel mode at an IRQL above DISPATCH_LEVEL.
0x77 | Current IRQL | MDL address | Access mode | The driver called MmMapLockedPagesSpecifyCache in user mode at an IRQL above APC_LEVEL.
0x78 | Current IRQL | MDL address | 0 | The driver called MmUnlockPages at an IRQL above DISPATCH_LEVEL.
0x79 | Current IRQL | Virtual address being unmapped | MDL address | The driver called MmUnmapLockedPages in kernel mode at an IRQL above DISPATCH_LEVEL.
0x7A | Current IRQL | Virtual address being unmapped | MDL address | The driver called MmUnmapLockedPages in user mode at an IRQL above APC_LEVEL.
0x7B | Current IRQL | Virtual address being unmapped | Number of bytes | The driver called MmUnmapIoSpace at an IRQL above APC_LEVEL.
0x7C | MDL address | MDL flags | 0 | The driver called MmUnlockPages, and passed an MDL whose pages were never successfully locked.
0x7D | MDL address | MDL flags | 0 | The driver called MmUnlockPages, and passed an MDL whose pages are from nonpaged pool. (These should never be unlocked.)
0x80 | Current IRQL | Event address | 0 | The driver called KeSetEvent at an IRQL above DISPATCH_LEVEL.
0x81 | MDL address | MDL flags | 0 | The driver called MmMapLockedPages. (You should use MmMapLockedPagesSpecifyCache instead, with the BugCheckOnFailure parameter set to FALSE.)
0x82 | MDL address | MDL flags | 0 | The driver called MmMapLockedPagesSpecifyCache with the BugCheckOnFailure parameter equal to TRUE. (This parameter should be set to FALSE.)
0x83 | Start of physical address range to map | Number of bytes to map | First page frame number that isn't locked down | The driver called MmMapIoSpace without having locked down the MDL pages.
0x84 | Start of physical address range to map | Number of bytes to map | First page frame number that is on the free list | The driver called MmMapIoSpace without having locked down the MDL pages (or after freeing the MDL pages).
0x85 | MDL address | Number of pages to map | First page frame number that isn't locked down | The driver called MmMapLockedPages without having locked down the MDL pages.
0x86 | MDL address | Number of pages to map | First page frame number that is on the free list | The driver called MmMapLockedPages without having locked down the MDL pages (or after freeing the MDL pages).
0x87 | Base physical page of the existing mapping (Shift left for physical address) | Number of pages already mapped in the existing mapping | MEMORY_CACHING_TYPE of the existing mapping | The driver called MmMapIoSpace, but the caller's cache type conflicts with an existing mapping.
0x88 | Base physical page of the requested mapping (Shift left for physical address) | Number of pages in the requested mapping | MEMORY_CACHING_TYPE of the requested mapping | The driver called MmMapIoSpace to map a physical range as non-cached or write-combined, but the caller's physical range already has an existing cached mapping.
0x89 | MDL address | Pointer to the non-memory page in the MDL | The non-memory page number in the MDL | An MDL is not marked as "I/O", but it contains non-memory page addresses.
0x8A | MDL address | Base physical page of the requested mapping (Shift left for physical address) | MEMORY_CACHING_TYPE of the requested mapping | The driver called MmMapLockedPagesXxx to map a physical range as non-cached or write-combined, but the caller's physical range already has an existing cached mapping.
0x90 | Reserved | Reserved | Reserved | The driver switched stacks, and the current stack is neither a thread stack nor a DPC stack. (Typically, the driver doing this should be on the stack obtained by the KB debugger command.)

The following parameters are used only when the Memory Pool Tracking option of Driver Verifier is active.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x51 | Base address of allocation | Corrupt address | Number of charged bytes | The driver attempted to free memory after having written past the end of the allocation.
0x52 | Base address of allocation | Reserved | Number of charged bytes | The driver attempted to free memory after having written past the end of the allocation.
0x53, 0x54, or 0x59 | Base address of allocation | Reserved | Reserved | The driver attempted to free memory after having written past the end of the allocation.
0x60 | Bytes allocated from paged pool | Bytes allocated from nonpaged pool | Total number of unfreed allocations | The driver is unloading without first freeing all its memory pools.
0x61 | Bytes allocated from paged pool | Bytes allocated from nonpaged pool | Total number of unfreed allocations | The driver is unloading, but it is simultaneously attempting to allocate pool in another thread.

The following parameters are used only when the Deadlock Detection option of Driver Verifier is active. This option is only available in Windows XP and later.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x1000 | Address of the resource | Reserved | Reserved | Self-deadlock: The current thread has tried to recursively acquire a resource.
0x1001 | Address of the resource that was the final cause of the deadlock | Reserved | Reserved | Deadlock: A lock hierarchy violation has been found. (Use the !deadlock extension for further information.)
0x1002 | Address of the resource | Reserved | Reserved | Uninitialized resource: A resource has been acquired without having been initialized first.
0x1003 | Address of the resource that is being released deadlocked | Address of the resource which should have been released first | Reserved | Unexpected release: A resource has been released out of the proper order.
0x1004 | Address of the resource | Address of the thread that acquired the resource | Address of the current thread | Unexpected thread: The wrong thread is releasing a resource.
0x1005 | Address of the resource | Reserved | Reserved | Multiple initialization: A resource is being initialized more than once.
0x1006 | Address of the thread being deleted | Address of the resource owned by the thread | Reserved | Thread holds resources: A thread is being deleted without first releasing its resources.
0x1007 | Address of the resource | Reserved | Reserved | Unacquired resource: A resource is being released without having first been acquired.

The following parameters are used only when the Disk Integrity Verification option of Driver Verifier is active. This option is only available in Windows .NET Server 2003 and later.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0xA0 | Pointer to the IRP making the read or write request | Device object of the lower device | Number of the sector in which the error was detected | A cyclic redundancy check (CRC) error was detected on a hard disk.

The _POOL_TYPE codes are enumerated in ntddk.h. In particular, zero indicates nonpaged pool and one indicates paged pool.

Cause

See the description of each code in the Parameters section for a description of the cause.

Resolving the Problem

This bug check can only occur when Driver Verifier has been instructed to monitor one or more drivers. If you did not intend to use Driver Verifier, you should deactivate it. You might consider removing the driver which caused this problem as well.

If you are the driver writer, use the information obtained through this bug check to fix the bugs in your code.

After a Memory Allocation Tracking bug check, use the following command in the kernel debugger:

kd> dp ViBadDriver L1; dS @$p

This will return the name of the driver causing the error.

Then use the the !verifier extension:

kd> !verifier 3 drivername.sys

This will return information about the leaked memory allocations.

For full details on Driver Verifier, see the Windows DDK.


Bug Check 0xC5: DRIVER_CORRUPTED_EXPOOL

The DRIVER_CORRUPTED_EXPOOL bug check has a value of 0x000000C5. This indicates that the system attempted to access invalid memory at a process IRQL that was too high.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL at time of reference
3 | 0: Read 1: Write
4 | Address that referenced memory

Cause

The kernel attempted to access pageable memory (or perhaps completely invalid memory) when the IRQL was too high. The ultimate cause of this problem is almost certainly a driver that has corrupted the system pool.

In most cases, this bug check results if a driver corrupts a small allocation (less than PAGE_SIZE). Larger allocations result in bug check 0xD0 (DRIVER_CORRUPTED_MMPOOL).

Resolving the Problem

If you have recently installed any new software, check to see if it is properly installed. Check for updated drivers on the manufacturer's website.

To debug this error, use the special pool option of Driver Verifier. If this fails to reveal the guilty driver, use the Global Flags utility to enable the special pool by pool tag.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.


Bug Check 0xC6: DRIVER_CAUGHT_MODIFYING_FREED_POOL

The DRIVER_CAUGHT_MODIFYING_FREED_POOL bug check has a value of 0x000000C6. This indicates that the driver attempted to access a freed memory pool.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | 0: Read 1: Write
3 | 0: Kernel mode 1: User mode
4 | Reserved

Comments

The faulty component will be displayed in the current kernel stack. This driver should be either replaced or debugged.


Bug Check 0xC7: TIMER_OR_DPC_INVALID

The TIMER_OR_DPC_INVALID bug check has a value of 0x000000C7. This is issued if a kernel timer or delayed procedure call (DPC) is found somewhere in memory where it is not permitted.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | 0: Timer object 1: DPC object 2: DPC routine
2 | Address of object
3 | Beginning of memory range checked
4 | End of memory range checked

Cause

This condition is usually caused by a driver failing to cancel a timer or DPC before freeing the memory where it resides. When Driver Verifier is active, it will catch such errors and issue this bug check.

Resolving the Problem

If you are the driver writer, use the information obtained through this bug check to fix the bugs in your code.

If you are a system administrator, you should unload the driver if the problem persists.

For full details on Driver Verifier, see the Windows DDK.


Bug Check 0xC8: IRQL_UNEXPECTED_VALUE

The IRQL_UNEXPECTED_VALUE bug check has a value of 0x000000C8. This indicates that the processor's IRQL is not what it should be at this time.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The value of (Current IRQL << 16) | (Expected IRQL << 8) | UniqueValue
2 | Zero, or APC->KernelRoutine
3 | Zero, or APC
4 | Zero, or APC->NormalRoutine

You can determine "UniqueValue" by computing (Parameter 1 AND 0xFF). If "UniqueValue" is either zero or one, Parameter 2, Parameter 3, and Parameter 4 will equal the indicated APC pointers. Otherwise, these parameters will equal zero.

Cause

This error is usually caused by a device driver or another lower-level program that changed IRQL for some period and did not restore the original IRQL at the end of that period. For example, the routine may have acquired a spin lock and failed to release it.


Bug Check 0xC9: DRIVER_VERIFIER_IOMANAGER_VIOLATION

The DRIVER_VERIFIER_IOMANAGER_VIOLATION bug check has a value of 0x000000C9. This is the bug check code for all Driver Verifier I/O Verification violations.

Parameters

When Driver Verifier is active and I/O Verification is selected, various I/O violations will cause this bug check to be issued. The following parameters will be displayed on the blue screen. Parameter 1 identifies the type of violation.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x01 | Address of IRP being freed | 0 | 0 | The driver attempted to free an object whose type is not IO_TYPE_IRP.
0x02 | Address of IRP being freed | 0 | 0 | The driver attempted to free an IRP that is still associated with a thread.
0x03 | Address of IRP being sent | 0 | 0 | The driver passed IoCallDriver an IRP Type not equal to IRP_TYPE.
0x04 | Address of DeviceObject | 0 | 0 | The driver passed IoCallDriver an invalid device object.
0x05 | Address of DeviceObject associated with offending driver | IRQL before IoCallDriver | IRQL after IoCallDriver | The IRQL changed during a call to the driver dispatch routine.
0x06 | IRP status | Address of IRP being completed | 0 | The driver called IoCompleteRequest with a status marked as pending (or equal to -1).
0x07 | Address of cancel routine | Address of IRP being completed | 0 | The driver called IoCompleteRequest while its cancel routine was still set.
0x08 | Address of DeviceObject | IRP major function code | Exception status code | The driver passed IoBuildAsynchronousFsdRequest an invalid buffer.
0x09 | Address of DeviceObject | I/O control code | Exception status code | The driver passed IoBuildDeviceIoControlRequest an invalid buffer.
0x0A | Address of DeviceObject | 0 | 0 | The driver passed IoInitializeTimer a device object with an already-initialized timer.
0x0C | Address of I/O status block | 0 | 0 | The driver passed an I/O status block to an IRP, but this block is allocated on a stack which has already unwound past that point.
0x0D | Address of user event object | 0 | 0 | The driver passed a user event to an IRP, but this event is allocated on a stack which has already unwound past that point.
0x0E | Current IRQL | Address of IRP | 0 | The driver called IoCompleteRequest while the IRQL was above dispatch level.
0x0F | Address of the DeviceObject to which the IRP is being sent | Pointer to the IRP | Pointer to FileObject | The driver sent a create request with a file object that has been closed, or that had its open canceled.

In addition to the errors mentioned in the previous table, there are a number of I/O Verification errors that will cause Driver Verifier to halt the system, but which are not actually bug checks.

These errors cause messages to be displayed on the blue screen, in a crash dump file, and in a kernel debugger. These messages will appear differently in each of these locations. When these errors occur, the hexadecimal bug check code 0xC9 and the bug check string DRIVER_VERIFIER_IOMANAGER_VIOLATION do not appear on the blue screen or in the debugger, although they will appear in a crash dump file.

On the blue screen, the following data will be displayed:

  • The message IO SYSTEM VERIFICATION ERROR.
  • The message WDM DRIVER ERROR XXX, where XXX is a hexadecimal code representing the specific error. (See the table below for a list of the I/O error codes and their meanings.)
  • The name of the driver which caused the error.
  • The address in the driver's code where the error was detected (Parameter 2).
  • A pointer to the IRP (Parameter 3).
  • A pointer to the DeviceObject (Parameter 4).

If a kernel-mode crash dump has been enabled, the following information will appear in the crash dump file:

  • The message BugCheck 0xC9 (DRIVER_VERIFIER_IOMANAGER_VIOLATION).
  • The hexadecimal I/O error code. (See the table below for a list of the I/O error codes and their meanings.)
  • The address in the driver's code where the error was detected.
  • A pointer to the IRP.
  • A pointer to the DeviceObject.

If a kernel debugger is attached to the system which has caused this violation, the following information will be sent to the debugger:

  • The message WDM DRIVER ERROR, along with an assessment of the severity of the error.
  • The name of the driver which caused the error.
  • A descriptive string which explains the cause of this error. Often additional information is passed along, such as a pointer to the IRP. (See the table below for a list of these descriptive strings and what additional information is specified.)
  • A query for further action. Possible responses are b (break), i (ignore), z (zap), r (remove), or d (disable). Instructing the operating system to continue allows you to see what would happen "down the line" if this error had not occurred. Of course, this often will lead to additional bug checks. The "zap" option will actually remove the breakpoint that caused this error to be discovered.

Note No other bug checks can be ignored in this manner. Only this kind of I/O Verification errors can be ignored, and even these errors can only be ignored if a kernel debugger is attached.

The following table lists those I/O Verification errors that can appear in Windows 2000 and later. In Windows 2000, these errors will only be displayed if I/O Verification is set to Level 2.

I/O Error Code | Severity | Cause of Error
0x200 | Unknown | This code covers all unknown I/O Verification errors.
0x201 | Fatal error | A device is deleting itself while there is another device beneath it in the driver stack. This may be because the caller has forgotten to call IoDetachDevice first, or the lower driver may have incorrectly deleted itself.
0x202 | Fatal error | A driver has attempted to detach from a device object that is not attached to anything. This may occur if detach was called twice on the same device object. (Device object specified.)
0x203 | Fatal error | A driver has called IoCallDriver without setting the CancelRoutine in the IRP to NULL. (IRP specified.)
0x204 | Fatal error | The caller has passed in NULL as a DeviceObject. This is fatal. (IRP specified.)
0x205 | Fatal error | The caller is forwarding an IRP that is currently queued beneath it. The code handling IRPs returning STATUS_PENDING in this driver appears to be broken. (IRP specified.)
0x206 | Fatal error | The caller has incorrectly forwarded an IRP (control field not zeroed). The driver should use IoCopyCurrentIrpStackLocationToNext or IoSkipCurrentIrpStackLocation. (IRP specified.)
0x207 | Fatal error | The caller has manually copied the stack and has inadvertently copied the upper layer's completion routine. Please use IoCopyCurrentIrpStackLocationToNext. (IRP specified.)
0x208 | Fatal error | This IRP is about to run out of stack locations. Someone may have forwarded this IRP from another stack. (IRP specified.)
0x209 | Fatal error | The caller is completing an IRP that is currently queued beneath it. The code handling IRPs returning STATUS_PENDING in this driver appears to be broken. (IRP specified.)
0x20A | Fatal error | The caller of IoFreeIrp is freeing an IRP that is still in use. (Original IRP and IRP in use specified.)
0x20B | Fatal error | The caller of IoFreeIrp is freeing an IRP that is still in use. (IRP specified.)
0x20C | Fatal error | The caller of IoFreeIrp is freeing an IRP that is still queued against a thread. (IRP specified.)
0x20D | Fatal error | The caller of IoInitializeIrp has passed an IRP that was allocated with IoAllocateIrp. This is illegal and unnecessary, and has caused a quota leak. Check the documentation for IoReuseIrp if this IRP is being recycled.
0x20E | Non-fatal error | A PNP IRP has an invalid status. (Any PNP IRP must have its status initialized to STATUS_NOT_SUPPORTED.) (IRP specified.)
0x20F | Non-fatal error | A Power IRP has an invalid status. (Any Power IRP must have its status initialized to STATUS_NOT_SUPPORTED.) (IRP specified.)
0x210 | Non-fatal error | A WMI IRP has an invalid status. (Any WMI IRP must have its status initialized to STATUS_NOT_SUPPORTED.) (IRP specified.)
0x211 | Non-fatal error | The caller has forwarded an IRP while skipping a device object in the stack. The caller is probably sending IRPs to the PDO instead of to the device returned by IoAttachDeviceToDeviceStack. (IRP specified.)
0x212 | Non-fatal error | The caller has trashed or has not properly copied the IRP's stack. (IRP specified.)
0x213 | Non-fatal error | The caller has changed the status field of an IRP it does not understand. (IRP specified.)
0x214 | Non-fatal error | The caller has changed the information field of an IRP it does not understand. (IRP specified.)
0x215 | Non-fatal error | A non-successful non-STATUS_NOT_SUPPORTED IRP status for IRP_MJ_PNP is being passed down stack. (IRP specified.) Failed PNP IRPs must be completed.
0x216 | Non-fatal error | The previously-set IRP_MJ_PNP status has been converted to STATUS_NOT_SUPPORTED. (IRP specified.)
0x217 | Non-fatal error | The driver has not handled a required IRP. The driver must update the status of the IRP to indicate whether or not it has been handled. (IRP specified.)
0x218 | Non-fatal error | The driver has responded to an IRP that is reserved for other device objects elsewhere in the stack. (IRP specified.)
0x219 | Non-fatal error | A non-successful non-STATUS_NOT_SUPPORTED IRP status for IRP_MJ_POWER is being passed down stack. (IRP specified.) Failed POWER IRPs must be completed.
0x21A | Non-fatal error | The previously-set IRP_MJ_POWER status has been converted to STATUS_NOT_SUPPORTED. (IRP specified.)
0x21B | Non-fatal error | A driver has returned a suspicious status. This is probably due to an uninitialized variable bug in the driver. (IRP specified.)
0x21C | Warning | The caller has copied the IRP stack but not set a completion routine. This is inefficient -- use IoSkipCurrentIrpStackLocation instead. (IRP specified.)
0x21D | Fatal error | An IRP dispatch handler has not properly detached from the stack below it upon receiving a remove IRP. (DeviceObject, Dispatch Routine, and IRP specified.)
0x21E | Fatal error | An IRP dispatch handler has not properly deleted its device object upon receiving a remove IRP. (DeviceObject, Dispatch Routine, and IRP specified.)
0x21F | Non-fatal error | A driver has not filled out a dispatch routine for a required IRP major function. (IRP specified.)
0x220 | Non-fatal error | IRP_MJ_SYSTEM_CONTROL has been completed by someone other than the ProviderId. This IRP should either have been completed earlier or should have been passed down. (IRP specified, along with the DeviceObject where it was targeted.)
0x221 | Fatal error | An IRP dispatch handler for a PDO has deleted its device object, but the hardware has not been reported as missing in a bus relations query. (DeviceObject, Dispatch Routine, and IRP specified.)
0x222 | Fatal error | A Bus Filter's IRP dispatch handler has detached upon receiving a remove IRP when the PDO is still alive. Bus Filters must clean up in FastIoDetach callbacks. (DeviceObject, Dispatch Routine, and IRP specified.)
0x223 | Fatal error | An IRP dispatch handler for a bus filter has deleted its device object, but the PDO is still present. Bus filters must clean up in FastIoDetach callbacks. (DeviceObject, Dispatch Routine, and IRP specified.)
0x224 | Fatal error | An IRP dispatch handler has returned a status that is inconsistent with the IRP's IoStatus.Status field. (Dispatch handler routine, IRP, IRP's IoStatus.Status, and returned Status specified.)
0x225 | Non-fatal error | An IRP dispatch handler has returned a status that is illegal (0xFFFFFFFF). This is probably due to an uninitialized stack variable. To debug this error, use the LN (List Nearest Symbols) command with the specified address.
0x226 | Fatal error | An IRP dispatch handler has returned without passing down or completing this IRP, or someone forgot to return STATUS_PENDING. (IRP specified.)
0x227 | Fatal error | An IRP completion routine is in pageable code. (This is never permitted.) (Routine and IRP specified.)
0x228 | Non-fatal error | A driver's completion routine has not marked the IRP pending if the PendingReturned field was set in the IRP passed to it. This may cause the OS to hang, especially if an error is returned by the stack. (Routine and IRP specified.)
0x229 | Fatal error | A cancel routine has been set for an IRP that is currently being processed by drivers lower in the stack, possibly stomping their cancel routine. (Routine and IRP specified.)
0x22A | Non-fatal error | The physical device object (PDO) has not responded to a required IRP. (IRP specified.)
0x22B | Non-fatal error | The physical device object (PDO) has forgotten to fill out the device relation list with the PDO for the TargetDeviceRelation query. (IRP specified.)
0x22C | Fatal error | The code implementing the TargetDeviceRelation query has not called ObReferenceObject on the PDO. (IRP specified.)
0x22D | Non-fatal error | The caller has completed a IRP_MJ_PNP it didn't understand instead of passing it down. (IRP specified.)
0x22E | Non-fatal error | The caller has completed a successful IRP_MJ_PNP instead of passing it down. (IRP specified.)
0x22F | Non-fatal error | The caller has completed an untouched IRP_MJ_PNP (instead of passing the IRP down), or non-PDO has failed the IRP using illegal value of STATUS_NOT_SUPPORTED. (IRP specified.)
0x230 | Non-fatal error | The caller has completed an IRP_MJ_POWER it didn't understand instead of passing it down. (IRP specified.)
0x231 | Fatal error | The caller has completed a successful IRP_MJ_POWER instead of passing it down. (IRP specified.)
0x232 | Non-fatal error | The caller has completed an untouched IRP_MJ_POWER (instead of passing the IRP down), or non-PDO has failed the IRP using illegal value of STATUS_NOT_SUPPORTED. (IRP specified.)
0x233 | Non-fatal error | The version field of the query capabilities structure in a query capabilities IRP was not properly initialized. (IRP specified.)
0x234 | Non-fatal error | The size field of the query capabilities structure in a query capabilities IRP was not properly initialized. (IRP specified.)
0x235 | Non-fatal error | The address field of the query capabilities structure in a query capabilities IRP was not properly initialized to -1. (IRP specified.)
0x236 | Non-fatal error | The UI Number field of the query capabilities structure in a query capabilities IRP was not properly initialized to -1. (IRP specified.)
0x237 | Fatal error | A driver has sent an IRP that is restricted for system use only. (IRP specified.)
0x238 | Warning | The caller of IoInitializeIrp has passed an IRP that was allocated with IoAllocateIrp. This is illegal, unnecessary, and negatively impacts performance in normal use. Check the documentation for IoReuseIrp if this IRP is being recycled.
0x239 | Warning | The caller of IoCompleteRequest is completing an IRP that has never been forwarded via a call to IoCallDriver or PoCallDriver. This may be a bug. (IRP specified.)
0x23A | Fatal error | A driver has forwarded an IRP at an IRQL that is illegal for this major code. (IRP specified.)
0x23B | Non-fatal error | The caller has changed the status field of an IRP it does not understand. (IRP specified.)

The following table lists additional I/O Verification errors that can appear in Windows XP and later. Some of these errors will only be revealed if Enhanced I/O Verification is activated.

I/O Error Code | Severity | Cause of Error
0x23C | Fatal error | A driver has completed an IRP without setting the cancel routine in the IRP to NULL. (IRP specified.)
0x23D | Non-fatal error | A driver has returned STATUS_PENDING but did not mark the IRP pending via a call to IoMarkIrpPending. (IRP specified.)
0x23E | Non-fatal error | A driver has marked an IRP pending but didn't return STATUS_PENDING. (IRP specified.)
0x23F | Fatal error | A driver has not inherited the DO_POWER_PAGABLE bit from the stack it has attached to. (DeviceObject specified.)
0x240 | Fatal error | A driver is attempting to delete a device object that has already been deleted via a prior call to IoDeleteDevice.
0x241 | Fatal error | A driver has detached its device object during a surprise remove IRP. (IRP and DeviceObject specified.)
0x242 | Fatal error | A driver has deleted its device object during a surprise remove IRP. (IRP and DeviceObject specified.)
0x243 | Fatal error | A driver has failed to clear the DO_DEVICE_INITIALIZING flag at the end of AddDevice. (DeviceObject specified.)
0x244 | Fatal error | A driver has not copied either the DO_BUFFERED_IO or the DO_DIRECT_IO flag from the device object it is attaching to. (DeviceObject specified.)
0x245 | Fatal error | A driver has set both the DO_BUFFERED_IO and the DO_DIRECT_IO flags. These flags are mutually exclusive. (DeviceObject specified.)
0x246 | Fatal error | A driver has failed to copy the DeviceType field from the device object it is attaching to. (DeviceObject specified.)
0x247 | Fatal error | A driver has failed an IRP that cannot legally be failed. (IRP specified.)
0x248 | Fatal error | A driver has added a device object that is not a PDO to a device relations query. (IRP and DeviceObject specified.)
0x249 | Non-fatal error | A driver has enumerated two child PDOs that returned identical Device IDs. (Both DeviceObjects specified.)
0x24A | Fatal error | A driver has mistakenly called a file I/O function at an IRQL other than PASSIVE_LEVEL.
0x24B | Fatal error | A driver has completed an IRP_MN_QUERY_DEVICE_RELATIONS request of type TargetRelations as successful, but did not properly fill out the request or forward the IRP to the underlying hardware stack. (DeviceObject specified.)
0x24C | Non-fatal error | A driver has returned STATUS_PENDING but did not mark the IRP pending by a call to IoMarkIrpPending. (IRP specified.)
0x24D | Fatal error | A driver has passed an invalid device object to a function that requires a PDO. (DeviceObject specified.)

Cause

See the description of each code in the Parameters section for a description of the cause.

Resolving the Problem

This bug check can only occur when Driver Verifier has been instructed to monitor one or more drivers. If you did not intend to use Driver Verifier, you should deactivate it. You might consider removing the driver which caused this problem as well.

If you are the driver writer, use the information obtained through this bug check to fix the bugs in your code.

For full details on Driver Verifier, see the Windows DDK.


Bug Check 0xCA: PNP_DETECTED_FATAL_ERROR

The PNP_DETECTED_FATAL_ERROR bug check has a value of 0x000000CA. This indicates that the Plug and Play Manager encountered a severe error, probably as a result of a flawed Plug and Play driver.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 identifies the type of violation.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x01 | Address of newly-reported PDO | Address of older PDO which has been duplicated | Reserved | Duplicate PDO: A specific instance of a driver has enumerated multiple PDOs with identical device ID and unique IDs.
0x02 | Address of purported PDO | Address of driver object | Reserved | Invalid PDO: An API which requires a PDO has been called with random memory, or with an FDO, or with a PDO which hasn't been initialized. (An uninitialized PDO is one that has not been returned to Plug and Play by QueryDeviceRelation or QueryBusRelations.)
0x03 | Address of PDO whose IDs were queried | Address of ID buffer | 1: DeviceID 2: UniqueID 3: HardwareIDs 4: CompatibleIDs | Invalid ID: An enumerator has returned an ID which contains illegal characters or isn't properly terminated. (IDs must contain only characters in the ranges 0x20 - 0x2B and 0x2D - 0x7F.)
0x04 | Address of PDO with DOE_DELETE_PENDING set | Reserved | Reserved | Invalid enumeration of deleted PDO: An enumerator has returned a PDO which it had previously deleted using IoDeleteDevice.
0x05 | Address of PDO | Reserved | Reserved | PDO freed while linked in devnode tree: The object manager reference count on a PDO dropped to zero while the devnode was still linked in the tree. (This usually indicates that the driver is not adding a reference when returning the PDO in a query IRP.)


Bug Check 0xCB: DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS

The DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS bug check has a value of 0x000000CB. This indicates that a driver or the I/O manager failed to release locked pages after an I/O operation.

Parameters

The four parameters listed in the message can have two possible meanings.

If a driver locked these pages, the parameters have the following meaning:

Parameter | Description
1 | Calling address in the driver that locked the pages
2 | Caller of the calling address in driver that locked the pages
3 | Address of the MDL containing the locked pages
4 | Number of locked pages

If the driver responsible for the error can be identified, its name is printed on the blue screen and stored in memory at the location (PUNICODE_STRING) KiBugCheckDriver.

If the I/O manager locked these pages, the parameters have the following meaning:

Parameter | Description
1 | Address of the dispatch routine of the top driver on the stack to which the IRP was sent
2 | Address of the device object of the top driver on the stack to which the IRP was sent
3 | Address of the MDL containing the locked pages
4 | Number of locked pages

Comments

This bug check is issued only if the registry value \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\TrackLockedPages is equal to DWORD 1. If this value is not set, the system will issue the less-informative bug check 0x76 (PROCESS_HAS_LOCKED_PAGES).


Bug Check 0xCC: PAGE_FAULT_IN_FREED_SPECIAL_POOL

The PAGE_FAULT_IN_FREED_SPECIAL_POOL bug check has a value of 0x000000CC. This indicates that the system has referenced memory which was earlier freed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the driver responsible for the error can be identified, its name is printed on the blue screen and stored in memory at the location (PUNICODE_STRING) KiBugCheckDriver.

Cause

The system has accessed memory in the special pool which was already freed by a driver. This usually indicates a system-driver synchronization problem.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.

Comments

This cannot be protected by try - except; it can only be protected by a probe.


Bug Check 0xCD: PAGE_FAULT_BEYOND_END_OF_ALLOCATION

The PAGE_FAULT_BEYOND_END_OF_ALLOCATION bug check has a value of 0x000000CD. This indicates that the system accessed memory beyond the end of some driver's pool allocation.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the driver responsible for the error can be identified, its name is printed on the blue screen and stored in memory at the location (PUNICODE_STRING) KiBugCheckDriver.

Cause

The driver allocated n bytes of memory from the special pool. Subsequently, the system referenced more than n bytes from this pool. This usually indicates a system-driver synchronization problem.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.

Comments

This cannot be protected by try - except; it can only be protected by a probe.


Bug Check 0xCE: DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS

The DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS bug check has a value of 0x000000CE. This indicates that a driver failed to cancel pending operations before unloading.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the driver responsible for the error can be identified, its name is printed on the blue screen and stored in memory at the location (PUNICODE_STRING) KiBugCheckDriver.

Cause

This driver failed to cancel lookaside lists, DPCs, worker threads, or other such items before unload.


Bug Check 0xCF: TERMINAL_SERVER_DRIVER_MADE_INCORRECT_MEMORY_REFERENCE

The TERMINAL_SERVER_DRIVER_MADE_INCORRECT_MEMORY_REFERENCE bug check has a value of 0x000000CF. This indicates that a driver has been incorrectly ported to the terminal server.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the driver responsible for the error can be identified, its name is printed on the blue screen and stored in memory at the location (PUNICODE_STRING) KiBugCheckDriver.

Cause

The driver is referencing session space addresses from the system process context. This probably results from the driver queuing an item to a system worker thread.

This driver needs to comply with Terminal Server's memory management rules.


Bug Check 0xD0: DRIVER_CORRUPTED_MMPOOL

The DRIVER_CORRUPTED_MMPOOL bug check has a value of 0x000000D0. This indicates that the system attempted to access invalid memory at a process IRQL that was too high.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL at time of reference
3 | 0: Read 1: Write
4 | Address that referenced memory

Cause

The kernel attempted to access pageable memory (or perhaps completely invalid memory) when the IRQL was too high. The ultimate cause of this problem is almost certainly a driver that has corrupted the system pool.

In most cases, this bug check results if a driver corrupts a large allocation (PAGE_SIZE or larger). Smaller allocations result in bug check 0xC5 (DRIVER_CORRUPTED_EXPOOL).

Resolving the Problem

If you have recently installed any new software, check to see if it is properly installed. Check for updated drivers on the manufacturer's website.

To debug this error, use the special pool option of Driver Verifier. If this fails to reveal the guilty driver, use the Global Flags utility to enable the special pool by pool tag.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.

An alternate method is to open the \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management registry key. In this key, create or edit the ProtectNonPagedPool value, and set it equal to DWORD 1. Then reboot. Then the system will unmap all freed nonpaged pool. This will prevent drivers from corrupting the pool. (This does not protect the pool from DMA hardware, however.)


Bug Check 0xD1: DRIVER_IRQL_NOT_LESS_OR_EQUAL

The DRIVER_IRQL_NOT_LESS_OR_EQUAL bug check has a value of 0x000000D1. This indicates that a kernel-mode driver attempted to access pageable memory at a process IRQL that was too high.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL at time of reference
3 | 0: Read 1: Write
4 | Address that referenced memory

Cause

A driver tried to access an address that is pageable (or that is completely invalid) while the IRQL was too high.

This bug check is usually caused by drivers that have used improper addresses.

Resolving the Problem

To begin debugging, use a kernel debugger to get a stack trace.


Bug Check 0xD2: BUGCODE_ID_DRIVER

The BUGCODE_ID_DRIVER bug check has a value of 0x000000D2. This indicates that a problem occurred with an NDIS driver.

Parameters

Before this bug check occurs, a message is sent to the DbgPrint buffer. If a debugger is connected, this message will be displayed.

This message indicates the type of violation. The meaning of the bug check parameters depends on this message.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Message and Cause
Address of the miniport block | Number of bytes requested | 0 | 1 | Allocating shared memory at raised IRQL. A driver called NdisMAllocateSharedMemory when the IRQL was DISPATCH_LEVEL or higher.
Address of the miniport block | The Status value submitted to NdisMResetComplete | The AddressingReset value submitted to NdisMResetComplete | 0 | Completing reset when one is not pending. A driver called NdisMResetComplete but no reset was pending.
Address of the miniport block | Memory page containing address being freed | Address of shared memory signature | Virtual address being freed | Freeing shared memory not allocated. A driver called NdisMFreeSharedMemory[Async] with an address that is not located in NDIS shared memory.
Address of the miniport block | Address of the packet that is incorrectly included in the packet array | Address of the packet array | Number of packets in the array | Indicating packet not owned by it. The miniport's packet array is corrupt.
Address of the MiniBlock | Address of the driver object | 0 | 0 | ndisAddDevice: AddDevice called with a MiniBlock that is not on ndisMiniDriverList.
Address of the MiniBlock | The MiniBlock's reference count | 0 | 0 | NdisMUnload: MiniBlock is getting unloaded but it is still on ndisMiniDriverList.
Address of the miniport block | Memory page | Wrapper context | Address of shared memory signature | Overwrote past allocated shared memory. The address being written to is not located in NDIS shared memory.

In the following instances of this bug check, the meaning of the parameters depends on the message and on the value of Parameter 4.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Message and Cause
Address of the miniport block | Address of the miniport interrupt | Address of the miniport timer queue | 1 | Unloading without deregistering interrupt. A miniport driver failed its initialization without deregistering its interrupt.
Address of the miniport block | Address of the miniport timer queue | Address of the miniport interrupt | 2 | Unloading without deregistering interrupt. A miniport driver did not deregister its interrupt during the halt process.
Address of the miniport block | Address of the miniport interrupt | Address of the miniport timer queue | 1 | Unloading without deregistering timer. A miniport driver failed its initialization without successfully canceling all its timers.
Address of the miniport block | Address of the miniport timer queue | Address of the miniport interrupt | 2 | Unloading without deregistering timer. A miniport driver halted without successfully canceling all its timers.

Comments

This bug check code only occurs on Windows 2000 and Windows XP. In Windows .NET Server 2003 and later, the corresponding code is bug check 0x7C (BUGCODE_NDIS_DRIVER).

On the checked build of Windows, only the Allocating Shared Memory at Raised IRQL and Completing Reset When One is Not Pending bug checks can occur. All the other instances of bug check 0xD2 are replaced with ASSERTs.


Bug Check 0xD3: DRIVER_PORTION_MUST_BE_NONPAGED

The DRIVER_PORTION_MUST_BE_NONPAGED bug check has a value of 0x000000D3. This indicates that the system attempted to access pageable memory at a process IRQL that was too high.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL at time of reference
3 | 0: Read 1: Write
4 | Address that referenced memory

If the driver responsible for the error can be identified, its name is printed on the blue screen and stored in memory at the location (PUNICODE_STRING) KiBugCheckDriver.

Cause

This bug check is usually caused by drivers that have incorrectly marked their own code or data as pageable.

Resolving the Problem

To begin debugging, use a kernel debugger to get a stack trace.


Bug Check 0xD4: SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD

The SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD bug check has a value of 0x000000D4. This indicates that a driver did not cancel pending operations before unloading.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL at time of reference
3 | 0: Read 1: Write
4 | Address that referenced memory

If the driver responsible for the error can be identified, its name is printed on the blue screen and stored in memory at the location (PUNICODE_STRING) KiBugCheckDriver.

Cause

This driver failed to cancel lookaside lists, DPCs, worker threads, or other such items before unload. Subsequently, the system attempted to access the driver's former location at a raised IRQL.

Resolving the Problem

To begin debugging, use a kernel debugger to get a stack trace. If the guilty driver has been identified, activate Driver Verifier and attempt to replicate this bug.

For full details on Driver Verifier, see the Windows DDK.


Bug Check 0xD5: DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL

The DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL bug check has a value of 0x000000D5. This indicates that a driver has referenced memory which was earlier freed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the driver responsible for the error can be identified, its name is printed on the blue screen and stored in memory at the location (PUNICODE_STRING) KiBugCheckDriver.

Cause

The Driver Verifier Special Memory Pool option has caught the driver accessing memory which was earlier freed.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.

Comments

This cannot be protected by try - except; it can only be protected by a probe.


Bug Check 0xD6: DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION

The DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION bug check has a value of 0x000000D6. This indicates the driver accessed memory beyond the end of its pool allocation.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the driver responsible for the error can be identified, its name is printed on the blue screen and stored in memory at the location (PUNICODE_STRING) KiBugCheckDriver.

Cause

The driver allocated n bytes of memory and then referenced more than n bytes. The Driver Verifier Special Memory Pool option detected this violation.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.

Comments

This cannot be protected by try - except; it can only be protected by a probe.


Bug Check 0xD7: DRIVER_UNMAPPING_INVALID_VIEW

The DRIVER_UNMAPPING_INVALID_VIEW bug check has a value of 0x000000D7. This indicates a driver is trying to unmap an address that was not mapped.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Virtual address to unmap
2 | 1: The view is being unmapped 2: The view is being committed
3 | 0
4 | 0

Comments

The guilty driver can be determined from the stack trace.


Bug Check 0xD8: DRIVER_USED_EXCESSIVE_PTES

The DRIVER_USED_EXCESSIVE_PTES bug check has a value of 0x000000D8. This indicates that there are no more system page table entries (PTE) remaining.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Pointer to the guilty driver's name (Unicode string), or zero
2 | Number of PTEs used by the guilty driver (if Parameter 1 is nonzero)
3 | Total free system PTEs
4 | Total system PTEs

If the driver responsible for the error can be identified, its name is printed on the blue screen and stored in memory at the location (PUNICODE_STRING) KiBugCheckDriver.

Cause

This is usually caused by a driver not cleaning up its memory use properly. Parameter 1 shows the driver which has consumed the most PTEs. The call stack will reveal which driver actually caused the bug check.

Resolving the Problem

Both drivers may need to be fixed. The total number of system PTEs may also need to be increased.


Bug Check 0xD9: LOCKED_PAGES_TRACKER_CORRUPTION

The LOCKED_PAGES_TRACKER_CORRUPTION bug check has a value of 0x000000D9. This indicates that the internal locked-page tracking structures have been corrupted.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of violation. The meaning of the other parameters depends on the value of Parameter 1.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x01 | The address of the internal lock tracking structure | The address of the memory descriptor list | The number of pages locked for the current process | The MDL is being inserted twice on the same process list.
0x02 | The address of the internal lock tracking structure | The address of the memory descriptor list | The number of pages locked for the current process | The MDL is being inserted twice on the systemwide list.
0x03 | The address of the first internal tracking structure found | The address of the internal lock tracking structure | The address of the memory descriptor list | The MDL was found twice in the process list when being freed.
0x04 | The address of the internal lock tracking structure | The address of the memory descriptor list | 0 | The MDL was found in the systemwide list on free after it was removed.

Cause

The error is indicated by the value of Parameter 1.


Bug Check 0xDA: SYSTEM_PTE_MISUSE

The SYSTEM_PTE_MISUSE bug check has a value of 0x000000DA. This indicates that a PTE routine has been used in an improper way.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of violation. The meaning of the other parameters depends on the value of Parameter 1.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x01 | The address of the internal lock tracking structure | The address of the memory descriptor list | The address of the duplicate internal lock tracking structure | The PTE mapping being freed is a duplicate.
0x02 | The address of the internal lock tracking structure | The number of PTEs the system thinks should be freed | The number of PTEs the driver is requesting to free | The number of PTE mappings being freed is incorrect.
0x03 | The address of the first internal tracking structure found | The PTE address the system thinks should be freed | The PTE address the driver is requesting to free | The PTE mapping address being freed is incorrect.
0x04 | The address of the internal lock tracking structure | The page frame number the system thinks should be first in the MDL | The page frame number that is currently first in the MDL | The first page of the mapped MDL has changed since the MDL was mapped.
0x05 | The address of the first internal tracking structure found | The virtual address the system thinks should be freed | The virtual address the driver is requesting to free | The start virtual address in the MDL being freed has changed since the MDL was mapped.
0x06 | The MDL specified by the driver | The virtual address specified by the driver | The number of PTEs to free (specified by the driver) | The MDL being freed was never (or is currently not) mapped.
0x07 | The starting PTE | The number of PTEs | Reserved | The PTE range is being double-allocated.
0x08 | The starting PTE | The number of PTEs the caller is freeing | The number of PTEs the system thinks should be freed | The caller is asking to free an incorrect number of PTEs.
0x09 | The starting PTE | The number of PTEs the caller is freeing | The PTE index that the system thinks is already free | The caller is asking to free several PTEs, but at least one of them is not allocated.
0x0A | 1: The driver requested "bugcheck on failure" in the MDL. 0: The driver did not request this. | The number of PTEs the caller is allocating | The type of PTE pool requested | The caller is asking to allocate zero PTEs.
0x0B | The corrupt PTE | The number of PTEs the caller is allocating | The type of PTE pool requested | The PTE list is already corrupted at the time of this allocation. The corrupt PTE is below the lowest possible PTE address.
0x0C | The corrupt PTE | The number of PTEs the caller is allocating | The type of PTE pool requested | The PTE list is already corrupted at the time of this allocation. The corrupt PTE is above the lowest possible PTE address.
0x0D | The starting PTE | The number of PTEs the caller is freeing | The type of PTE pool | The caller is trying to free zero PTEs.
0x0E | The starting PTE | The number of PTEs the caller is freeing | The type of PTE pool | The caller is trying to free PTEs, but the guard PTE has been overwritten.
0x0F | The non-existent PTE | The number of PTEs the caller is trying to free | The type of PTE pool being freed | The caller is trying to free a non-existent PTE. The non-existent PTE is below the lowest possible PTE address.
0x10 | The non-existent PTE | The number of PTEs the caller is trying to free | The type of PTE pool being freed | The caller is trying to free a non-existent PTE. The non-existent PTE is above the highest possible PTE address.
0x11 | The non-existent PTE | The number of PTEs the caller is trying to free | The type of PTE pool being freed | The caller is trying to free a non-existent PTE. The non-existent PTE is at the base of the PTE address space.

Cause

The error is indicated by the value of Parameter 1.

A stack trace will identify the guilty driver.


Bug Check 0xDB: DRIVER_CORRUPTED_SYSPTES

The DRIVER_CORRUPTED_SYSPTES bug check has a value of 0x000000DB. This indicates that an attempt was made to touch memory at an invalid IRQL, probably due to corruption of system PTEs.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL
3 | 0: Read 1: Write
4 | Address in code which referenced memory

Cause

A driver tried to access pageable (or completely invalid) memory at too high of an IRQL. This bug check is almost always caused by drivers that have corrupted system PTEs.

Resolving the Problem

If this bug check occurs, the culprit can be detected by editing the registry. In the \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management registry key, create or edit the TrackPtes value, and set it equal to DWORD 3. Then reboot. The system will then save stack traces, and if the driver commits the same error, the system will issue bug check 0xDA (SYSTEM_PTE_MISUSE). Then the stack trace will identify the guilty driver.


Bug Check 0xDC: DRIVER_INVALID_STACK_ACCESS

The DRIVER_INVALID_STACK_ACCESS bug check has a value of 0x000000DC. This indicates that a driver accessed a stack address that lies below the stack pointer of the stack's thread.

Parameters

None


Bug Check 0xDE: POOL_CORRUPTION_IN_FILE_AREA

The POOL_CORRUPTION_IN_FILE_AREA bug check has a value of 0x000000DE. This indicates that a driver corrupted pool memory used for holding pages destined for disk.

Parameters

None

Cause

When the Memory Manager dereferenced the file, it discovered the corruption in pool memory.


Bug Check 0xDF: IMPERSONATING_WORKER_THREAD

The IMPERSONATING_WORKER_THREAD bug check has a value of 0x000000DF. This indicates that a workitem did not disable impersonation before it completed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The worker routine that caused this error
2 | The parameter passed to this worker routine
3 | A pointer to the work item
4 | Reserved

Cause

A worker thread was impersonating another process, and failed to disable impersonation before it returned.


Bug Check 0xE0: ACPI_BIOS_FATAL_ERROR

The ACPI_BIOS_FATAL_ERROR bug check has a value of 0x000000E0. This indicates that one of your computer components is faulty.

Parameters

The parameters for this bug check are issued by the BIOS, not by Windows. They can only be interpreted by the hardware vendor.

Cause

Your computer's BIOS has reported that a component in your system is so faulty that there is no way for Windows to operate. The BIOS is indicating that there is no alternative but to issue a bug check.

Resolving the Problem

You can determine which component is faulty by running the diagnostic disk or tool that came with your computer.

If you do not have this tool, you must contact your system vendor and report this error message to them. They will be able to assist you in correcting this hardware problem, thereby allowing Windows to operate.

Microsoft cannot address this error. Only the hardware vendor is qualified to analyze it.


Bug Check 0xE1: WORKER_THREAD_RETURNED_AT_BAD_IRQL

The WORKER_THREAD_RETURNED_AT_BAD_IRQL bug check has a value of 0x000000E1. This indicates that a worker thread completed and returned at IRQL DISPATCH_LEVEL or above.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Address of the worker routine
2 | IRQL that the worker thread returned at
3 | Work item parameter
4 | Work item address

Cause

A worker thread completed and returned at IRQL DISPATCH_LEVEL or above.

Resolving the Problem

To find the guilty driver, use the LN (List Nearest Symbols) debugger command:

kd> ln address

where address is the worker routine address given in Parameter 1.


Bug Check 0xE2: MANUALLY_INITIATED_CRASH

The MANUALLY_INITIATED_CRASH bug check has a value of 0x000000E2. This indicates that the user deliberately initiated a crash dump from either the kernel debugger or the keyboard.

Parameters

None

Comments

For details on manually-initiated crash dumps, see Forcing a System Crash.


Bug Check 0xE3: RESOURCE_NOT_OWNED

The RESOURCE_NOT_OWNED bug check has a value of 0x000000E3. This indicates that a thread tried to release a resouce it did not own.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Address of resource
2 | Address of thread
3 | Address of owner table (if it exists)
4 | Reserved


Bug Check 0xE4: WORKER_INVALID

The WORKER_INVALID bug check has a value of 0x000000E4. This indicates that an executive worker item was found in memory which must not contain such items.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Code position indicator
2 | Address of worker item
3 | Start of pool block
4 | End of pool block

Cause

This is usually caused by a driver freeing memory which still contains an executive worker item.


Bug Check 0xE6: DRIVER_VERIFIER_DMA_VIOLATION

The DRIVER_VERIFIER_DMA_VIOLATION bug check has a value of 0x000000E6. This is the bug check code for all Driver Verifier DMA Verification violations.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 is the only parameter of interest; this identifies the exact violation. If a debugger is attached, an informative message is displayed in the debugger.

Parameter 1 | Cause of Error and Debugger Message
0x00 This code can represent two different kinds of errors:

1. The driver attempted to flush too many bytes to the end of the map register file. The number of bytes permitted and the number of bytes attempted are displayed.

2. Windows has run out of contiguous map registers. The number of map registers needed and the largest block of contiguous map registers is displayed.
0x01 | The performance counter has decreased. The old and new values of the counter are displayed.
0x02 | The performance counter has increased too fast. The counter value is displayed in the debugger.
0x03 | The driver freed too many DMA common buffers. Usually this means it freed the same buffer twice.
0x04 | The driver freed too many DMA adapter channels. Usually this means it freed the same adapter channel twice.
0x05 | The driver freed too many DMA map registers. Usually this means it freed the same map register twice. The number of active map registers is displayed.
0x06 | The driver freed too many DMA scatter-gather lists. Usually this means it freed the same scatter-gather list twice. The number of lists allocated and the number of lists freed is displayed.
0x07 | The driver attempted to release the adapter without first freeing all its common buffers. The adapter address and the number of remaining buffers is displayed.
0x08 | The driver attempted to release the adapter without first freeing all adapter channels, common buffers, or scatter-gather lists. The adapter address and the number of remaining items is displayed.
0x09 | The driver attempted to release the adapter without first freeing all map registers. The adapter address and the number of remaining map registers is displayed.
0x0A | The driver attempted to release the adapter without first freeing all its scatter-gather lists. The adapter address and the number of remaining scatter-gather lists is displayed.
0x0B | The driver has allocated too many adapter channels simultaneously. (Only one adapter channel is permitted per adapter.)
0x0C | The driver attempted to allocate too many map registers at one time. The number requested and the number allowed are displayed.
0x0D | The driver did not flush its adapter buffers. The number of bytes that the driver attempted to map and the maximum number of bytes allowed are displayed.
0x0E | The driver attempted a DMA transfer without locking the buffer. The buffer in question was in paged memory. The address of the MDL is displayed.
0x0F | The driver or the hardware wrote outside of its allocated DMA buffer. The nature of the error (overrun or underrun) is displayed, as well as the relevant addresses.
0x10 | The driver attempted to free its map registers while some were still mapped. The number of map registers still mapped is displayed.
0x11 | The driver has too many outstanding reference counts for the adapter. The number of reference counts and the adapter address are displayed.
0x13 | The driver called a DMA routine at an improper IRQL. The required IRQL and the actual IRQL are displayed.
0x14 | The driver called a DMA routine at an improper IRQL. The required IRQL and the actual IRQL are displayed.
0x15 | The driver attempted to allocate too many map registers. The number requested and the number allowed are displayed.
0x16 | The driver attempted to flush a buffer that isn't mapped. The address of the buffer is displayed.
0x18 | The driver attempted a DMA operation using an adapter that was already released and no longer exists. The adapter address is displayed.
0x19 | The driver passed a null DMA_ADAPTER value to a HAL routine.
0x1B | The driver passed an address and MDL to a HAL routine, but this address is not within the bounds of this MDL. The address passed and the address of the MDL are displayed.
0x1D | The driver attempted to map an address range that was already mapped. The address range and the current mapping for that range are displayed.
0x1E | The driver called HalGetAdapter. This function is obsolete — you must use IoGetDmaAdapter instead.
0x1F | The driver referenced an invalid system address — either before the first MDL, or after the end of the first MDL, or using a transfer length that is longer than the MDL buffer and crosses a page boundary within the MDL. Either the invalid address and the first MDL address, or the MDL address and the extra transfer length are displayed.
0x20 | The driver attempted to flush a map register that hasn't been mapped. The map register base, flushing address, and MDL are displayed.
0x21 | The driver attempted to map a zero-length buffer for transfer.

Cause

See the description of each code in the Parameters section for a description of the cause.

Resolving the Problem

This bug check can only occur when Driver Verifier has been instructed to monitor one or more drivers. If you did not intend to use Driver Verifier, you should deactivate it. You might consider removing the driver which caused this problem as well.

If you are the driver writer, use the information obtained through this bug check to fix the bugs in your code.

The Driver Verifier DMA Verification option is only available in Windows XP and later. For full details on Driver Verifier, see the Windows DDK.


Bug Check 0xE7: INVALID_FLOATING_POINT_STATE

The INVALID_FLOATING_POINT_STATE bug check has a value of 0x000000E7. This indicates that a thread's saved floating point state is invalid.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates which validity check failed. Parameter 4 is not used. The meaning of the other parameters depends on the value of Parameter 1.

Parameter 1 | Parameter 2 | Parameter 3 | Cause of Error
0x0 | The flags field | 0 | The saved context flags field is invalid. Either FLOAT_SAVE_VALID is not set, or some of the reserved bits are non-zero.
0x1 | The saved IRQL | The current IRQL | The current processor's IRQL is not the same as when the floating point context was saved.
0x2 | The saved address of the thread that owns this floating point context | The current thread | The saved context does not belong to the current thread.

Cause

While restoring the previously-saved floating point state for a thread, the state was found to be invalid.

Parameter 1 indicates which validity check failed.


Bug Check 0xE8: INVALID_CANCEL_OF_FILE_OPEN

The INVALID_CANCEL_OF_FILE_OPEN bug check has a value of 0x000000E8. This indicates that an invalid file object was passed to IoCancelFileOpen.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The FileObject passed to IoCancelFileOpen
2 | The DeviceObject passed to IoCancelFileOpen
3 | Reserved
4 | Reserved

Cause

The file object passed to IoCancelFileOpen is invalid. It should have reference of one. The driver that called IoCancelFileOpen is at fault.


Bug Check 0xE9: ACTIVE_EX_WORKER_THREAD_TERMINATION

The ACTIVE_EX_WORKER_THREAD_TERMINATION bug check has a value of 0x000000E9. This indicates that an active executive worker thread is being terminated.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The exiting ETHREAD
2 | Reserved
3 | Reserved
4 | Reserved

Cause

An executive worker thread is being terminated without having gone through the worker thread rundown code. This is forbidden; work items queued to the ExWorkerQueue must not terminate their threads.

A stack trace should indicate the cause.


Bug Check 0xEA: THREAD_STUCK_IN_DEVICE_DRIVER

The THREAD_STUCK_IN_DEVICE_DRIVER bug check has a value of 0x000000EA. This indicates that a thread in a device driver is endlessly spinning.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | A pointer to the stuck thread object
2 | A pointer to the DEFERRED_WATCHDOG object
3 | A pointer to the offending driver name
4 | In the kernel debugger: The number of times the "intercepted" bug check 0xEA was hit On the blue screen: 1

Cause

A device driver is spinning in an infinite loop, most likely waiting for hardware to become idle.

This usually indicates problem with the hardware itself, or with the device driver programming the hardware incorrectly. In many cases this is the result of a bad video card or a bad display driver.

Resolving the Problem

Use the .thread (Set Register Context) command with Parameter 1. Then use KB (Display Stack Backtrace) to find the location where the thread is stuck.

If the kernel debugger is already connected and running when Windows detects a timeout condition, then DbgBreakPoint will be called instead of KeBugCheckEx. A detailed message will be printed to the debugger.

This message will include what would have been the bug check parameters. Since no actual bug check was issued, the .bugcheck command will not be of use. The four parameters can also be retrieved from Watchdog's global variables by using dd watchdog!g_WdBugCheckData L5" on a 32-bit system, or dq watchdog!g_WdBugCheckData L5" on a 64-bit system.

Debugging this error in an interactive manner like this will enable you to identify an offending thread, set breakpoints in it, and then use G (Go) to return to the spinning code to debug it further.

On multiprocessor machines it is possible to hit a timeout if the spinning thread is interrupted by a hardware interrupt and an ISR or DPC routine is running at the time of the bug check. The reason for this is that the timeout's work item can be delivered and handled on the second CPU and the same time. If this occurs, you will have to look deeper at the offending thread's stack to determine the spinning code which caused the timeout to occur. Use the DdS (Display Words and Symbols) command to do this.


Bug Check 0xEB: DIRTY_MAPPED_PAGES_CONGESTION

The DIRTY_MAPPED_PAGES_CONGESTION bug check has a value of 0x000000EB. This indicates that no free pages are available to continue operations.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The total number of dirty pages
2 | The number of dirty pages destined for the page file
3 | The size of the nonpaged pool available at the time of the bug check (in pages)
4 | The number of transition pages that are currently stranded

Cause

The filesystem driver stack has deadlocked and the majority of the modified pages are destined for the filesystem. Since the filesystem is nonoperational, the system has crashed because none of the modified pages can be reused without losing data. Any filesystem or filter driver in the stack may be at fault.

To see general memory statistics, use the !vm 3 extension.

This bug check can occur for any of the following reasons:

  • A driver has blocked, deadlocking the modified or mapped page writers. Examples of this include mutex deadlocks or accesses to paged out memory in file system drivers or filter drivers. This indicates a driver bug.

    If Parameter 1 or 2 is large, then this is a possibility. Use !vm 3.

  • A storage driver is not processing requests. Examples of this are stranded queues and non-responding drives. This indicates a driver bug.

    If Parameter 1 or 2 is large, then this is a possibility. Use !process 0 7.

  • Not enough pool is available for the storage stack to write out modified pages. This indicates a driver bug.

    If Parameter 3 is small, then this is a possibility. Use !vm and !poolused 2.


Bug Check 0xEC: SESSION_HAS_VALID_SPECIAL_POOL_ON_EXIT

The SESSION_HAS_VALID_SPECIAL_POOL_ON_EXIT bug check has a value of 0x000000EC. This indicates that a session unload occurred while a session driver still held memory.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The session ID
2 | The number of special pool pages that are leaking
3 | Reserved
4 | Reserved

Cause

This error is caused by a session driver not freeing its special pool allocations prior to a session unload. This indicates a bug in win32k.sys, atmfd.dll, rdpdd.dll, or a video driver.


Bug Check 0xED: UNMOUNTABLE_BOOT_VOLUME

The UNMOUNTABLE_BOOT_VOLUME bug check has a value of 0x000000ED. This indicates that the I/O subsystem attempted to mount the boot volume and it failed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The device object of the boot volume
2 | The status code from the file system that describes why it failed to mount the volume
3 | Reserved
4 | Reserved


Bug Check 0xEF: CRITICAL_PROCESS_DIED

The CRITICAL_PROCESS_DIED bug check has a value of 0x000000EF. This indicates that a critical system process died.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The process object
2 | Reserved
3 | Reserved
4 | Reserved


Bug Check 0xF1: SCSI_VERIFIER_DETECTED_VIOLATION

The SCSI_VERIFIER_DETECTED_VIOLATION bug check has a value of 0x000000F1. This is the bug check code for all Driver Verifier SCSI Verification violations.

Parameters

The four bug check parameters are displayed on the blue screen. Parameter 1 identifies the type of violation.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Cause of Error
0x1000 | First argument passed | Second argument passed | Reserved | The miniport driver passed bad arguments to ScsiPortInitialize.
0x1001 | Delay, in microseconds | Reserved | Reserved | The miniport driver called ScsiPortStallExecution and specified a delay greater than 0.1 second, stalling the processor too long.
0x1002 | Address of routine that took too long | Address of miniport's HW_DEVICE_EXTENSION | Duration of the routine, in microseconds | A miniport routine called by the port driver took longer than 0.5 second to execute. (0.5 seconds is the limit for most routines. However, the HwInitialize routine is allowed 5 seconds, and the FindAdapter routine is exempt.)
0x1003 | Address of miniport's HW_DEVICE_EXTENSION | Address of the SRB | Reserved | The miniport driver completed a request more than once.
0x1004 | Address of the SRB | Address of miniport's HW_DEVICE_EXTENSION | Reserved | The miniport driver completed a request with an invalid SRB status.
0x1005 | Address of miniport's HW_DEVICE_EXTENSION | Address of LOGICAL_UNIT_EXTENSION | Reserved | The miniport driver called ScsiPortNotification to ask for NextLuRequest, but an untagged request is still active.
0x1006 | Address of miniport's HW_DEVICE_EXTENSION | Invalid virtual address | Reserved | The miniport driver passed an invalid virtual address to ScsiPortGetPhysicalAddress. (This usually means the address supplied doesn't map to the common buffer area.)
0x1007 | Address of ADAPTER_EXTENSION | Address of miniport's HW_DEVICE_EXTENSION | Reserved | The reset hold period for the bus ended, but the miniport driver still has outstanding requests.

Cause

See the description of each code in the Parameters section for an explanation of the cause.

Resolving the Problem

This bug check can only occur when Driver Verifier has been instructed to monitor one or more drivers. If you did not intend to use Driver Verifier, you should deactivate it. You might consider removing the driver which caused this problem as well.

If you are the driver writer, use the information obtained through this bug check to fix the bugs in your code.

The Driver Verifier SCSI Verification option is only available in Windows XP and later. For full details on Driver Verifier, see the Windows DDK.


Bug Check 0xF3: DISORDERLY_SHUTDOWN

The DISORDERLY_SHUTDOWN bug check has a value of 0x000000F3. This indicates that Windows was unable to shut down due to lack of memory.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The total number of dirty pages
2 | The number of dirty pages destined for the page file
3 | The size of the nonpaged pool available at the time of the error (in pages)
4 | The current shutdown stage

Cause

Windows attempted to shut down, but there were no free pages available to continue operations.

Because applications were not terminated and drivers were not unloaded, they continued to access pages even after the modified writer had terminated. This causes the system to run out of pages, since the page files could be used.


Bug Check 0xF4: CRITICAL_OBJECT_TERMINATION

The CRITICAL_OBJECT_TERMINATION bug check has a value of 0x000000F4. This indicates that a process or thread crucial to system operation has unexpectedly exited or been terminated.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The terminating object type: 0x3: Process 0x6: Thread
2 | The terminating object
3 | The process image file name
4 | Pointer to an ASCII string containing an explanatory message

Cause

Several processes and threads are necessary for the operation of the system. When they are terminated for any reason, the system can no longer function.


Bug Check 0xF6: PCI_VERIFIER_DETECTED_VIOLATION

The PCI_VERIFIER_DETECTED_VIOLATION bug check has a value of 0x000000F6. This indicates that an error occurred in the BIOS or another device being verified by the PCI driver.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 is the only parameter of interest; this identifies the nature of the failure detected.

Parameter 1 | Cause of Error
0x01 | An active bridge was reprogrammed by the BIOS during a docking event.
0x02 | The PMCSR register was not updated within the spec-mandated time.
0x03 | A driver has written to Windows-controlled portions of a PCI device's configuration space.

Cause

The PCI driver detected an error in a device or BIOS being verified.


Bug Check 0xF7: DRIVER_OVERRAN_STACK_BUFFER

The DRIVER_OVERRAN_STACK_BUFFER bug check has a value of 0x000000F7. This indicates that a driver has overrun a stack-based buffer.

Parameters

None

Cause

A driver overran a stack-based buffer (or local variable) in a way that would have overwritten the function's return address and jumped back to an arbitrary address when the function returned.

This is the classic "buffer overrun" hacking attack. The system has been brought down to prevent a malicious user from gaining complete control of it.

Resolving the Problem

Use the KB (Display Stack Backtrace) command to get a stack trace.

The last routine on the stack before the buffer overrun handlers and bug check call is the one that overran its local variable.


Bug Check 0xF8: RAMDISK_BOOT_INITIALIZATION_FAILED

The RAMDISK_BOOT_INITIALIZATION_FAILED bug check has a value of 0x000000F8. This indicates that an initialization failure occurred while attempting to boot from the RAM disk.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Indicates the cause of the failure. 1: No LoaderXIPRom descriptor was found in the loader memory list. 2: Unable to open the RAM disk driver (ramdisk.sys or \Device\Ramdisk). 3: FSCTL_CREATE_RAM_DISK failed. 4: Unable to create GUID string from binary GUID. 5: Unable to create symbolic link pointing to the RAM disk device.
2 | NTSTATUS code
3 | 0
4 | 0


Bug Check 0xF9: DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN

The DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN bug check has a value of 0x000000F9. This indicates that a driver returned STATUS_REPARSE to an IRP_MJ_CREATE request with no trailing names.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | The device object that was opened
2 | The device object to which the IRP_MJ_CREATE request was issued
3 | Address of the UNICODE string containing the new name of the file (to be reparsed)
4 | Information returned by the driver for the IRP_MJ_CREATE request

Comments

STATUS_REPARSE should be returned only for IRP_MJ_CREATE requests with trailing names, as that indicates the driver is supporting name spaces.


Bug Check 0x1000007E: SYSTEM_THREAD_EXCEPTION_NOT_HANDLED_M

The SYSTEM_THREAD_EXCEPTION_NOT_HANDLED_M bug check has a value of 0x1000007E. This indicates that a system thread generated an exception which the error handler did not catch.

Bug check 0x1000007E has the same meaning and parameters as bug check 0x7E (SYSTEM_THREAD_EXCEPTION_NOT_HANDLED).


Bug Check 0x1000007F: UNEXPECTED_KERNEL_MODE_TRAP_M

The UNEXPECTED_KERNEL_MODE_TRAP_M bug check has a value of 0x1000007F. This indicates that a trap was generated by the Intel CPU and the kernel failed to catch this trap.

Bug check 0x1000007F has the same meaning and parameters as bug check 0x7F (UNEXPECTED_KERNEL_MODE_TRAP).


Bug Check 0x1000008E: KERNEL_MODE_EXCEPTION_NOT_HANDLED_M

The KERNEL_MODE_EXCEPTION_NOT_HANDLED_M bug check has a value of 0x1000008E. This indicates that a kernel-mode program generated an exception which the error handler did not catch.

Bug check 0x1000008E has the same meaning and parameters as bug check 0x8E (KERNEL_MODE_EXCEPTION_NOT_HANDLED).


Bug Check 0x100000EA: THREAD_STUCK_IN_DEVICE_DRIVER_M

The THREAD_STUCK_IN_DEVICE_DRIVER_M bug check has a value of 0x100000EA. This indicates that a thread in a device driver is endlessly spinning.

Bug check 0x100000EA has the same meaning and parameters as bug check 0xEA (THREAD_STUCK_IN_DEVICE_DRIVER).


Bug Check 0xC0000218: STATUS_CANNOT_LOAD_REGISTRY_FILE

The STATUS_CANNOT_LOAD_REGISTRY_FILE bug check has a value of 0xC0000218. This indicates that a registry file could not be loaded.

Parameters

This bug check will display a descriptive text message. The name of the damaged file is displayed as part of the message.

Cause

This error occurs if a necessary registry hive file cannot be loaded. Usually this means the file is corrupt or is missing.

In rare instances, this error can be caused by a driver that has corrupted the registry image in memory, or by a memory error in this region.

Resolving the Problem

Try running the Emergency Recovery Disk (ERD) and allow the system to repair any errors that it detects. If the problem is a missing or corrupt registry file, this will usually fix the problem.


Bug Check 0xC000021A: STATUS_SYSTEM_PROCESS_TERMINATED

The STATUS_SYSTEM_PROCESS_TERMINATED bug check has a value of 0xC000021A. This means that an error has occurred in a crucial user-mode subsystem.

Parameters

This bug check will display a descriptive text message.

Cause

This error occurs when a user-mode subsystem, such as WinLogon or the Client Server Runtime Subsystem (CSRSS), has been fatally compromised and security can no longer be guaranteed. In response, the operating system switches to kernel mode. Microsoft Windows cannot run without WinLogon or CSRSS. Therefore, this is one of the few cases where the failure of a user-mode service can shut down the system.

Mismatched system files can also cause this error. This can occur if you have restored your hard disk from a backup. Some backup programs might skip restoring system files that they determine are in use.

Resolving the Problem

Running the kernel debugger is not useful in this situation because the actual error occurred in a user-mode process.

Resolving an error in a user-mode device driver, system service, or third-party application: Because bug check 0xC000021A occurs in a user-mode process, the most common culprits are third-party applications. If the error occurred after the installation of a new or updated device driver, system service, or third-party application, the new software should be removed or disabled. Contact the manufacturer of the software about a possible update.

If the error occurs during system startup, restart your computer, and press F8 at the character-based menu that displays the operating system choices. At the resulting Windows Advanced Options menu, choose the Last Known Good Configuration option. This option is most effective when only one driver or service is added at a time. If this does not resolve the error, try manually removing the offending software. If the system partition is formatted with file allocation table (FAT), use a Microsoft MS-DOS® startup disk to gain access to the computer's hard disk. If the system partition is formatted with NTFS file system, you might be able to use Safe Mode to rename or delete the faulty software. If the faulty software is used as part of the system startup process in Safe Mode, you need to start the computer using the Recovery Console in order to access the file. If a newly installed piece if hardware is suspected, remove it to see if this resolves the issue.

Try running the Emergency Recovery Disk (ERD) and allow the system to repair any errors that it detects.

Resolving a mismatched system file problem: If you have recently restored your hard disk from a backup, check if there is an updated version of the Backup/Restore program available from the manufacturer. Make sure the latest Windows Service Pack is installed.


Bug Check 0xC0000221: STATUS_IMAGE_CHECKSUM_MISMATCH

The STATUS_IMAGE_CHECKSUM_MISMATCH bug check has a value of 0xC0000221. This indicates that a driver or a system DLL has been corrupted.

Parameters

This bug check will display a descriptive text message. The name of the damaged file is displayed as part of the message.

Cause

This bug check results from a serious error in a driver or other system file. The file header checksum does not match the expected checksum.

This can also be caused by faulty hardware in the I/O path to the file (a disk error, faulty RAM, or a corrupted page file).

Resolving the Problem

To remedy this error, run the Emergency Recovery Disk (ERD) and allow the system to repair or replace the missing or damaged driver file on the system partition.

You can also run an in-place upgrade over the existing copy of Windows. This preserves all registry settings and configuration information, but replaces all system files. If any Service Packs and/or hotfixes had previously been applied, you need to reinstall them afterward in the appropriate order (latest Service Pack, then any post-Service Pack hotfixes in the order in which they were originally installed, if applicable).

If a specific file was identified in the bug check message as being corrupted, you can try replacing that individual file manually. If the system partition is formatted with FAT, you can start from an MS-DOS startup disk and copy the file from the original source onto the hard disk. If you have a dual-boot machine, you can boot to your other operating system and replace the file.

If you want to replace the file on a single-boot system with an NTFS partition, you need to restart the system, press F8 at the operating system Loader menu, and choose Safe Mode with Command Prompt. From there, copy a fresh version of the file from the original source onto the hard disk. If the file is used as part of the system startup process in Safe Mode, you need to start the computer using the Recovery Console in order to access the file. If these methods fail, try reinstalling Windows and then restoring the system from a backup.

Note If the original file from the product CD has a filename extension ending in an _ (underscore), the file needs to be uncompressed before it can be used. The Recovery Console's Copy command automatically detects compressed files and expands them as they are copied to the target location. If you are using Safe Mode to access a drive, use the Expand command to uncompress and copy the file to the target folder. You can use the Expand command in the command line environment of Safe Mode.

Resolving a disk error problem: Disk errors can be a source of file corruption. Run Chkdsk /f /r to detect and resolve any file system structural corruption. You must restart the system before the disk scan begins on a system partition.

Resolving a RAM problem: If the error occurred immediately after RAM was added to the system, the paging file might be corrupted or the new RAM itself might be either faulty or incompatible.

To determine if newly added RAM is causing a bug check

  1. Return the system to the original RAM configuration.
  2. Use the Recovery Console to access the partition containing the paging file and delete the file pagefile.sys.
  3. While still in the Recovery Console, run Chkdsk /r on the partition that contained the paging file.
  4. Restart the system.
  5. Set the paging file to an optimal level for the amount of RAM added.
  6. Shutdown the system and add your RAM.

    The new RAM must meet the system manufacturer's specifications for speed, parity, and type (that is, fast page-mode (FPM) versus extended data out (EDO) versus synchronous dynamic random access memory (SDRAM)). Try to match the new RAM to the existing installed RAM as closely as possible. RAM can come in many different capacities, and more importantly, in different formats (single inline memory modules — SIMM — or dual inline memory modules — DIMM). The electrical contacts can be either gold or tin and it is not wise to mix these contact types.

If you experience the same error message after reinstalling the new RAM, run hardware diagnostics supplied by the system manufacturer, especially the memory scanner. For details on these procedures, see the owner's manual for your computer.

When you can log on to the system again, check the System Log in Event Viewer for additional error messages that might help pinpoint the device or driver that is causing the error.

Disabling memory caching of the BIOS might also resolve this error.


Bug Check 0xDEADDEAD: MANUALLY_INITIATED_CRASH1

The MANUALLY_INITIATED_CRASH1 bug check has a value of 0xDEADDEAD. This indicates that the user deliberately initiated a crash dump from either the kernel debugger or the keyboard.

Parameters

None

Comments

For details on manually-initiated crash dumps, see Forcing a System Crash.


Crash Dump Files

This section includes:

Kernel-Mode Dump Files

User-Mode Dump Files


Kernel-Mode Dump Files

When a kernel-mode error occurs, the default behavior of Microsoft® Windows® is to display the blue screen with bug check data.

However, there are several alternative behaviors that can be selected:

  • A kernel debugger (such as WinDbg or KD) can be contacted.
  • A memory dump file can be written.
  • The system can automatically reboot.
  • A memory dump file can be written, and the system can automatically reboot afterwards.

This section covers how to create and analyze a kernel-mode memory dump file. There are three different varieties of crash dump files. However, it should be remembered that no dump file can ever be as useful and versatile as a live kernel debugger attached to the system that has failed.

This section includes:

Varieties of Kernel-Mode Dump Files

Creating a Kernel-Mode Dump File

Analyzing a Kernel-Mode Dump File


Varieties of Kernel-Mode Dump Files

There are three kinds of kernel-mode crash dump files:

Complete Memory Dump

Kernel Memory Dump

Small Memory Dump

The Kernel-Memory Crash Dump and the Small Memory Dump are only available in Windows 2000 and later.

The difference between these dump files is one of size. The Complete Memory Dump is the largest and contains the most information, the Kernel Memory Dump is somewhat smaller, and the Small Memory Dump is only 64 KB in size.

The advantage to the larger files is that, since they contain more information, they are more likely to help you find the cause of the crash.

The advantage of the smaller files is that they are smaller and written more quickly. Speed is often valuable; if you are running a server, you may want the server to reboot as quickly as possible after a crash, and the reboot will not take place until the dump file has been written.

After a Complete Memory Dump or Kernel Memory Dump has been created, it is possible to create a Small Memory Dump file from the larger dump file. See the .dump (Create Dump File) command for details.

Note Much information can be obtained by analyzing a kernel-mode dump file. However, no kernel-mode dump file can provide as much information as actually debugging the crash directly with a kernel debugger.


Complete Memory Dump

A Complete Memory Dump is the largest kernel-mode dump file. This file contains all the physical memory for the machine at the time of the fault.

This dump file requires a pagefile on your boot drive that is at least as large as your main system memory: it should be able to hold a file whose size equals your entire RAM plus one megabyte.

The Complete Memory Dump file is written to %SystemRoot%\Memory.dmp by default.

If a second bug check occurs and another Complete Memory Dump (or Kernel Memory Dump) is created, the previous file will be overwritten.


Kernel Memory Dump

A Kernel Memory Dump contains all the memory in use by the kernel at the time of the crash.

This kind of dump file is significantly smaller than the Complete Memory Dump. Typically, the dump file will be around one-third the size of the physical memory on the system. Of course, this quantity will vary considerably, depending on your circumstances.

This dump file will not include unallocated memory, or any memory allocated to user-mode applications. It only includes memory allocated to the Windows kernel and hardware abstraction level (HAL), as well as memory allocated to kernel-mode drivers and other kernel-mode programs.

For most purposes, this crash dump is the most useful. It is significantly smaller than the Complete Memory Dump, but it only omits those portions of memory that are unlikely to have been involved in the crash.

Since this kind of dump file does not contain images of any user-mode executables residing in memory at the time of the crash, you may also need to set the executable image path if these executables turn out to be important.

The Kernel Memory Dump file is written to %SystemRoot%\Memory.dmp by default.

If a second bug check occurs and another Kernel Memory Dump (or Complete Memory Dump) is created, the previous file will be overwritten.


Small Memory Dump

A Small Memory Dump is much smaller than the other two kinds of kernel-mode crash dump files. It is exactly 64 KB in size, and requires only 64 KB of pagefile space on the boot drive.

This dump file includes the following:

  • The bug check message and parameters, as well as other blue-screen data.
  • The processor context (PRCB) for the processor that crashed.
  • The process information and kernel context (EPROCESS) for the process that crashed.
  • The thread information and kernel context (ETHREAD) for the thread that crashed.
  • The kernel-mode call stack for the thread that crashed. If this is longer than 16 KB, only the topmost 16 KB will be included.
  • A list of loaded drivers.

In Windows XP and Windows .NET Server 2003, the following items are also included:

  • A list of loaded modules and unloaded modules.
  • The debugger data block. This contains basic debugging information about the system.
  • Any additional memory pages that Windows identifies as being useful in debugging failures. This includes the data pages that the registers were pointing to when the crash occurred, and other pages specifically requested by the faulting component.
  • (IA-64 processor only) The backing store (for IA-64 processors only.)
  • (Windows .NET Server 2003 only) The Windows type — for example, "Professional" or "Server".

This kind of dump file can be useful when space is greatly limited. However, due to the limited amount of information included, errors that were not directly caused by the thread executing at time of crash may not be discovered by an analysis of this file.

Since this kind of dump file does not contain images of any executables residing in memory at the time of the crash, you may also need to set the executable image path if these executables turn out to be important.

If a second bug check occurs and a second Small Memory Dump file is created, the previous file will be preserved. Each additional file will be given a distinct name, which contains the date of the crash encoded in the filename. For example, mini022900-01.dmp is the first memory dump file generated on February 29, 2000. A list of all Small Memory Dump files is kept in the directory %SystemRoot%\Minidump.


Creating a Kernel-Mode Dump File

There are three ways in which a kernel-mode dump file can be created:

  1. You can enable the dump file from the Control Panel, and then the system can crash on its own.
  2. You can enable the dump file from the Control Panel, and then force the system to crash.
  3. You can use the debugger to create a dump file without crashing the system.

This section includes:

Enabling a Kernel-Mode Dump File

Forcing a System Crash

Creating a Dump File Without a System Crash

Verifying the Creation of a Kernel-Mode Dump File

Using an NMI Switch

It is also possible to use an NMI switch to create a crash dump file. Contact your hardware vendor to determine whether your machine has this switch.

The usage of NMI switches is not covered in this documentation.


Enabling a Kernel-Mode Dump File

During a system crash, the Windows crash dump settings determine whether a dump file will be created, and if so, what size the dump file will be.

The Windows Control Panel controls the kernel-mode crash dump settings. Only a system administrator can modify these settings.

To change these settings, go to Control Panel and click on the System icon. Select the Advanced panel, and click on Startup and Recovery.

You will see the following dialog box:

Control Panel: Startup and Recovery Dialog Box

Under Write Debugging Information, you can select which of the three sizes of dump files you wish to have as the default. Only one dump file can be created for any given crash. The default crash dump size is Small Memory Dump. See Varieties of Kernel-Mode Dump Files for a description of the three file types.

After selecting the dump file size, you can accept or change the default dump file path and file name.

You can also select or deselect any of the Write an event to the system log, Send an administrative alert, and Automatically reboot options.

If you make any changes, the system will reboot after you click OK.

The settings that you select will apply to any kernel-mode dump file created by a system crash, regardless of whether the system crash was accidental or whether it was caused by the debugger. See Forcing a System Crash for details on causing a deliberate crash.

However, these settings do not affect dump files created by the .dump command. See Creating a Dump File Without a System Crash for details on using this command.


Forcing a System Crash

Once kernel-mode dump files have been enabled, most system crashes should cause a crash file to be written and the blue screen to be displayed.

However, there are times that a system freezes without actually initiating a kernel crash. Possible symptoms of such a freeze include:

  • The mouse pointer moves, but can't do anything.
  • All video is frozen, the mouse pointer does not move, but paging continues.
  • There is no response at all to the mouse or keyboard, and no use of the disk.

If an experienced debugging technician is present, he or she can hook up a kernel debugger and analyze the problem. For some tips on what to look for when this situation occurs, see Debugging a Stalled System.

However, if no technician is present, you may wish to create a kernel-mode dump file and send it to an off-site technician. This dump file can be used to analyze the cause of the error.

There are two ways to deliberately cause a system crash:

Forcing a System Crash from the Debugger

Forcing a System Crash from the Keyboard


Forcing a System Crash from the Debugger

If KD or WinDbg is performing kernel-mode debugging, it can force a system crash to occur. This is done by entering the .crash (Force System Crash) command at the command prompt. (If the target computer does not crash immediately, follow this with the G (Go) command.)

When this command is issued, the system will call KeBugCheck and issue bug check 0xE2 (MANUALLY_INITIATED_CRASH). Unless crash dumps have been disabled, a crash dump file is written at this point.

After the crash dump file has been written, the kernel debugger on the host computer will be alerted and can be used to actively debug the crashed target.


Forcing a System Crash from the Keyboard

A system crash can be directly caused from most non-USB keyboards.

Two preparations must be made before this can be done:

  1. If you wish a crash dump file to be written, you must enable such dump files, choose the path and file name, and select the size of the dump file. For details, see Enabling a Kernel-Mode Dump File.
  2. You must enable the keyboard-initiated crash in the registry. In the registry key HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\i8042prt\Parameters, create a value named CrashOnCtrlScroll, and set it equal to REG_DWORD 0x1 (or any nonzero value).

The system must be rebooted before these changes will take effect.

After this has been done, the keyboard crash can be initiated as follows. Hold down the rightmost CTRL key, and press the SCROLL LOCK key twice.

It is possible for a system to freeze in such a way that this CTRL+SCROLL LOCK+SCROLL LOCK sequence will not work. However, this should be a very rare occurrence. The CTRL+SCROLL LOCK+SCROLL LOCK crash initiation will work even in many instances where CTRL+ALT+DEL does not work.

The system then calls KeBugCheck and issues bug check 0xE2 (MANUALLY_INITIATED_CRASH). Unless crash dumps have been disabled, a crash dump file is written at this point.

If a kernel debugger is attached to the frozen machine, the machine will break into the kernel debugger after the crash dump file has been written.


Creating a Dump File Without a System Crash

If KD or WinDbg is performing kernel-mode debugging, it can cause a kernel-mode dump file to be written without crashing the target computer.

This dump file can be either a Complete Memory Dump or a Small Memory Dump. The Control Panel settings are not relevant to this action.

Whereas dump files caused by a system crash are written to the computer that has crashed, this dump file will be written to the host computer.

For details, see the .dump (Create Dump File) command.


Verifying the Creation of a Kernel-Mode Dump File

If you have a machine that has broken into the debugger, but you are unsure whether the crash dump file was successfully written, execute the following command:

dd nt!IopFinalCrashDumpStatus L1

This displays the value of the IopFinalCrashDumpStatus variable.

If this value equals zero, the process was successful. If it equals -1 (0xFFFFFFFF), the dump process has not started.

Any other value is a status code indicating an error during the dump process.


Analyzing a Kernel-Mode Dump File

This section includes:

Analyzing a Kernel-Mode Dump File with KD

Analyzing a Kernel-Mode Dump File with WinDbg

Analyzing a Kernel-Mode Dump File with KAnalyze

Installing Symbol Files

Regardless of which tool you use, you need to install the symbol files for the version of Windows that generated the dump file. These files will be used by the debugger you choose to use to analyze the dump file. For more information about the proper installation of symbol files, see Installing Windows Symbol Files.

DumpChk and DumpExam

The DumpExam tool is obsolete. It is no longer needed in the analysis of a crash dump file.


Analyzing a Kernel-Mode Dump File with KD

Kernel-mode memory dump files can be analyzed by KD. The processor or Windows version that the dump file was created on does not need to match the platform on which KD is being run.

Starting KD

To analyze a dump file, start KD with the -z command-line option:

kd -y SymbolPath -i ImagePath -z DumpFileName

The -v option (verbose mode) is also useful. For a full list of options, see KD Command-Line Options.

You can also open a dump file after the debugger is running by using the .opendump (Open Dump File) command, followed with G (Go).

It is possible to debug multiple dump files at the same time. This can be done by including multiple -z switches on the command line (each followed by a different file name), or by using the .opendump command to add additional dump files as debugger targets.

Dump files generally end with the extension .dmp or .mdmp. You can use network shares or Universal Naming Convention (UNC) file names for the memory dump file.

It is also common for dump files to be packed into a CAB file. If you specify the file name (including the .cab extension) after the -z option or as the argument to an .opendump command, the debugger can read the dump files directly out of the CAB. However, if there are multiple dump files stored in a single CAB, the debugger will only be able to read one of them. The debugger will not read any additional files from the CAB, even if they were symbol files or other files associated with the dump file.

Analyzing the Dump File

If you are analyzing a Kernel Memory Dump or a Small Memory Dump, you may need to set the executable image path to point to any executable files which may have been loaded in memory at the time of the crash. See Setting Paths and Loading Files for details.

Analysis of a dump file is similar to analysis of a live debugging session. See the Debugger Commands reference section for details on which commands are available for debugging dump files in kernel mode.

In most cases, you should begin by using !analyze. This extension command performs automatic analysis of the dump file and can often result in a lot of useful information.

The .bugcheck (Display Bug Check Data) shows the bug check code and its parameters. Look up this bug check in the Bug Check Code Reference for information on the specific error.

The following debugger extensions are especially useful for analyzing a kernel-mode crash dump:

!drivers

!kdext*.locks

!memusage

!vm

!errlog

!process 0 0

!process 0 7


Analyzing a Kernel-Mode Dump File with WinDbg

Kernel-mode memory dump files can be analyzed by WinDbg. The processor or Windows version that the dump file was created on does not need to match the platform on which KD is being run.

Starting WinDbg

To analyze a dump file, start WinDbg with the -z command-line option:

windbg -y SymbolPath -i ImagePath -z DumpFileName

The -v option (verbose mode) is also useful. For a full list of options, see WinDbg Command-Line Options.

If WinDbg is already running and is in dormant mode, you can open a crash dump by selecting the File | Open Crash Dump menu command or pressing the CTRL+D shortcut key. When the Open Crash Dump dialog box appears, enter the full path and name of the crash dump file in the File name text box, or use the dialog box to select the proper path and file name. When the proper file has been chosen, click Open.

You can also open a dump file after the debugger is running by using the .opendump (Open Dump File) command, followed with G (Go).

It is possible to debug multiple dump files at the same time. This can be done by including multiple -z switches on the command line (each followed by a different file name), or by using the .opendump command to add additional dump files as debugger targets.

Dump files generally end with the extension .dmp or .mdmp. You can use network shares or Universal Naming Convention (UNC) file names for the memory dump file.

It is also common for dump files to be packed into a CAB file. If you specify the file name (including the .cab extension) after the -z option or as the argument to an .opendump command, the debugger can read the dump files directly out of the CAB. However, if there are multiple dump files stored in a single CAB, the debugger will only be able to read one of them. The debugger will not read any additional files from the CAB, even if they were symbol files or other files associated with the dump file.

Analyzing the Dump File

If you are analyzing a Kernel Memory Dump or a Small Memory Dump, you may need to set the executable image path to point to any executable files that may have been loaded in memory at the time of the crash. See Setting Paths and Loading Files for details.

Analysis of a dump file is similar to analysis of a live debugging session. See the Debugger Commands reference section for details on which commands are available for debugging dump files in kernel mode.

In most cases, you should begin by using !analyze. This extension command performs automatic analysis of the dump file and can often result in a lot of useful information.

The .bugcheck (Display Bug Check Data) shows the bug check code and its parameters. Look up this bug check in the Bug Check Code Reference for information on the specific error.

The following debugger extensions are especially useful for analyzing a kernel-mode crash dump:

!drivers

!kdext*.locks

!memusage

!vm

!errlog

!process 0 0

!process 0 7


Analyzing a Kernel-Mode Dump File with KAnalyze

Kernel Memory Space Analyzer (KAnalyze, kanalyze.exe) is another tool that can examine kernel-mode dump files.

KAnalyze and its documentation are part of the OEM Support Tools package.

To download these tools, search for Knowledge Base article Q253066 at http://support.microsoft.com/default.aspx and follow the instructions on that page.


User-Mode Dump Files

This section includes:

Varieties of User-Mode Dump Files

Creating a User-Mode Dump File

Analyzing a User-Mode Dump File


Varieties of User-Mode Dump Files

There are several kinds of user-mode crash dump files, but they are divided into two categories:

Full User-Mode Dumps

Minidumps and Microdumps

The difference between these dump files is one of size. Minidumps and microdumps are compact, and can be easily sent to an analyst.

Note Much information can be obtained by analyzing a dump file. However, no dump file can provide as much information as actually debugging the crash directly with a debugger.


Full User-Mode Dumps

A full user-mode dump is the basic user-mode dump file.

This dump file includes the entire memory space of a process, the program's executable image itself, the handle table, and other information that will be useful to the debugger.

It is possible to "shrink" a full user-mode dump file into a minidump. Simply load the dump file into the debugger and then use the .dump (Create Dump File) command to save a new dump file in minidump format.

Note Despite their names, the largest "minidump" file actually contains more information than the full user-mode dump. For example, .dump /mf or .dump /ma will create a larger and more complete file than .dump /f.


Minidumps and Microdumps

A user-mode dump file that includes only selected parts of the memory associated with a process is called a minidump.

The size and contents of a minidump file varies depending on the program being dumped and the application doing the dumping. Sometimes, a minidump file is fairly large and includes the full memory and handle table. Other times, it is much smaller.

The smallest minidump files are called microdumps. These include very little information. For example, they might only contain information about a single thread, or information about modules that are actually referenced in the stack, or they might even include a truncated version of the stack.

The largest minidump files actually contain more information than the "full" user-mode dump. For example, .dump /mf or .dump /ma will create a larger and more complete file than .dump /f.

If you are creating a minidump file with the debugger, you can choose exactly what information to include. A simple .dump /m command will include basic information about the loaded modules that make up the target process, thread information, and stack information. This can be modified by using any of the following options:

.dump option | Effect on dump file
/mf | Adds full memory data to the minidump. All accessible committed pages owned by the target application will be included.
/mh | Adds data about the handles associated with the target application to the minidump.
/mu | Adds unloaded module information to the minidump. This is only available in Windows .NET Server 2003.
/ma | Creates the largest minidump. The /ma option is equivalent to /mfhu — it adds full memory data, handle data, and unloaded module information to the minidump.
/mi | Adds secondary memory to the minidump. Secondary memory is any memory referenced by a pointer on the stack or backing store, plus a small region surrounding this address.
/mp | Adds process environment block (PEB) and thread environment block (TEB) data to the minidump. This can be useful if you need access to Windows system information regarding the application's processes and threads.
/mw | Adds all committed read-write private pages to the minidump.
/md | Adds all read-write data segments within the executable image to the minidump.
/mr | Deletes from the minidump those portions of the stack and store memory that are not useful for recreating the stack trace. Local variables and other data type values are deleted as well. This option does not make the minidump smaller (since these memory sections are simply zeroed), but it is useful if you wish to protect the privacy of other applications.
/mR | Deletes the full module paths from the minidump. Only the module names will be included. This is a useful option if you wish to protect the privacy of the user's directory structure.

These options can be combined. For example, the command .dump /mfiu can be used to create a fairly large minidump, or the command .dump /mrR can be used to create a minidump that preserves the user's privacy. For full syntax details, see .dump (Create Dump File).

For details on the internals of minidump files, see the DbgHelp Reference in the Platform SDK.


Creating a User-Mode Dump File

This section includes:

Autodump+

Dr. Watson

CDB and WinDbg

UserDump

Each of these tools can be used to create user-mode dump files, but each of them has different abilities. The following table shows the features of each tool.

Feature | Autodump+ | Dr. Watson | CDB and WinDbg | UserDump
Creating a dump file when an application crashes (postmortem debugging) | Yes | Yes | Yes | Yes
Creating a dump file when an application "hangs" (stops responding but does not actually crash) | Yes | No | Yes | Yes
Creating a dump file when an application encounters an exception | Yes | Yes | Yes | Yes
Creating a dump file while an application is running normally | No | No | Yes | No
Creating a dump file from an application that fails during startup | No | No | Yes | Yes
Shrinking an existing dump file | No | No | Yes | No


Autodump+

This section includes:

Introduction to Autodump+

Autodump+ Modes of Operation

Running Autodump+

Windows Server Configuration

Common Autodump+ Scenarios

Additional Autodump+ Information


Introduction to Autodump+

This section includes:

What Autodump+ Does

When Autodump+ Can Be Used


What Autodump+ Does

Autodump+ is a console-based Microsoft® Visual Basic® script. It automates the CDB debugger to produce memory dumps and log files that contain debug output from one or more processes.

Each time Autodump+ is run, debugging information — memory dumps and text files that contain debug information — is placed in a new, uniquely named folder (such as C:\Temp\Crash_Mode__Date_01-22-2001__Time_09-41-08AM) on the local file system or a remote network share. In addition, each file that Autodump+ creates is also given a unique name (such as PID-1708__Inetinfo.exe__Date_01-22-2001__Time_09-41-08AM.log) to avoid overwriting older files with newer ones.

Autodump+ works with any user-mode process or service such as IIS, Microsoft Transaction Server (MTS), or Microsoft COM+ applications.

The following are some of the features of Autodump+:

  • Autodump+ uses the latest Microsoft debuggers for speed and reliability.
  • When Autodump+ is dumping memory for multiple processes, it does so asynchronously so that each process is frozen and dumped at the same time, which can provide an effective "snapshot" of the entire application at the time Autodump+ was run. It is important to capture all of the processes that compose a given application and all the processes that a given application makes use of at the same time so that you can capture the state of the application at the time the problem occurs. This is especially important for applications that make remote procedure calls to other processes.
  • Autodump+ has a command-line interface. Because Autodump+ does not have a graphical user interface, it can be run with the -quiet option from within a remote command shell (a Command Prompt window that is controlled through Remote.exe). The -quiet option suppresses all popup dialog boxes, and logs all output to the event log. For more information on how to run Autodump+ from a remote command shell, see Running in Crash Mode Remotely.
  • When Autodump+ monitors for crashes, it can alert a user or computer of a crash through the Windows Messenger service. This feature is activated though the -notify command-line option.
  • When Autodump+ monitors a process in crash mode and a crash occurs, Autodump+ sends important information about the type of crash to the event log.
  • Autodump+ supports XCOPY deployment — if you copy the Debugging Tools for Windows installation folder to a new location, it will still work properly. In addition, Autodump+ does not require that you register any custom Component Object Model (COM) components on the system, which makes this tool ideal for use on production servers that have a locked-down software configuration. To remove Autodump+, simply delete the folder to which it was installed or copied.

Note The tool known as Exception Monitor is obsolete. Autodump+ subsumes all the functionality of Exception Monitor.


When Autodump+ Can Be Used

Autodump+ is capable of creating a detailed dump file in a variety of scenarios. This file contains debugging information that is needed to isolate the cause of problems that arise in complex environments.

When Should You Use Autodump+?

You should use Autodump+ to capture debugging information if you are experiencing the following problems:

  • Processes that hang.
  • Processes that have 100 percent CPU utilization on a single processor computer, 50 percent on a dual processor computer, 25 percent on a quad processor computer, and so on.
  • Processes that crash or shut down unexpectedly.

When Shouldn't You Use Autodump+?

You should not use Autodump+ in the following situations:

  • If you need to troubleshoot a program or process that terminates unexpectedly upon startup.

    You can only use Autodump+ with processes that start successfully. If you need to troubleshoot processes that terminate unexpectedly upon startup, you should use CDB, WinDbg, or UserDump instead.

  • If there is a noticeable performance impact when you use Autodump+ in crash mode.

    This is usually caused by dynamic-link libraries (DLLs) or programs that throw a large number of Microsoft® Visual C++® EH exceptions (which occur when you use the C++ throw statement or when you use try/catch blocks). Programs that write a large amount of information to the debug output stream can also cause a performance degradation. In the vast majority of cases, Autodump+ does not impact performance noticeably when it is running in crash mode.


Autodump+ Modes of Operation

Autodump+ has three modes of operation:

  • Hang Mode is used to troubleshoot process that hangs, 100 percent CPU utilization, and other problems that do not involve a crash. When you use Autodump+ in hang mode, you must wait until the process hangs before you run the script.
  • Quick Mode is a light-weight version of hang mode that produces minidump files of the specified processes and a debug log file with extended debugging information. For processes that consume large amounts of virtual memory, quick mode can be significantly faster than regular hang mode.
  • Crash Mode is used to troubleshoot crashes that would normally activate a postmortem debugger, or any other type of error that causes a program or service to terminate unexpectedly. When you use Autodump+ in crash mode, you must start Autodump+ before the crash occurs. Autodump+ can be configured to notify an administrator or a computer of a crash through the -notify option.


Hang Mode

In hang mode, Autodump+ immediately produces full memory dumps for all of the processes that are specified on the command line after the script is finished running. Each .dmp file created goes into a folder that contains the date/time stamp from when Autodump+ was run, and each file name contains the process name, the process ID, and the date/time stamp from when Autodump+ was run. While the process memory is being dumped to a file, the process is frozen, with the debugger non-invasively attached to it. After the memory dump is finished, the debugger detaches and the process resumes.

You can use Autodump+ in hang mode in place of UserDump to dump the memory for one or more processes. In addition, hang mode works inside a Terminal Server session.


Quick Mode

In quick mode, Autodump+ produces log files from a scripted debug session and minidump files, which are usually less than 100 KB in size. This mode is usually faster than creating full memory dumps for each process that is specified on the command line.

A minidump file is especially useful if you do not plan to analyze it yourself. A small dump file can easily be zipped and sent in an email message to a professional support technician. This is easier than having to place the files on an FTP site or use some other method of transfer.


Crash Mode

In crash mode, Autodump+ attaches the CDB debugger to all processes that are specified on the command line and automatically configures the debugger to monitor for the following kinds of exceptions:

  • Invalid handle
  • Illegal instruction
  • Integer divide-by-zero
  • Floating point divide-by-zero
  • Integer overflow
  • Invalid lock sequence
  • Access violation
  • Stack overflow
  • C++ EH exception
  • Unknown exception

You can use Autodump+ in crash mode in place of UserDump when you are troubleshooting these kinds of exceptions.

Because crash mode uses an "invasive" attach through the CDB debugger, it does not work inside a Microsoft® Windows NT® 4.0 or Windows® 2000 Terminal Server session, as these operating systems will not permit a debugger in one window station to attach to a process in a different window station. Crash mode is supported in a Terminal Server session on Windows XP and Windows .NET Server 2003 platforms. Quick mode and hang mode will work inside a Terminal Server session on any platform.

Note For a work-around in Windows NT or Windows 2000 Terminal Server using remote.exe, see Running in Crash Mode Remotely. For general information on invasive and non-invasive attaching, see Starting the Debugger.

When Autodump+ is running in crash mode, a debugger remains attached to each process that is specified on the command line for the lifetime of that process until a fatal exception is trapped and the process crashes, or until a user presses CTRL+C to detach the debugger from that process. To manually detach the debugger from the process, you must maximize the debugger window and press CTRL+C to break into the debugger. When you press CTRL+C, Autodump+ traps this command, begins to list the stacks for all threads to a log file, and then produces a minidump file of the process before it detaches from the debugger. Because crash mode performs an invasive attach, the process is terminated when the debugger is detached, and it will have to be restarted. If it is an MTS or COM+ process, the process is restarted automatically the next time a call is made to a component in that package.

First Chance Exceptions

Each kind of exception (access violation, stack overflow, and so on) can be raised to a debugger as either a "first chance" or "second chance" exception. First chance exceptions are, by definition, non-fatal unless they are not handled properly with an error handler, at which point they are raised again as a second chance exception (which only a debugger can handle). If no debugger handles a second chance exception, the application is shut down.

By default, when Autodump+ detects a first chance (non-fatal) exception for all types of exceptions except unknown and EH exceptions, it takes the following actions:

  1. Pauses the process to log the date and time that the exception occurred in the log file for the process that is being monitored.
  2. Logs the thread ID and call stack for the thread that raised the exception in the log file for the process that is being monitored.
  3. Produces a uniquely-named minidump file of the process at the time the exception occurred and then resumes the process.(This is equivalent to .dump -u /m.)

By default, Autodump+ does not produce a unique minidump file for first chance EH and unknown exceptions because it is quite common for a process to encounter a significant number of these exceptions, which are usually handled by error handling code within a process or DLL. In other words, these exceptions are usually handled exceptions, and they do not become second chance (unhandled) exceptions, which terminate the process.

However, you can configure Autodump+ to produce unique minidump files for first chance EH and unknown exceptions. To do this, you must set a constant in the script. For more information about these constants, see Micromanaging Autodump+.

Second Chance Exceptions

When Autodump+ detects a second chance (fatal) exception for all types of exceptions (including EH and unknown exceptions), it takes the following actions:

  1. Pauses the process.
  2. Logs the date and time that the exception occurred.
  3. Logs the thread ID and the call stack for the thread that raised the exception.
  4. Produces a full memory dump of the process at the time the fatal exception occurred.
  5. Exits the debugger. This terminates the process.

Autodump+ keeps a separate log file for each process that it monitors.


Running Autodump+

This section includes:

Running Autodump+ the First Time

The Autodump+ Command Line


Running Autodump+ the First Time

To run Autodump+, open a Command Prompt window, switch to the folder to which the debuggers were installed or copied, and type the following:

adplus.vbs

You might be prompted to change your default script interpreter from WScript.exe to CScript.exe. Microsoft strongly recommends that you allow Autodump+ to set CScript as the default script interpreter.


The Autodump+ Command Line

To use Autodump+, you must specify a series of command-line options or arguments to the script. At a minimum, Autodump+ requires two command-line options: one that specifies the mode of operation, and one that specifies a target process to operate against.

For details, see Autodump+ Command-Line Options.


Windows Server Configuration

Before you run Autodump+ in crash mode on Windows 2000 Server or Windows NT Server, you should properly prepare the server to get the most information out of the Autodump+ crash-mode debugging sessions.

This section includes:

Windows 2000 Server Configuration

Windows NT Server Configuration


Windows 2000 Server Configuration

If you wish to run Autodump+ in crash mode on Windows 2000 Server, you should perform the following procedure first.

To prepare a Windows 2000 Server for debugging in crash mode

  1. Install the Windows 2000 SP1 or SP2 symbols (Sp1sym.exe or Sp2sym.exe) to the C:\WINNT\Symbols folder on your servers. You can download the symbols from the following Microsoft Web sites:

    Windows 2000 SP1:

    http://www.microsoft.com/windows2000/downloads/servicepacks/sp1/debug/default.asp

    Windows 2000 SP2:

    http://www.microsoft.com/windows2000/downloads/servicepacks/sp2/debug/default.asp

  2. After you download Sp1sym.exe or Sp2sym.exe, run the file from the designated folder.
  3. When you are prompted, extract the files to a new temporary folder, such as C:\Sp1sym or C:\Sp2sym, or to a drive or folder that has enough disk space.
  4. Run C:\Sp1sym\Support\Debug\Symbols\i386\Symbolsx.exe or C:\Sp2sym\Support\Debug\Symbols\i386\Symbolsx.exe (where C:\Sp1sym or C:\Sp2sym is the folder to which you extracted the files in the preceding step).
  5. Read the license agreement. If you agree, click Yes.
  6. When you are prompted for a directory to which you can extract the files, select C:\WINNT\Symbols, and then click OK. Notice that a new C:\WINNT\Symbols directory appears with various subdirectories named DLL, EXE, and so on.
  7. Copy the symbols for your custom DLLs and any post-SP1 or post-SP2 hotfixes to the C:\WINNT\Symbols\DLL folder.
  8. Copy the symbols for your custom .exe files to the C:\WINNT\Symbols\EXE folder. In addition, you must obtain any .pdb or .dbg files related to the target application and place these files in the C:\WINNT\Symbols\DLL folder.
  9. Overwrite any .dbg or .pdb files that already exist in the C:\WINNT\Symbols\DLL directory with versions from your hotfixes.

    You can use the latest version of WinZip to open hotfix packages. You can extract the symbols from the \Debug subdirectory, which is contained in each hotfix self-installer.

  10. Create an _NT_SYMBOL_PATH environment variable, and set it equal to "C:\WINNT\Symbols". This variable can be either a system environment variable or a user environment variable.


Windows NT Server Configuration

If you wish to run Autodump+ in crash mode on Windows NT 4.0 Server, you should perform the following procedure first.

To prepare Windows NT 4.0 Server for debugging in crash mode

  1. Assuming that you are running Windows NT 4.0 Service Pack 6a, install the Windows NT 4.0 SP 6a symbols (Sp6symi.exe) to the C:\WINNT\Symbols folder on your servers. You can download the symbols from the following Microsoft Web site:

    http://www.microsoft.com/ntserver/nts/downloads/recommended/SP6/debug/default.asp

  2. After you download Sp6symi.exe, run it from the designated folder.
  3. When you are prompted, extract the files to the C:\WINNT folder (or substitute the appropriate \WINNT directory if the symbols were not installed to C:\WINNT). Notice that a new C:\WINNT\Symbols folder appears with various subdirectories named DLL, EXE, and so on.
  4. Copy the subdirectories from the C:\WINNT\Symbols\IIS4 directory to C:\WINNT\Symbols. When you are prompted to overwrite all the files, click Yes.
  5. Copy the symbols for your custom DLLs and any post-SP 6a hotfixes to the C:\WINNT\Symbols\DLL folder.
  6. Copy the symbols for your custom .exe files to the C:\WINNT\Symbols\EXE folder. In addition, you must obtain any .pdb or .dbg files for the target application and place these files in the C:\WINNT\Symbols\DLL directory.
  7. Overwrite any .dbg or .pdb files that already exist in the C:\WINNT\Symbols\DLL directory with versions from your hotfixes.

    You can use the latest version of WinZip to open hotfix packages. You can extract the symbols from the \Debug subdirectory, which is contained in each hotfix self-installer.

  8. Create an _NT_SYMBOL_PATH environment variable, and set it equal to "C:\WINNT\Symbols". This variable can be either a system or user-environment variable.

Though it is not required that you download and install symbols on the servers that are being debugged, it is highly recommended. When you download and install symbols on the server, the output that is captured in the log files is much more useful.


Common Autodump+ Scenarios

This section outlines some of the more common scenarios in which it might be necessary to run Autodump+:

Process Hangs or Consumes 100 Percent of CPU

Process Ends Unexpectedly

MTS or COM+ Server Application Ends Unexpectedly

Running in Crash Mode Remotely

Monitoring Autodump+ in Crash Mode


Process Hangs or Consumes 100 Percent of CPU

Autodump+ can be used to diagnose a process that has hung or is consuming 100 percent CPU (for sustained periods of time, or indefinitely). If you wish to diagnose this problem after it has begun, you should run Autodump+ in hang mode to obtain a memory dump of the process.

Running Autodump+ in hang mode during the 100 percent CPU condition produces memory dumps of the process or processes that are specified on the command line.

For example, use one of the following command syntaxes:

ADPlus -hang -p 1896

This command runs Autodump+ in hang mode and produces a full memory dump of a process with PID 1896.

ADPlus -hang -pn myapp.exe

This command runs Autodump+ in hang mode and produces full memory dumps of all processes that are named Myapp.exe.

ADPlus -hang -iis -pn myapp.exe -o c:\temp

This command runs Autodump+ in hang mode and produces full memory dumps of IIS, all instances of Mtx.exe or Dllhost.exe, and all processes that are named Myapp.exe. It then places the memory dumps in the C:\Temp folder.

Unable to Attach in Hang Mode

In certain rare situations, it might not be possible for the debugger to attach to the process after the 100 percent CPU condition or hang has occurred, and running Autodump+ in hang mode after the problem has occurred might not produce memory dumps. In these scenarios, it might be best to attach the debugger before the problem has occurred. To do this, run Autodump+ in crash mode as follows:

ADPlus -crash -p 1896

This command runs Autodump+ in crash mode for a process with PID 1896 and waits for an exception or a user to press CTRL+C in the minimized debugger window to generate a memory dump and detach the debugger.

ADPlus -crash -pn myapp.exe

This command runs Autodump+ in crash mode for the process named Myapp.exe and waits for an exception or a user to press CTRL+C in the minimized debugger window to generate a memory dump and detach the debugger.

ADPlus -crash -iis -pn myapp.exe -o c:\temp

This command runs Autodump+ in crash mode for all instances of the process named Myapp.exe, in addition to Inetinfo.exe and all instances of Mtx.exe or Dllhost.exe. The minimized debugger then waits for an exception or a user to press CTRL+C in the minimized debugger window to generate a memory dump and detach the debugger. The memory dumps and log files are then placed in the C:\Temp folder.

Reconfiguring Autodump+

By default, Autodump+ only produces minidump files when the user presses CTRL+C. This is done to conserve disk space. In this scenario, it may be useful to configure Autodump+ to generate a full memory dump when the user presses CTRL+C. To do this, set the Full_Dump_on_CONTRL_C constant to TRUE. For example:

Const Full_Dump_on_CONTRL_C = TRUE

See Micromanaging Autodump+ for details.

In addition, it is often helpful to capture a performance or system monitor log file for the time period up to and including the 100 percent CPU condition. At a minimum, this log file should capture the following objects at 1 to 5 second intervals:

  • Memory
  • Process
  • Processor
  • System
  • Thread

Additional Information

For another method of debugging a process that is consuming 100% of CPU, see Tracking Down a Processor Hog.


Process Ends Unexpectedly

If a process randomly crashes or shuts down unexpectedly, you can run Autodump+ in crash mode to obtain a memory dump of the process that is crashing before the problem occurs.

For example, use one of the following command syntaxes:

ADPlus -crash -iis

This command runs Autodump+ in crash mode and causes it to attach the CDB debugger to Inetinfo.exe and all Mtx.exe or Dllhost.exe processes that are running on the computer. Autodump+ then waits for any first chance and second chance exceptions. Because the -o option is omitted, Autodump+ places all files in a subfolder below the installation folder by default.

ADPlus -quiet -crash -iis -notify RemoteComputer -o c:\temp

This command runs Autodump+ in crash mode and causes it to attach the CDB debugger to Inetinfo.exe and all Mtx.exe or Dllhost.exe processes that are running on the computer. The -quiet option suppresses all popup dialog boxes, and logs all output to the event log. Because the -notify option is used, the debuggers notify all users who are logged on to the computer named RemoteComputer whenever a crash is detected or when the process that is being monitored shuts down. Because the -o option is used, all output is placed in the C:\Temp folder. If the folder does not exist, it is created.

ADPlus -crash -iis -o \\Server\Share

This command is the same as the previous one except that it logs all output to a network server. A new subfolder is created under \\server\share; the subfolder's name is based on the name of the local computer. Thus, if you are running Autodump+ in a Web farm, each server in the farm on which Autodump+ is running logs its own unique folder under \\server\share. (You do not have to create unique folders for each server — this is done automatically.)

Running From a Local Console

If you are running Autodump+ in crash mode from the local console rather than remotely, you must remain logged on to the console for the duration of the debug session.

For example, when Autodump+ is launched in crash mode with the -iis option to monitor IIS, then when the launching user logs out of the console, the copies of CDB that are running on the console will be closed (along with all other running applications). As a result, debugging stops, and the process that is being monitored is ended.

To avoid this issue, you can lock the console session (press the CTRL+ALT+DEL key combination, and then click Lock Computer), or run Autodump+ inside a remote command shell that has been configured not to require an interactive logon.

For more information on scheduling a remote command shell to run non-interactively, see Running in Crash Mode Remotely.


MTS or COM+ Server Application Ends Unexpectedly

Custom Component Object Model (COM) components that run inside of an MTS or COM+ server application actually run inside of a surrogate process (Mtx.exe or Dllhost.exe). These surrogate processes have properties and settings that you can configure through the MTS Explorer (in Windows NT 4.0) or the Component Services Microsoft Management Console (MMC) snap-in (in Windows 2000, Windows XP, and Windows .NET Server 2003).

By default, MTS or COM+ server applications are configured to shut down after 3 minutes of idle time. To ensure that these processes remain running while the debugger is attached and monitoring for exceptions, you must configure them to "Leave running when idle".

In addition, MTS and COM+ implement a failfast, which is a safeguard that is designed to fail (or shut down) MTS/COM+ processes that generate unhandled access violations.

Failfast is enabled by default in MTS or COM+ applications that raise unhandled access violation exceptions. As a result, a failing MTS/COM+ server application never gets a chance to raise a second chance access violation exception (that is, it is shut down after the first chance access violation). By default, Autodump+ is configured to only produce a minidump file on first chance exceptions.

To debug an MTS/COM+ server application

  1. Configure the MTS/COM+ server application to "Leave running when idle."
  2. Set the Create_Full_Dump_On_1st_Chance_Exception constant to TRUE in ADPlus.vbs. See Micromanaging Autodump+ for details.
  3. Run Autodump+ in crash mode and wait for the application to fail.

Because MTS and COM+ shut down a server application, and because the process is not given a chance to raise a second chance exception due to the failfast policy, you might only be able to obtain a first chance access violation memory dump.


Running in Crash Mode Remotely

There are many occasions when it is necessary to initiate Autodump+ in crash mode from a local client computer to monitor a process that terminates unexpectedly on one or more remote servers in a server farm. Typically, on Windows 2000, this is done through Windows Terminal Services. However, because it is not possible to debug applications that are running in different window stations on Windows NT 4.0 and Windows 2000, Autodump+ disables crash mode functionality when it detects that it is running inside of a Terminal Services session.

The solution is to create a batch file that opens a Command Prompt window on the remote server which has been shared by using the remote.exe utility, and then schedule this batch file to run on the target server using the "AT" command (which causes the command shell to run non-interactively, similar to a service). The remote command shell is then connected to a local workstation or client computer that uses the same remote.exe utility that was used to start it.

To start a remote command shell on a server by using the 'AT' command, you must follow the correct procedure on the remote server and the local client.

Ideally, you should install the debuggers on the local client computer. If this is not feasible, at the very least you should place a copy of the remote.exe utility on the local client. The following procedure assumes that Debugging Tools for Windows package is installed in C:\Debuggers on the remote server, and that this package (or at least remote.exe) is installed in D:\Debuggers on the local client. Adjust this procedure to the actual installation on your computers.

To set up a remote command shell on the server

  1. Create a new batch file named Remoteshell.cmd in the C:\Debuggers folder.
  2. Add the following line to this batch file:
    c:\debuggers\remote.exe /s "cmd.exe" remoteshell
  3. At the console on the server or in a Terminal Services session, open a new Command Prompt window, and type the following command:
    AT 15:00 c:\debuggers\remoteshell.cmd

    where "15:00" is one minute later than the current time. For example, if the current time is 14:59, type 15:00.

  4. Wait for the 'AT' command to run.
  5. At the command prompt, type AT with no parameters to verify that the task has run with no errors.

To connect to the remote command shell from the client

  1. At a command prompt, switch to the D:\Debuggers directory.
  2. Type the following command:
    remote.exe /c RemoteServer remoteshell

    where RemoteServer is the name of the remote server.

  3. Your local command shell is now connected to the remote command shell that is running on the server, and all commands that you type locally will be carried out on the remote server. For example, the dir c:\ command lists the contents of the remote server's drive C.
  4. In the remote command shell, you can now run Autodump+ in crash mode as if you were running it locally from the console. However, you must use the -quiet option to suppress all dialog boxes that Autodump+ displays by default. If you do not use this option, the remote command shell will hang after you run Autodump+ and will not return to a prompt, at which point you must close the Command Prompt window on the server and start a new instance.
  5. To send a debug break (CTRL+C) to a process that Autodump+ is currently debugging remotely through crash mode, you must use the Breakin.exe utility, which is installed by default with the debuggers in the root of the debuggers directory. For example, to stop debugging IIS (Inetinfo.exe) that is running with a process ID of 1975, type the following command in the remote command shell:
    breakin.exe 1975

    Alternatively, you can use the Kill.exe utility to terminate any processes that are being debugged. This utility is located in the root directory of the Debugging Tools for Windows installation tree.


Monitoring Autodump+ in Crash Mode

There are several ways to determine if Autodump+ has captured information about a crash, or if a process that is being monitored in crash mode has shut down:

  • Use the -notify option, and ensure that the messenger service is started on the server that is being debugged and on the client computer that will receive notifications.
  • In the output directory, open the .log file for each process in a text editor, and scroll to the end of the file. Look for the following text:
    0:070> * -------- AutodumpPlus 4.01 finished running at: --------
0:070> .time
Debug session time: Mon Aug 06 15:25:15 2001
System Uptime: 3 days 17:00:34
Process Uptime: 1 days 3:10:38
0:070> * -------------------------------------------------------
  • In the output directory, look for any .dmp files that contain the phrase "__2nd_chance". If a memory dump is labeled with this phrase, a process has crashed.
  • In the output directory, look for any .dmp files that contain the phrase "__Process_was_shutdown". If a memory dump is labeled with this phrase, the process was terminated by an administrator or, if it is an MTS/COM+ application, it may have been shut down because the idle limit was reached.
  • In the output directory, look for any .dmp files that contain the phrase "__CTRL-C". If a memory dump is labeled with this phrase, either a debug break exception was thrown from a DLL that was running inside the process, or someone pressed CTRL+C from the console (or used Breakin.exe if running remotely) to stop the current debugging session.


Additional Autodump+ Information

This section includes:

Micromanaging Autodump+

Autodump+ Limitations and Restrictions


Micromanaging Autodump+

Although it is usually not necessary in most cases, you can change the default behavior of Autodump+ by using predefined constants that are located near the beginning of the script. To configure Autodump+ to do this, edit ADPlus.vbs with a text editor and set the constants to the proper values.

Here is an excerpt from ADPlus.vbs that shows the important constants and their meanings:

' Set DEBUGGING = TRUE to turn on verbose debug output, which is useful for troubleshooting
' ADPlus problems.
Const DEBUGGING = FALSE

' Set Full_Dump_on_CONTRL_C to TRUE if you want to have ADPlus produce a full memory dump
' (as opposed to a mini memory dump) whenever CTRL-C is pressed to stop debugging
' when running in crash mode.
' NOTE: Depending on the number of processes that are being monitored, this could generate
' a signifigant amount of memory dumps.
Const Full_Dump_on_CONTRL_C = FALSE

' Set Create_Full_Dump_on_1st_Chance_Exception to TRUE if you want ADPlus to produce
' a full memory dump for the process each time it encounters a first chance exception.
' This is disabled by default for performance reasons. This is particularly useful
' if you are troubleshooting MTS or COM+ packages that get shut down after a first chance
' unhandled exception and do not reach a second chance exception state before the process
' is shut down.
Const Create_Full_Dump_on_1st_Chance_Exception = FALSE

' Set No_Dump_on_1st_Chance_Exception to TRUE if you do not want ADPlus to produce any memory
' dumps when it encounters first chance exceptions. You may want to do this if a very high rate
' of first chance exceptions is encountered (for example, hundreds per minute)
' and if the debugger is spending too much time producing mini memory dumps, which
' cause the process to appear to hang.
' NOTE: You should NOT set this constant to TRUE if
' Create_Full_Dump_on_1st_Chance_Exception (the preceding constant) is ALSO set to TRUE
' because this produces mutually exclusive behavior.
Const No_Dump_on_1st_Chance_Exception = FALSE

' Set Dump_on_EH_Exceptions to TRUE if you want ADPlus to produce a memory dump each time
' it encounters a C++ EH exception. This is disabled by default for performance reasons.
Const Dump_on_EH_Exceptions = FALSE

' Set Dump_on_Unknown_Exceptions = TRUE if you want ADPlus to produce a memory dump each time
' it encounters an unknown exception. This is disabled by default for performance reasons.
Const Dump_on_Unknown_Exceptions = FALSE

' Set Dump_Stack_on_DLL_Load = TRUE if you want ADPlus to dump the stack each time
' a DLL is loaded. This is disabled by default for performance reasons.
Const Dump_Stack_on_DLL_Load = FALSE

' Set Dump_Stack_on_DLL_Load_Unload = TRUE if you want ADPlus to dump the stack each time
' a DLL is unloaded. This is disabled by default for performance reasons.
Const Dump_Stack_on_DLL_UnLoad = FALSE

' Set No_CrashMode_Log = TRUE if you do NOT want ADPlus to create a log file in Crash Mode.
' If a process is generating a lot of exceptions, the debug log file that is created
' in crash mode can become quite large.
Const No_CrashMode_Log = FALSE

' Set No_Free_Space_Checking = TRUE if you do NOT want ADPlus to check for free space
' before running. Certain RAID drivers can cause problems for the free space checking
' routines, and it may be necessary to set this to TRUE to allow ADPlus to run.
Const No_Free_Space_Checking = FALSE

' Set MAX_APPLICATIONS_TO_DEBUG to whatever upper limit you want to impose on the -IIS switch.
' By default, MAX_APPLICATIONS_TO_DEBUG defaults to 20 to limit the number of MTS
' or COM+ applications ADPlus will dump or monitor.
' NOTE: If there are 30 running MTS or COM+ applications, and MAX_APPLICATIONS_TO_DEBUG
' is set to 20, ADPlus displays an error message that indicates that there are too many
' applications running and then quits.
Const MAX_APPLICATIONS_TO_DEBUG = 20


Autodump+ Limitations and Restrictions

The following notes and restrictions apply to Autodump+:

  • The -iis option only works if Internet Information Server (IIS) 4.0 or Internet Information Services (IIS) 5.x or higher is installed.
  • Autodump+ might display the following error:

    AutodumpPlus has detected that the following registry value HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\NTFSDisable8Dot3NameCreation is set to 1. AutodumpPlus will not work properly with 8.3 path's disabled. Please set this value to 0 and reboot the server before running AutodumpPlus again.

    For additional information about this registry setting, search for Knowledge Base article Q253066, "How to Disable the 8.3 Name Creation on NTFS Partitions", at http://support.microsoft.com/default.aspx.

    After you change this registry value to zero, you may receive the following error message the next time you try to run Autodump+:

    AutodumpPlus encountered an error trying to get the short path name for the following directory: "C:\Program Files\Debugging Tools for Windows". AutodumpPlus can not continue.

    Even though 8.3 name creation is now enabled for the NTFS file system, the Debugging Tools for Windows folder was created before 8.3 name creation was allowed. As a result, the file system does not contain a short name representation for this folder. To resolve this issue, create a new folder in another place on the file system after you enable 8.3 name creation (that is, after you set NTFSDisable8Dot3NameCreation to zero and reboot the server) and then copy the debuggers to this folder. Then, try to run Autodump+ again.

    Please note that this information applies to the given output directory as well as the installation directory. If the output directory that is specified on the command line was created before 8.3 name creation was enabled, it will cause this error as well. To eliminate this error, ensure that the source or installation directory as well as the output directory are created after this value is enabled.

  • When the -quiet option is included, Autodump+ logs information to the event log on systems that are equipped with the Windows Scripting Host version 5.1 or later.
  • If you use the -o option, the specified path must not contain more than one nonexistent folder. For example, if you specify "-o C:\Temp1\Temp2" when neither the C:\Temp1 nor \Temp2 folders exist, Autodump+ displays an error message and will not create these folders. If you only specify "-o C:\Temp1", Autodump+ creates the C:\Temp1 folder if it does not exist and places all output files in that folder. If you are specifying multiple subfolders and using the -o option, it is best to ensure that all of the subfolders exist before you run Autodump+.
  • In COM+, you can configure a server package to launch in the debugger on the Advanced tab in the Properties dialog box of the package. If you enable the Launch in Debugger option, Autodump+ cannot attach the CDB debugger to a process (by default, only one debugger can be attached to a process at a time).
  • When a remote procedure call (RPC) is made from a process that Autodump+ is analyzing in crash mode to another process that has failed or has been shut down, the log file that Autodump+ creates for the process that is being monitored may contain one or more of the following exceptions:
    Unknown exception - code 80010105 (first chance)
Unknown exception - code 800706be (first chance)
Unknown exception - code 800706ba (first chance)

    These exceptions are normal. RPC raises these exceptions when a call is made from a process that is being monitored to a nonexistent or failed process.

    In addition, if Autodump+ is monitoring Inetinfo.exe in the Autodump+ debug log for that process, you may see the following exception:

    Unknown exception - code 800706bf (first chance)

    This exception usually appears after IIS makes a call to an out-of-process (high-isolation) Web site that has failed. It might be followed by two instances of the following exception:

    Unknown exception - code 800706ba (first chance)


Dr. Watson

This section includes:

Using Dr. Watson to Create a Dump File

Installing Dr. Watson as the Postmortem Debugger


Using Dr. Watson to Create a Dump File

The Dr. Watson for Windows program (drwtsn32.exe) is preinstalled in your system directory (typically c:\winnt\system32) when Windows is set up. The default options are set the first time Dr. Watson for Windows runs, which can be either when an application error occurs or when you run it from the command prompt or the Run dialog box.

To run Dr. Watson, the following command line is generally used:

drwtsn32 -p ProcessID

For other options, see the Dr. Watson Command-Line Options.

By default, Dr. Watson is set up to save a memory dump file immediately upon the failure of a user-mode component. By default, this file is named user.dmp. Its default location depends on the version of Windows that is being used:

  • In Windows NT, the default location is the %UserProfile%\Local Settings folder.
  • In Windows 2000, the default location is the %AllUsersProfile%\Documents\DrWatson folder.
  • In Windows XP and Windows .NET Server 2003, the default location is the %AllUsersProfile%\Application Data\Microsoft\Dr Watson folder.

This dump file is as large as the amount of RAM dedicated to the user-mode process on the system that failed. It includes the contents of the failed user-mode's memory segment at the time that the error occurred.

As with any user-mode debugging session, symbols for the appropriate executables and DLLs must exist on the local computer. If a popup dialogue warning box is enabled (see Enabling Postmortem Debugging), you can copy the symbols when the popup box appears. However, the symbols should not be copied after the debugger has started.


Installing Dr. Watson as the Postmortem Debugger

When an application error occurs, Windows can respond in several different ways, depending on the postmortem debugging settings. If these settings instruct a debugging tool to create a dump file, a user-mode memory dump file will be created.

The default postmortem setting is for a dump file to be written by Dr. Watson. This means that when an application crashes, Dr. Watson will be activated and will save a memory dump file. For details on how to alter this, see Enabling Postmortem Debugging.

If these settings have been changed, you can reinstall Dr. Watson as the postmortem debugger by running Dr. Watson with the -i option:

drwtsn32 -i

For details, see Dr. Watson Command-Line Options.

Dr. Watson on Windows XP and Windows .NET Server 2003

If Dr. Watson is activated on Windows XP or Windows .NET Server 2003, a message box will appear. This message box gives you the option of sending an error report to Microsoft. If you choose Don't Send, a dump file will be created and stored on your hard disk. If you choose Send Error Report, a dump file will be created and stored on your hard disk, and will also be transmitted to Microsoft over the Internet.

However, if you have manually set the \\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AeDebug\Auto value to zero, the Don't Send button will simply terminate the application. The Send Error Report button will create a dump file and send it to Microsoft but will not store it on your hard disk. A third button, Debug, will create a dump file and store it on your hard disk.


CDB and WinDbg

CDB and WinDbg can create user-mode dump files in a variety of ways.

Creating a Dump File Automatically

When an application error occurs, Windows can respond in several different ways, depending on the postmortem debugging settings. If these settings instruct a debugging tool to create a dump file, a user-mode memory dump file will be created.

The default postmortem setting is for a dump file to be written by Dr. Watson. If you wish to use WinDbg as the postmortem debugger, use the following command to automatically configure the registry:

windbg -I

If you wish to use CDB as the postmortem debugger, you will have to configure the registry manually. For details, see Enabling Postmortem Debugging.

Creating Dump Files While Debugging

When CDB or WinDbg is debugging a user-mode application, you can also the .dump (Create Dump File) command to create a dump file.

This command does not cause the target application to terminate. By selecting the proper command options, you can create a minidump file (with or without full handle information or full memory information), or create a microdump.

Shrinking an Existing Dump File

CDB and WinDbg can also be used to shrink a dump file. To do this, begin debugging an existing dump file, and then use the .dump command to create a dump file of smaller size.


UserDump

The UserDump tool (userdump.exe), also known as User-Mode Process Dump, can create user-mode dump files.

UserDump and its documentation are part of the OEM Support Tools package.

To download these tools, search for Knowledge Base article Q253066 at http://support.microsoft.com/default.aspx and follow the instructions on that page.

The default postmortem setting is for a dump file to be written by Dr. Watson. For details on how to alter this, see Enabling Postmortem Debugging.


Analyzing a User-Mode Dump File

This section includes:

Reading a Dr. Watson Log File

Analyzing a User-Mode Dump File with CDB

Analyzing a User-Mode Dump File with WinDbg


Reading a Dr. Watson Log File

The Dr. Watson log file records the details of the crash dump creation process. (It is distinct from the actual dump file.)

Log File Section Explanation

When an application exception (or program error) occurs, Dr. Watson generates a log file (drwtsn32.log). The log file will always start with the following line:

Application exception occurred:

The next part of the log file always contains program error information. The error number listed corresponds to the error generated by the system.

The Faulting Application as Listed in the Dr. Watson Log File

The next part of the log file contains system information about the user and the computer on which the program error occurred:

System Information Section of the Dr. Watson Log File

The next part of the log file contains the list of tasks that were running on the system at the time that the program error occurred:

Task List Section of the Dr. Watson Log File

The next part of the log file contains the list of modules that the program loaded:

Module List Section of the Dr. Watson Log File

The next part of the log file contains the state dump for the thread ID that is listed. The state dump consists of a register dump, disassembly of the code surrounding the current program counter, a stack back trace, and a raw stack dump. This first part of the state dump lists the thread ID:

The next part of the state dump contains the register dump:

State Dump Section of the Dr. Watson Log File

The next part of the state dump contains the instruction disassembly:

Instruction Disassembly Section of the Dr. Watson Log File

The next part of the state dump contains the stack back trace:

Stack Back Trace Section of the Dr. Watson Log File

The final part of the state dump contains the raw stack dump:

Raw Stack Dump Section of the Dr. Watson Log File

Following the state dump, the final part of the log file contains the symbol table:

Symbol Table Section of the Dr. Watson Log File


Analyzing a User-Mode Dump File with CDB

User-mode memory dump files can be analyzed by CDB. The processor or Windows version that the dump file was created on does not need to match the platform on which CDB is being run.

Installing Symbol Files

Before analyzing the memory dump file, you will need to install the symbol files for the version of Windows that generated the dump file. These files will be used by the debugger you choose to use to analyze the dump file. For more information about the proper installation of symbol files, see Installing Windows Symbol Files.

You will also need to install all the symbol files for the user-mode process, either an application or system service, that caused the system to generate the dump file. If this code was written by you, the symbol files should have been generated when the code was compiled and linked. If this is commercial code, check on the product CD-ROM or contact the software manufacturer for these particular symbol files.

Starting CDB

To analyze a dump file, start CDB with the -z command-line option:

cdb -y SymbolPath -i ImagePath -z DumpFileName

The -v option (verbose mode) is also useful. For a full list of options, see CDB Command-Line Options.

You can also open a dump file after the debugger is running by using the .opendump (Open Dump File) command, followed with G (Go). This allows you to debug multiple dump files at the same time.

It is possible to debug multiple dump files at the same time. This can be done by including multiple -z switches on the command line (each followed by a different file name), or by using the .opendump command to add additional dump files as debugger targets.

Dump files generally end with the extension .dmp or .mdmp. You can use network shares or Universal Naming Convention (UNC) file names for the memory dump file.

It is also common for dump files to be packed into a CAB file. If you specify the file name (including the .cab extension) after the -z option or as the argument to an .opendump command, the debugger can read the dump files directly out of the CAB. However, if there are multiple dump files stored in a single CAB, the debugger will only be able to read one of them. The debugger will not read any additional files from the CAB, even if they are symbol files or executables associated with the dump file.

Analyzing a Full User Dump File

Analysis of a full user dump file is similar to analysis of a live debugging session. See the Debugger Commands reference section for details on which commands are available for debugging dump files in user mode.

Analyzing Minidump Files

Analysis of a user-mode minidump file is done in the same way as a full user dump. However, since much less memory has been preserved, you are much more limited in the actions you can perform. Commands that attempt to access memory beyond what is preserved in the minidump file will not function properly.


Analyzing a User-Mode Dump File with WinDbg

User-mode memory dump files can be analyzed by WinDbg. The processor or Windows version that the dump file was created on does not need to match the platform on which WinDbg is being run.

Installing Symbol Files

Before analyzing the memory dump file, you will need to install the symbol files for the version of Windows that generated the dump file. These files will be used by the debugger you choose to use to analyze the dump file. For more information about the proper installation of symbol files, see Installing Windows Symbol Files.

You will also need to install all the symbol files for the user-mode process, either an application or system service, that caused the system to generate the dump file. If this code was written by you, the symbol files should have been generated when the code was compiled and linked. If this is commercial code, check on the product CD-ROM or contact the software manufacturer for these particular symbol files.

Starting WinDbg

To analyze a dump file, start WinDbg with the -z command-line option:

windbg -y SymbolPath -i ImagePath -z DumpFileName

The -v option (verbose mode) is also useful. For a full list of options, see WinDbg Command-Line Options.

If WinDbg is already running and is in dormant mode, you can open a crash dump by selecting the File | Open Crash Dump menu command or pressing the CTRL+D shortcut key. When the Open Crash Dump dialog box appears, enter the full path and name of the crash dump file in the File name text box, or use the dialog box to select the proper path and file name. When the proper file has been chosen, click Open.

You can also open a dump file after the debugger is running by using the .opendump (Open Dump File) command, followed with G (Go).

It is possible to debug multiple dump files at the same time. This can be done by including multiple -z switches on the command line (each followed by a different file name), or by using the .opendump command to add additional dump files as debugger targets.

Dump files generally end with the extension .dmp or .mdmp. You can use network shares or Universal Naming Convention (UNC) file names for the memory dump file.

It is also common for dump files to be packed into a CAB file. If you specify the file name (including the .cab extension) after the -z option or as the argument to an .opendump command, the debugger can read the dump files directly out of the CAB. However, if there are multiple dump files stored in a single CAB, the debugger will only be able to read one of them. The debugger will not read any additional files from the CAB, even if they were symbol files or executables associated with the dump file.

Analyzing a Full User Dump File

Analysis of a full user dump file is similar to analysis of a live debugging session. See the Debugger Commands reference section for details on which commands are available for debugging dump files in user mode.

Analyzing Minidump Files

Analysis of a user-mode minidump file is done in the same way as a full user dump. However, since much less memory has been preserved, you are much more limited in the actions you can perform. Commands that attempt to access memory beyond what is preserved in the minidump file will not function properly.


Debugging Techniques

This section includes:

Elementary Debugging Techniques

Stack Traces

Processor Architecture

Application Verifier

RPC Debugging

ACPI Debugging

Plug and Play Debugging

Advanced Debugging Techniques


Elementary Debugging Techniques

This section includes:

Converting Virtual Addresses to Physical Addresses

Tracking Down a Processor Hog

Determining the ACL of an Object

Debugging an Application Failure


Converting Virtual Addresses to Physical Addresses

Most debugger commands use virtual addresses, not physical addresses, as their input and output. However, there are times that having the physical address can be useful.

There are two ways to convert a virtual address to a physical address: by using the !vtop extension, and by using the !pte extension. In Windows NT 4.0, the !vpdd extension can also be used.

Address Conversion Using !vtop

Suppose you are debugging a target computer on which the "MyApp.exe" process is running, and you wish to investigate the virtual address 0x0012F980.

Converting a virtual address to a physical address using !vtop

  1. Make sure that you are working in hexadecimal. If necessary, set the current base with the N 16 command.
  2. Determine the byte index of the address. This number is equal to the lowest twelve bits of the virtual address. So the virtual address 0x0012F980 has a byte index of 0x980.
  3. Determine the directory base of the address by using the !process extension:
    kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
....
PROCESS ff779190  SessionId: 0  Cid: 04fc    Peb: 7ffdf000  ParentCid: 0394
    DirBase: 098fd000  ObjectTable: e1646b30  TableSize:   8.
    Image: MyApp.exe
  4. Use the !vtop extension. The first parameter of this extension should be either the directory base or the directory base without the three trailing hexadecimal zeroes. (This shorter number is known as the page frame number of the directory base. In this example, the first parameter can be either 0x098FD000 or 0x098FD.) The second parameter of !vtop should be the virtual address in question:
    kd> !vtop 98fd 12f980
Pdi 0 Pti 12f
0012f980 09de9000 pfn(09de9)

    The second number shown on the final line is the physical address of the beginning of the physical page.

  5. Add the byte index to the address of the beginning of the page: 0x09DE9000 + 0x980 = 0x09DE9980. This is the desired physical address.

You can verify that this computation was done correctly by displaying the memory at each address. The !d* extension displays memory at a specified physical address:

kd> !dc 9de9980
# 9de9980 6d206e49 726f6d65 00120079 0012f9f4 In memory.......
# 9de9990 0012f9f8 77e57119 77e8e618 ffffffff .....q.w...w....
# 9de99a0 77e727e0 77f6f13e 77f747e0 ffffffff .'.w>..w.G.w....
# 9de99b0 .....

The D* (Display Memory) command uses a virtual address as its argument:

kd> dc 12f980
0012f980  6d206e49 726f6d65 00120079 0012f9f4  In memory.......
0012f990  0012f9f8 77e57119 77e8e618 ffffffff  .....q.w...w....
0012f9a0  77e727e0 77f6f13e 77f747e0 ffffffff  .'.w>..w.G.w....
0012f9b0  .....

Since the results are the same, this indicates that the physical address 0x09DE9980 does indeed correspond to the virtual address 0x0012F980.

Address Conversion using !pte

Again, suppose you are investigating the virtual address 0x0012F980 belonging to the "MyApp.exe" process.

Converting a virtual address to a physical address using !pte

  1. Make sure that you are working in hexadecimal. If necessary, set the current base with the N 16 command.
  2. Determine the byte index of the address. This number is equal to the lowest twelve bits of the virtual address. So the virtual address 0x0012F980 has a byte index of 0x980.
  3. Set the process context to the desired process:
    kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
....
PROCESS ff779190  SessionId: 0  Cid: 04fc    Peb: 7ffdf000  ParentCid: 0394
    DirBase: 098fd000  ObjectTable: e1646b30  TableSize:   8.
    Image: MyApp.exe

kd> .process /p ff779190
Implicit process is now ff779190
.cache forcedecodeptes done
  4. Use the !pte extension with the virtual address as its argument. This displays information in two columns. The left column describes this address' page directory entry (PDE); the right column describes its page table entry (PTE):
    kd> !pte 12f980
               VA 0012f980
PDE at   C0300000        PTE at C00004BC
contains 0BA58067      contains 09DE9067
pfn ba58 ---DA--UWV    pfn 9de9 ---DA--UWV
  5. Look in the last row of the right column. The notation "pfn 9de9" appears. The number 0x9DE9 is the page frame number (PFN) of this PTE. Multiply the page frame number by 0x1000 (i.e., shift it left 12 bits). The result, 0x09DE9000, is the physical address of the beginning of the page.
  6. Add the byte index to the address of the beginning of the page: 0x09DE9000 + 0x980 = 0x09DE9980. This is the desired physical address.

This is the same result obtained by the earlier method.

Converting Addresses By Hand

Although the !ptov and pte extensions supply the fastest way to convert virtual addresses to physical addresses, this conversion can be done manually as well. A description of this process will shed light on some of the details of the virtual memory architecture.

Memory structures vary in size, depending on the processor and the hardware configuration. This example is taken from an x86 system that does not have Physical Address Extension (PAE) enabled.

Let 0x0012F980 be used as the virtual address again. First, convert it to binary, either by hand or by using the .formats (Show Number Formats) command:

kd> .formats 12f980
Evaluate expression:
  Hex:     0012f980
  Decimal: 1243520
  Octal:   00004574600
  Binary:  00000000 00010010 11111001 10000000
  Chars:   ....
  Time:    Thu Jan 15 01:25:20 1970
  Float:   low 1.74254e-039 high 0
  Double:  6.14381e-318

This virtual address is a combination of three fields. Bits 0 to 11 are the byte index. Bits 12 to 21 are the page table index. Bits 22 to 31 are the page directory index. Separating the fields, you have:

0x0012F980  =  0y  00000000 00   010010 1111   1001 10000000

This exposes the three pieces of the virtual address:

  • Page directory index = 0y0000000000 = 0x0
  • Page table index = 0y0100101111 = 0x12F
  • Byte index = 0y100110000000 = 0x980

You then need three additional pieces of information for your system.

  • The size of each PTE: this is four bytes on non-PAE x86 systems
  • The size of a page: this is 0x1000 bytes
  • The PTE_BASE physical address: on a non-PAE system this is 0xC0000000

Using this data, you can compute the address of the PTE itself:

PTE address   =   PTE_BASE
                + (page directory index) * PAGE_SIZE
                + (page table index) * sizeof(MMPTE)
              =   0xc0000000
                + 0x0   * 0x1000
                + 0x12F * 4
              =   0xC00004BC

This is the address of the PTE. The PTE is a 32-bit DWORD. Examine its contents:

kd> dd 0xc00004bc L1
c00004bc  09de9067

This PTE has value 0x09DE9067. It is made of two fields:

  • The low 12 bits of the PTE are the status flags. In this case, these flags equal 0x067 — or in binary, 0y000001100111. For an explanation of the status flags, see the !pte reference page.
  • The high 20 bits of the PTE are equal to the page frame number (PFN) of the PTE. In this case, the PFN is 0x09DE9.

The first physical address on the physical page is the PFN multiplied by 0x1000 (shifted left 12 bits). The byte index is the offset on this page. So the physical address you are looking for is 0x09DE9000 + 0x980 = 0x09DE9980. This is the same result obtained by the earlier methods.


Tracking Down a Processor Hog

If one application is "hogging" all of the processor's attention, other processes will end up "starving" and unable to run.

Use the following procedure to correct a bug of this sort:

Debugging an application which is using all the CPU cycles

  1. Identify which application is causing this problem: Use Task Manager or Perfmon to find which process which is using 99% or 100% of the processor's cycles. This may tell you the offending thread as well.
  2. Attach WinDbg or CDB to this process.
  3. Identify which thread is causing the problem: Break into the offending application. Use the !runaway 3 extension to take a "snapshot" of where all the CPU time is going. Hit G (Go) and wait a few seconds. Then break in and use !runaway 3 again.
    0:002> !runaway 3
 User Mode Time
 Thread    Time
 4e0        0:12:16.0312
 268        0:00:00.0000
 22c        0:00:00.0000
 Kernel Mode Time
 Thread    Time
 4e0        0:00:05.0312
 268        0:00:00.0000
 22c        0:00:00.0000

0:002> g

0:001> !runaway 3
 User Mode Time
 Thread    Time
 4e0        0:12:37.0609
 3d4        0:00:00.0000
 22c        0:00:00.0000
 Kernel Mode Time
 Thread    Time
 4e0        0:00:07.0421
 3d4        0:00:00.0000
 22c        0:00:00.0000

    Compare the two sets of numbers and look for the thread whose user-mode time or kernel-mode time has increased the most. Since !runaway sorts by descending CPU time, the offending thread is usually the one at the top of the list. In this case, thread 0x4E0 is causing the problem.

  4. Use the ~ (Thread Status) and ~S (Set Current Thread) commands to make this the current thread:
    0:001> ~
   0  Id: 3f4.3d4 Suspend: 1 Teb: 7ffde000 Unfrozen
.  1  Id: 3f4.22c Suspend: 1 Teb: 7ffdd000 Unfrozen
   2  Id: 3f4.4e0 Suspend: 1 Teb: 7ffdc000 Unfrozen

0:001> ~2s
  5. Use KB (Display Stack Backtrace) to obtain a stack trace of this thread:
    0:002> kb
FramePtr  RetAddr   Param1   Param2   Param3   Function Name
0b4ffc74  77f6c600  000000c8.00000000 77fa5ad0 BuggyProgram!CreateMsgFile+0x1b
0b4ffce4  01836060  0184f440 00000001 0b4ffe20 BuggyProgram!OpenDestFileStream+0xb3
0b4ffd20  01843eba  02b5b920 00000102 02b1e0e0 BuggyProgram!SaveMsgToDestFolder+0xb3
0b4ffe20  01855924  0b4ffef0 00145970 0b4ffef0 BuggyProgram!DispatchToConn+0xa4
0b4ffe5c  77e112e6  01843e16 0b4ffef0 0b4fff34 RPCRT4!DispatchToStubInC+0x34
0b4ffeb0  77e11215  0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStubWorker@RPC_INTERFACE@@AAEJPAU_RPC_MESSAGE@@IPAJ@Z+0xb0
0b4ffed0  77e1a3b1  0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStub@RPC_INTERFACE@@QAEJPAU_RPC_MESSAGE@Z+0x41
0b4fff40  77e181e4  02b1e0b0 00000074 0b4fff90 RPCRT4!?ReceiveOriginalCall@OSF_SCONNECTION@Z+0x14b
0b4fff60  77e1a5df  02b1e0b0 00000074 00149210 RPCRT4!?DispatchPacket@OSF_SCONNECTION@+0x91
0b4fff90  77e1ac1c  77e15eaf 00149210 0b4fffec RPCRT4!?ReceiveLotsaCalls@OSF_ADDRESS@@QAEXXZ+0x76
  6. Set a breakpoint on the return address of the currently-running function. In this case, the return address is shown on the first line as 0x77F6C600. The return address is equivalent to the function offset shown on the second line (BuggyProgram!OpenDestFileStream+0xB3). If no symbols are available for the application, the function name may not appear. Use the G (Go) command to execute until this return address is reached, using either the symbolic or hexadecimal address:
    0:002> g BuggyProgram!OpenDestFileStream+0xb3
  7. If this breakpoint is hit, repeat the process. For example, suppose this breakpoint is hit. The following steps should be taken:
    0:002> kb
FramePtr  RetAddr   Param1   Param2   Param3   Function Name
0b4ffce4  01836060  0184f440 00000001 0b4ffe20 BuggyProgram!OpenDestFileStream+0xb3
0b4ffd20  01843eba  02b5b920 00000102 02b1e0e0 BuggyProgram!SaveMsgToDestFolder+0xb3
0b4ffe20  01855924  0b4ffef0 00145970 0b4ffef0 BuggyProgram!DispatchToConn+0xa4
0b4ffe5c  77e112e6  01843e16 0b4ffef0 0b4fff34 RPCRT4!DispatchToStubInC+0x34
0b4ffeb0  77e11215  0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStubWorker@RPC_INTERFACE@@AAEJPAU_RPC_MESSAGE@@IPAJ@Z+0xb0
0b4ffed0  77e1a3b1  0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStub@RPC_INTERFACE@@QAEJPAU_RPC_MESSAGE@Z+0x41
0b4fff40  77e181e4  02b1e0b0 00000074 0b4fff90 RPCRT4!?ReceiveOriginalCall@OSF_SCONNECTION@Z+0x14b
0b4fff60  77e1a5df  02b1e0b0 00000074 00149210 RPCRT4!?DispatchPacket@OSF_SCONNECTION@+0x91
0b4fff90  77e1ac1c  77e15eaf 00149210 0b4fffec RPCRT4!?ReceiveLotsaCalls@OSF_ADDRESS@@QAEXXZ+0x76

0:002> g BuggyProgram!SaveMsgToDestFolder+0xb3

    If this is hit, you continue:

    0:002> kb
FramePtr  RetAddr   Param1   Param2   Param3   Function Name
0b4ffd20  01843eba  02b5b920 00000102 02b1e0e0 BuggyProgram!SaveMsgToDestFolder+0xb3
0b4ffe20  01855924  0b4ffef0 00145970 0b4ffef0 BuggyProgram!DispatchToConn+0xa4
0b4ffe5c  77e112e6  01843e16 0b4ffef0 0b4fff34 RPCRT4!DispatchToStubInC+0x34
0b4ffeb0  77e11215  0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStubWorker@RPC_INTERFACE@@AAEJPAU_RPC_MESSAGE@@IPAJ@Z+0xb0
0b4ffed0  77e1a3b1  0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStub@RPC_INTERFACE@@QAEJPAU_RPC_MESSAGE@Z+0x41
0b4fff40  77e181e4  02b1e0b0 00000074 0b4fff90 RPCRT4!?ReceiveOriginalCall@OSF_SCONNECTION@Z+0x14b
0b4fff60  77e1a5df  02b1e0b0 00000074 00149210 RPCRT4!?DispatchPacket@OSF_SCONNECTION@+0x91
0b4fff90  77e1ac1c  77e15eaf 00149210 0b4fffec RPCRT4!?ReceiveLotsaCalls@OSF_ADDRESS@@QAEXXZ+0x76

0:002> g BuggyProgram!DispatchToConn+0xa4
  8. Finally you will find a breakpoint which is not hit. In this case, you should suppose that the last G command simply sets the target running and it does not break. This means that the SaveMsgToDestFolder() function is never returning.
  9. Break into the thread again and set a breakpoint on BuggyProgram!SaveMsgToDestFolder+0xB3 with the BP (Set Breakpoint) command. Then use the G command repeatedly. Is this breakpoint hit immediately, regardless of how many times you execute the target? If so, it is very likely that you have identified the offending function:
    0:002> bp BuggyProgram!SaveMsgToDestFolder+0xb3

0:002> g

0:002> g
  10. Use the P (Step) command to proceed through the function until you identify the place where the looping sequence of instructions are. You can then analyze the application's source code to identify the cause of the spinning thread. The cause will usually turn out to be a problem in the logic of a while, do-while, goto, or for loop.

See Also

Process Hangs or Consumes 100 Percent of CPU


Determining the ACL of an Object

You can use the debugger to examine the access control list (ACL) of an object.

The following method can be used if you are performing kernel debugging. To use it while you are performing user-mode debugging, you need to redirect control to a kernel debugger. See Controlling the User-Mode Debugger from the Kernel Debugger for details.

First, use the !object debugger extension with the name of the object in question:

kd> !object \BaseNamedObjects\AgentToWkssvcEvent
Object: ffbb8a98  Type: (80e30e70) Event
    ObjectHeader: ffbb8a80
    HandleCount: 2  PointerCount: 3
    Directory Object: e14824a0  Name: AgentToWkssvcEvent

This shows that the object header has address 0xFFBB8A80. Use the DT (Display Type) command with this address and the nt!_OBJECT_HEADER structure name:

kd> dt nt!_OBJECT_HEADER ffbb8a80
   +0x000 PointerCount     : 3
   +0x004 HandleCount      : 2
   +0x004 NextToFree       : 0x00000002
   +0x008 Type             : 0x80e30e70
   +0x00c NameInfoOffset   : 0x10 ''
   +0x00d HandleInfoOffset : 0 ''
   +0x00e QuotaInfoOffset  : 0 ''
   +0x00f Flags            : 0x20 ' '
   +0x010 ObjectCreateInfo : 0x8016b460
   +0x010 QuotaBlockCharged : 0x8016b460
   +0x014 SecurityDescriptor : 0xe11f08b6
   +0x018 Body             : _QUAD

The security descriptor pointer value is shown as 0xE11F08B6. The lowest three bits of this value represent an offset past the beginning of this structure, so you should ignore them (in other words, the SECURITY_DESCRIPTOR structure actually begins at 0xE11F08B6 & ~0x7). Use the !sd extension on this address:

kd> !sd e11f08b0
->Revision: 0x1
->Sbz1    : 0x0
->Control : 0x8004
            SE_DACL_PRESENT
            SE_SELF_RELATIVE
->Owner   : S-1-5-32-544
->Group   : S-1-5-18
->Dacl    :
->Dacl    : ->AclRevision: 0x2
->Dacl    : ->Sbz1       : 0x0
->Dacl    : ->AclSize    : 0x44
->Dacl    : ->AceCount   : 0x2
->Dacl    : ->Sbz2       : 0x0
->Dacl    : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[0]: ->AceFlags: 0x0
->Dacl    : ->Ace[0]: ->AceSize: 0x14
->Dacl    : ->Ace[0]: ->Mask : 0x001f0003
->Dacl    : ->Ace[0]: ->SID: S-1-5-18

->Dacl    : ->Ace[1]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[1]: ->AceFlags: 0x0
->Dacl    : ->Ace[1]: ->AceSize: 0x18
->Dacl    : ->Ace[1]: ->Mask : 0x00120001
->Dacl    : ->Ace[1]: ->SID: S-1-5-32-544

->Sacl    :  is NULL

This displays the security information for this object.


Debugging an Application Failure

There are a large variety of errors possible in user-mode applications.

The most common kinds of failures include access violations, alignment faults, exceptions, critical section timeouts (deadlocks), and in-page I/O errors.

Access violations and data type misalignments are among the most common. They usually occur when an invalid pointer is dereferenced. The blame could lie with the function that caused the fault, or with an earlier function that passed an invalid parameter to the faulting function.

User-mode exceptions have many possible causes. If an unknown exception occurs, look it up in ntstatus.h or winerror.h if possible.

Critical section timeouts (or possible deadlocks) occur when one thread is waiting for a critical section for a long time. These are difficult to debug and require an in-depth analysis of the stack trace.

In-page I/O errors are almost always hardware failures. You can double-check the status code in ntstatus.h to verify.

See Advanced Debugging Techniques for some tips on how to proceed.


Stack Traces

This section includes:

Anatomy of a Stack Trace

Manually Walking a Stack


Anatomy of a Stack Trace

The following is a register dump from the kernel debugger. It contains information about what is stored in the stack:

kd> r  [This command dumps the information from a register.]
eax=c0000018 ebx=80621828 ecx=00000000 edx=807da761 esi=e12e0e28 edi=e12df868
eip=f28343b3 esp=f2c132cc ebp=f2c132f0 iopl=0         nv up ei pl zr na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000246
VIDEOPRT!pVideoPortReportResourceList+0x263:
f28343b3 8db340010000     lea     esi,[ebx+0x140]   ds:0023:80621968=00000000

The registers are used as follows:

  • esp = stack pointer
  • ebp = base pointer
  • eip = instruction pointer
  • eax, ebx, ecx, edx = general purpose registers for storing intermediate results
  • edi, esi = often used as general registers

A stack trace could be diagramed in the following manner:

  • Arguments
  • Return Address
  • Caller's EBP
  • Local Variables

The stack trace displayed on a kernel debugger is written in assembly code. A simple set of instructions in assembly code could look like this:

push ebp            ;Places the caller's base pointer (ebp) on to the stack
mov ebp,esp        ;Sets the base pointer (ebp) equal to the stack pointer (esp)
mov eax, [ebp+8]        ;Grab the value of the first argument off the stack and store it in eax
add eax, [ebp+c]        ;Add the second argument's value to the value in eax
pop ebp            ;Restore the caller's base pointer
ret 8            ;Return to the calling function and remove 8 bytes from the stack

The compiler can optimize this code, simplifying it so that it is shorter and more direct. An optimized routine might look like this: (Note how the code omits references to the base pointer.)

mov eax, [esp+4]
add eax, [esp+8]
ret 8

Finally here's how it would look in C:

ULONG Add(ULONG a, ULONG b)
{
    return a + b;
}


Manually Walking a Stack

In some cases, the stack trace function will fail in the debugger. This can be caused by a call to an invalid address which caused the debugger to lose the location of the return address is; or you may have come across a stack pointer for which you cannot directly get a stack trace; or there could be some other debugger problem. In any case, being able to manually walk a stack is often valuable.

The basic concept is fairly simple: dump out the stack pointer, find out where the modules are loaded, find possible function addresses and verify by checking to see if each possible stack entry makes a call to the next.

Before going through an example, it is important to note is that kb (Display Stack Backtrace) command has an additional feature on Intel systems. By doing a kb=[ebp] [eip] [esp], the debugger will display the stack trace for the frame with the given values for base pointer, instruction pointer, and stack pointer respectively.

For the example, a failure which actually gives a stack trace is used so the results can be checked at the end.

The first step is to find out what modules are loaded where. This is accomplished with the X (Examine Symbols) command (some symbols are edited out for the reasons of length):

kd> x *!
start    end        module name
77f70000 77fb8000   ntdll     (C:\debug\ntdll.dll, \\ntstress\symbols\dll\ntdll.DBG)
80010000 80012320   Aha154x   (load from Aha154x.sys deferred)
80013000 8001aa60   SCSIPORT  (load from SCSIPORT.SYS deferred)
8001b000 8001fba0   Scsidisk  (load from Scsidisk.sys deferred)

80100000 801b7b40   NT        (ntoskrnl.exe, \\ntstress\symbols\exe\ntoskrnl.DBG)
802f0000 8033c000   Ntfs      (load from Ntfs.sys deferred)
80400000 8040c000   hal       (load from hal.dll deferred)
fe4c0000 fe4c38c0   vga       (load from vga.sys deferred)
fe4d0000 fe4d3e60   VIDEOPRT  (load from VIDEOPRT.SYS deferred)
fe4e0000 fe4f0e40   ati       (load from ati.SYS deferred)
fe500000 fe5057a0   Msfs      (load from Msfs.SYS deferred)
fe510000 fe519560   Npfs      (load from Npfs.SYS deferred)

fe520000 fe521f60   ndistapi  (load from ndistapi.sys deferred)
fe530000 fe54ed20   Fastfat   (load from Fastfat.SYS deferred)
fe5603e0 fe575360   NDIS      (NDIS.SYS, \\ntstress\symbols\SYS\NDIS.DBG)
fe580000 fe585920   elnkii    (elnkii.sys, \\ntstress\symbols\sys\elnkii.DBG)
fe590000 fe59b8a0   ndiswan   (load from ndiswan.sys deferred)
fe5a0000 fe5b7c40   nbf       (load from nbf.sys deferred)
fe5c0000 fe5c1b40   TDI       (load from TDI.SYS deferred)
fe5d0000 fe5dd580   nwlnkipx  (load from nwlnkipx.sys deferred)

fe5e0000 fe5ee220   nwlnknb   (load from nwlnknb.sys deferred)
fe5f0000 fe5fb320   afd       (load from afd.sys deferred)
fe610000 fe62bf00   tcpip     (load from tcpip.sys deferred)
fe630000 fe648600   netbt     (load from netbt.sys deferred)
fe650000 fe6572a0   netbios   (load from netbios.sys deferred)
fe660000 fe660000   Parport   (load from Parport.SYS deferred)
fe670000 fe670000   Parallel  (load from Parallel.SYS deferred)
fe680000 fe6bcf20   rdr       (rdr.sys, \\ntstress\symbols\sys\rdr.DBG)

fe6c0000 fe6f0920   srv       (load from srv.sys deferred)

The second step is dumping out the stack pointer (esp on an x86, sp on an IA-64) to look for addresses in the modules given by the x *! command:

kd> dd esp
fe4cc97c  80136039 00000270 00000000 00000000
fe4cc98c  fe682ae4 801036fe 00000000 fe68f57a
fe4cc99c  fe682a78 ffb5b030 00000000 00000000
fe4cc9ac  ff680e08 801036fe 00000000 00000000
fe4cc9bc  fe6a1198 00000001 fe4cca78 ffae9d98

fe4cc9cc  02000901 fe4cca68 ffb50030 ff680e08
fe4cc9dc  ffa449a8 8011c901 fe4cca78 00000000
fe4cc9ec  80127797 80110008 00000246 fe6a1430
kd> dd
fe4cc9fc  00000270 fe6a10ae 00000270 ffa44abc
fe4cca0c  ffa449a8 ff680e08 fe6b2c04 ff680e08
fe4cca1c  ffa449a8 e12820c8 e1235308 ffa449a8
fe4cca2c  fe685968 ff680e08 e1235308 ffa449a8
fe4cca3c  ffb0ad48 ffb0ad38 00100000 ffb0ad38
fe4cca4c  00000000 ffa44a84 e1235308 0000000a
fe4cca5c  c00000d6 00000000 004ccb28 fe4ccbc4

fe4cca6c  fe680ba4 fe682050 00000000 fe4ccbd4

To determine which values are likely function addresses and which are parameters or saved registers, the first thing to consider is what the different types of things on the stack look like. Most integers are going to be smaller values and most of the DWORDs will be zeros (like 00000270). Most pointers to local addresses will be near the stack pointer (like fe4cca78). Status codes usually begin with a c (c00000d6). Unicode and ASCII strings can be identified by the fact that each character will be in the range of 20-7f. (In KD, the DC (Display Memory) command will show the characters on the right). Most importantly, the function addresses will be in the range listed by x *!. Notice that all modules listed are in the ranges of 77f70000 to 8040c000 and fe4c0000 to fe6f0920. Based on these ranges, the possible function addresses in the above list are: 80136039, 801036fe (listed twice, so more likely a parameter), fe682ae4, fe68f57a, fe682a78, fe6a1198, 8011c901, 80127797, 80110008, fe6a1430, fe6a10ae, fe6b2c04, fe685968, fe680ba4, and fe682050. Check out these locations by using an LN (List Nearest Symbols) command for each address:

kd> ln 80136039
(80136039)   NT!_KiServiceExit+0x1e  |  (80136039)   NT!_KiServiceExit2-0x177
kd> ln fe682ae4
(fe682ae4)   rdr!_RdrSectionInfo+0x2c | (fe682ae4)   rdr!_RdrFcbReferenceLock-0xb4
kd> ln 801036fe
(801036fe)   NT!_KeWaitForSingleObject | (801036fe)   NT!_MmProbeAndLockPages-0x2f8
kd> ln fe68f57a
(fe68f57a)   rdr!_RdrDereferenceDiscardableCode+0xb4
                         (fe68f57a)   rdr!_RdrUninitializeDiscardableCode-0xa
kd> ln fe682a78
(fe682a78)   rdr!_RdrDiscardableCodeLock | (fe682a78) rdr!_RdrDiscardableCodeTimeout-0x38

kd> ln fe6a1198
(fe6a1198)   rdr!_SubmitTdiRequest+0xae | (fe6a1198)   rdr!_RdrTdiAssociateAddress-0xc
kd> ln 8011c901
(8011c901)   NT!_KeSuspendThread+0x13 | (8011c901)   NT!_FsRtlCheckLockForReadAccess-0x55
kd> ln 80127797
(80127797)   NT!_ZwCloseObjectAuditAlarm+0x7 | (80127797)   NT!_ZwCompleteConnectPort-0x9
kd> ln 80110008
(80110008)   NT!_KeWaitForMultipleObjects+0x27c | (80110008) NT!_FsRtlLookupMcbEntry-0x164
kd> ln fe6a1430
(fe6a1430)   rdr!_RdrTdiCloseConnection+0xa | (fe6a1430)   rdr!_RdrDoTdiConnect-0x4

kd> ln fe6a10ae
(fe6a10ae)   rdr!_RdrTdiDisconnect+0x56 | (fe6a10ae)   rdr!_SubmitTdiRequest-0x3c
kd> ln fe6b2c04
(fe6b2c04)   rdr!_CleanupTransportConnection+0x64 | (fe6b2c04)rdr!_RdrReferenceServer-0x20
kd> ln fe685968
(fe685968)   rdr!_RdrReconnectConnection+0x1b6
                        (fe685968)   rdr!_RdrInvalidateServerConnections-0x32
kd> ln fe682050
(fe682050)   rdr!__strnicmp+0xaa  |  (fe682050)   rdr!_BackPackSpinLock-0xa10

As was noted before, 801036fe is not likely to be part of the stack trace as it is listed twice. If the return addresses have an offset of zero, they can be ignored (you cannot return to the beginning of a function). Based on this information, the stack trace is revealed to be:

NT!_KiServiceExit+0x1e
rdr!_RdrSectionInfo+0x2c
rdr!_RdrDereferenceDiscardableCode+0xb4
rdr!_SubmitTdiRequest+0xae
NT!_KeSuspendThread+0x13
NT!_ZwCloseObjectAuditAlarm+0x7
NT!_KeWaitForMultipleObjects+0x27c
rdr!_RdrTdiCloseConnection+0xa
rdr!_RdrTdiDisconnect+0x56
rdr!_CleanupTransportConnection+0x64
rdr!_RdrReconnectConnection+0x1b6
rdr!__strnicmp+0xaa

To verify each symbol, unassemble immediately before the return address specified to see if it does a call to the function above it. The following is edited (the offsets used were found by trial and error) to reduce length:

kd> u 80136039-2 l1    looks ok, its a call
NT!_KiServiceExit+0x1c:
80136037 ffd3             call    ebx
kd> u fe682ae4-2 l1    paged out (all zeroes) unknown
rdr!_RdrSectionInfo+0x2a:
fe682ae2 0000             add     [eax],al
kd> u fe68f57a-6 l1    looks ok, its a call, but not anything above
rdr!_RdrDereferenceDiscardableCode+0xae:
fe68f574 ff15203568fe     call dword ptr [rdr!__imp__ExReleaseResourceForThreadLite]
kd> u fe682a78-6 l1    paged out (all zeroes) unknown

rdr!_DiscCodeInitialized+0x2:
fe682a72 0000             add     [eax],al
kd> u  fe6a1198-5 l1    looks good, call to something above
rdr!_SubmitTdiRequest+0xa9:
fe6a1193 e82ee3feff       call  rdr!_RdrDereferenceDiscardableCode (fe68f4c6)
kd> u 8011c901-2 l1    not good, its a jump in the function
NT!_KeSuspendThread+0x11:
8011c8ff 7424             jz      NT!_KeSuspendThread+0x37 (8011c925)
kd> u 80127797-2 l1    looks good, an int 2e -> KiServiceExit

NT!_ZwCloseObjectAuditAlarm+0x5:
80127795 cd2e             int     2e
kd> u 80110008-2 l1    not good, its a test instruction not a call
NT!_KeWaitForMultipleObjects+0x27a:
80110006 85c9             test    ecx,ecx
kd> u 80110008-5 l1    paged out (all zeroes) unknown
NT!_KeWaitForMultipleObjects+0x277:
80110003 0000             add     [eax],al
kd> u fe6a1430-6 l1    looks good its a call to ZwClose...
rdr!_RdrTdiCloseConnection+0x4:
fe6a142a ff15f83468fe     call    dword ptr [rdr!__imp__ZwClose (fe6834f8)]

kd> u fe6a10ae-2 l1    paged out (all zeroes) unknown
rdr!_RdrTdiDisconnect+0x54:
fe6a10ac 0000             add     [eax],al
kd> u  fe6b2c04-5 l1    looks good, call to something above
rdr!_CleanupTransportConnection+0x5f:
fe6b2bff e854e4feff       call    rdr!_RdrTdiDisconnect (fe6a1058)
kd> u fe685968-5 l1    looks good, call to immediately above
rdr!_RdrReconnectConnection+0x1b1:
fe685963 e838d20200       call    rdr!_CleanupTransportConnection (fe6b2ba0)

kd> u fe682050-2 l1    paged out (all zeroes) unknown
rdr!__strnicmp+0xa8:
fe68204e 0000             add     [eax],al

Based on this, it looks like RdrReconnectConnection called RdrCleanupTransportConnection, to RdrTdiDisconnect, to ZwCloseObjectAuditAlarm, to KiSystemServiceExit. The other functions on the stack are probably left over portions of previously active stacks.

In this case, the stack trace worked properly, so here is the actual stack trace to check our answer:

kd> k
ChildEBP RetAddr
fe4cc978 80136039 NT!_NtClose+0xd
fe4cc978 80127797 NT!_KiServiceExit+0x1e

fe4cc9f4 fe6a1430 NT!_ZwCloseObjectAuditAlarm+0x7
fe4cca10 fe6b2c04 rdr!_RdrTdiCloseConnection+0xa
fe4cca28 fe685968 rdr!_CleanupTransportConnection+0x64
fe4cca78 fe688157 rdr!_RdrReconnectConnection+0x1b6
fe4ccbd4 80106b1e rdr!_RdrFsdCreate+0x45b
fe4ccbe8 8014b289 NT!IofCallDriver+0x38
fe4ccc98 8014decd NT!_IopParseDevice+0x693
fe4ccd08 8014d6d2 NT!_ObpLookupObjectName+0x487
fe4ccde4 8014d3ad NT!_ObOpenObjectByName+0xa2
fe4cce90 8016660d NT!_IoCreateFile+0x433
fe4cced0 80136039 NT!_NtCreateFile+0x2d

The first entry was the current location based on the stack trace, but otherwise, the stack was correct up to the point that RdrReconnectConnection was called. The same process could have been used to trace the entire stack. For a more exact method of manual stack walking, you would need to unassemble each potential function and follow all pushes and pops to identify each DWORD on the stack.


Processor Architecture

This section includes:

The x86 Processor

The IA-64 Processor


The x86 Processor

This section includes:

The x86 Architecture

The x86 Instructions

Annotated x86 Disassembly


The x86 Architecture

The x86 uses a complex instructions set computers (CISC) architecture, which means there is a modest number of special-purpose registers instead of large quantities of general-purpose registers. It also means that complicated special-purpose instructions will be predominate.

The x86 processor traces its heritage at least as far back as the 8-bit Intel 8080 processor. Many peculiarities in the x86 instruction are due to the backwards compatibility with that processor (and with its Zilog Z-80 variation).

Microsoft® Win32® uses the x86 processor in flat mode. This documentation will focus only on the flat mode.

Registers

The x86 architecture consists of the following unprivileged integer registers:

eax | accumulator
ebx | base register
ecx | count register
edx | double-precision register
esi | source index register
edi | destination index register
ebp | base pointer register
esp | stack pointer

All integer registers are 32-bit. However, many of them have 16-bit or 8-bit subregisters.

ax | low 16 bits of eax
bx | low 16 bits of ebx
cx | low 16 bits of ecx
dx | low 16 bits of edx
si | low 16 bits of esi
di | low 16 bits of edi
bp | low 16 bits of ebp
sp | low 16 bits of esp
al | low 8 bits of eax
ah | high 8 bits of ax
bl | low 8 bits of ebx
bh | high 8 bits of bx
cl | low 8 bits of ecx
ch | high 8 bits of cx
dl | low 8 bits of edx
dh | high 8 bits of dx

Operating on a subregister affects only the subregister and none of the parts outside the subregister. For example, storing to the ax register leaves the high 16 bits of the eax register unchanged.

When using the ? (Evaluate Expression) command, registers should be prefixed with an "at" sign ( @ ). For example, you should use ? @ax rather than ? ax. This assures that the debugger recognizes "ax" as a register rather than a symbol.

However, the (@) is not required in the R (Registers) command. For instance, r ax=5 will always be interpreted correctly.

There are also non-integer registers in the x86 architecture.

eip | instruction pointer
flags | flags

The instruction pointer is the address of the instruction being executed.

The flags register is a collection of single-bit flags. Many instructions alter the flags to describe the result of the instruction. These flags can then be tested by conditional jump instructions. See The x86 Flags for details.

Calling Conventions

The x86 architecture has several different calling conventions. Fortunately, they all follow the same register preservation and function return rules:

  • The register preservation rule is that functions must preserve all registers except for eax, ecx, and edx, which can be changed across a function call, and esp, which must be updated as described below.
  • The function return rule is that the eax register receives function return values if the result is 32-bit or smaller. If the result is 64-bit, then the result is stored in the edx:eax pair.

The following is a list of calling conventions used in x86 architecture:

  • Win32 (Stdcall)

    Function parameters are passed on the stack, pushed right to left, and the callee cleans the stack.

  • Native C++ (Thiscall)

    Function parameters are passed on the stack, pushed right to left, the "this" pointer is passed in the ecx register, and the callee cleans the stack.

  • COM(Stdcall for C++)

    Function parameters are passed on the stack, pushed right to left, then the "this" pointer is pushed on the stack, then the function is called. The callee cleans the stack.

  • Fastcall

    The first parameter is passed in the eax register, the second parameter in the ecx register, the third in the edx register, and the remaining parameters are passed on the stack, pushed right to left. The callee cleans the stack.

  • Cdecl

    Function parameters are passed on the stack, pushed right to left, and the caller cleans the stack. The Cdecl calling convention is used for all functions with variable-length parameters.

Debugger Dump of Registers and Flags

Here is a sample debugger register dump:

eax=00000000 ebx=008b6f00 ecx=01010101 edx=ffffffff esi=00000000 edi=00465000
eip=77f9d022 esp=05cffc48 ebp=05cffc54 iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000286

You can ignore the iopl and the last line of the example.

The x86 Flags

The two-letter codes at the end of the second line are flags. These are single-bit registers which have a variety of uses.

The following table lists the x86 flags:

Flag Code | Flag Name | Value | Flag Status | Status Description
of | Overflow Flag | 0 1 | nv ov | No overflow Overflow
df | Direction Flag | 0 1 | up dn | Direction up Direction down
if | Interrupt Flag | 0 1 | di ei | Interrupts disabled Interrupts enabled
sf | Sign Flag | 0 1 | pl ng | Positive (or zero) Negative
zf | Zero Flag | 0 1 | nz zr | Non-zero Zero
af | Auxiliary Carry Flag | 0 1 | na ac | No auxiliary carry Auxiliary carry
pf | Parity Flag | 0 1 | pe po | Parity even Parity odd
cf | Carry Flag | 0 1 | nc cy | No carry Carry
tf | Trap Flag | If tf equals 1, the processor will raise a STATUS_SINGLE_STEP exception after the execution of one instruction. This flag is used by a debugger to implement single-step tracing; it should not be used by other applications.
iopl | I/O Privilege Level | This is a two-bit flag, with values between zero and three. It is used by the operating system to control access to hardware. It should not be used by applications.

When registers are displayed as a result of some command in the Debugger Command window, it is the flag status which is displayed. However, if you wish to change a flag using the R (Registers) command, you should refer to it by the flag code.

In the Registers window of WinDbg, the flag code is used to view or alter flags. The flag status is not supported.

Here is an example. In the register display above, the flag status ng appears. This means that the sign flag is currently set to 1. To change this, use the following command:

r sf=0

This sets the sign flag to zero. If you do another register display, the ng status code will not appear. Instead, the pl status code will be displayed.

The Sign Flag, Zero Flag, and Carry Flag are the most important flags for you.

Conditions

A condition is a way of testing the state of one or more flags.

Many conditions have multiple names. For example "AE" and "NB" are the same, depending on whether you view it as "above or equal" or as "not below." The following table lists the conditions and their meaning.

Condition Name | Meaning
E Z | if zero (or comparison equal)
NE NZ | if nonzero (or comparison unequal)
GE | if greater than or equal to zero
LT NGE | if less than zero
GT | if greater than zero
LE NGT | if less than zero
C | if carry
NC | if no carry
AE NB | if above or equal (unsigned greater)
B NAE | if below (unsigned less than)
A NBE | if above (unsigned greater or equal)
BE NA | if below or equal (unsigned less than or equal)

Conditions are typically used to act on the result of a cmp or test instruction. For example,

cmp eax, 5
jz equal

compares the eax register against the number 5 by computing the expression (eax - 5) and setting flags according to the result. If the result of the subtraction is zero, then the zr flag will be set, and the jz condition will be true so the jump will be taken.

Data Types

  • byte: 8 bits
  • word: 16 bits
  • dword: 32 bits
  • qword: 64 bits (floating point double)
  • tword: 80 bits (floating point extended double)

Notation

r, r1, r2... | registers
m | memory address (see the succeeding Addressing Modes section for more information)
#n | immediate constant
r/m | register or memory
r/#n | register or immediate constant
r/m/#n | register or memory or immediate constant
cc | A condition code listed in the preceding Conditions section.
T | "B", "W", or "D" (byte, word or dword)
accT | size T accumulator: al if T = "B", ax if T = "W", or eax if T = "D"

Addressing Modes

There is a large number of addressing modes, but they all take the form T ptr [expr], where T is some data type (see the preceding Data Types section) and expr is some expression involving constants and/or register.

The notation for most modes can be deduced without much difficulty. For example, BYTE PTR [esi+edx*8+3] means "take the value of the esi register, add to it eight times the value of the edx register, add three, then access the byte at the resulting address."

Pipelining

The Pentium is dual-issue, which means that it can do up to two things in one clock tick. However, the rules on when it is capable of doing two things at once (known as "pairing") are very complicated.

Since x86 is a CISC processor, you don't have to worry about jump delay slots.

Synchronized Memory Access

Load, modify, and store instructions can be prefixed by the lock instruction, which does the following:

  • Before issuing the instruction, the CPU will flush all pending memory operations to ensure coherency. All data prefetches are abandoned.
  • While issuing the instruction, the CPU will have exclusive access to the bus. This ensures atomicity of the load/modify/store operation.

The xchg instruction automatically asserts a lock if a value is being exchanged with memory.

All other instructions default to non-locking.

Jump Prediction

Unconditional jumps are predicted to be taken.

Conditional jumps are predicted to be taken depending on whether they were taken the last time they were executed. The cache for recording jump history is limited in size.

If the CPU does not have a recorder of whether the conditional jump was taken or not taken the last time it was executed, it predicts backward conditional jumps as taken and forward conditional jumps as not taken.

Alignment

The x86 processor will automatically fix up unaligned memory access, at a performance penalty. No exception is raised.

A memory access is considered "aligned" if the address is an integer multiple of the object size. For example, all BYTE accesses are aligned (everything is an integer multiple of one), WORD accesses to even addresses are aligned, and DWORD addresses must be a multiple of four in order to be aligned.


The x86 Instructions

In the list below, instructions marked with an asterisk (*) are particularly important. Instructions not marked so can be glossed over.

On the x86 processor, instructions are variable-sized, so disassembling backwards is an exercise in pattern matching. To disassemble backwards from an address, you should start disassembling at a point further back than you really want to go, then look forward until the instructions start making sense. The first few instructions may not make any sense because you may have started disassembling in the middle of an instruction. There is a possibility, unfortunately, that the disassembly will never synchronize with the instruction stream and you will have to try disassembling at a different starting point until you find a starting point that works.

For well-packed switch statements, the compiler emits data directly into the code stream, so disassembling through a switch statement will usually stumble across instructions that make no sense (because they are really data). Find the end of the data and continue disassembling there.

Instruction Notation

The general notation for instructions is to put the destination register on the left and the source on the right. There might be some exceptions to this rule.

Arithmetic instructions are typically two-register with the source and destination registers combining. The result is stored into the destination.

Some of the instructions have both 16-bit and 32-bit versions, but only the 32-bit versions are listed here. Not listed here are floating point instructions, privileged instructions, and instructions that are used only in segmented models (which Microsoft® Win32® doesn't use).

To save space, many of the instructions are expressed in combined form. For example

* MOV r1, r/m/#n r1 = r/m/#n

means that the first parameter must be a register, but the second can be a register or a memory reference or an immediate value.

To save even more space, instructions can also be expressed as

* MOV r1/m, r/m/#n r1/m = r/m/#n

which means that the first parameter can be a register or a memory reference, and the second can be a register, memory reference, or immediate value.

Unless otherwise noted, when this abbreviation is used, you cannot choose "memory" for both source and destination.

Furthermore, a bit-size suffix (8, 16, 32) can be appended to the source or destination to indicate that the parameter must be of that size. For example, r8 means "an 8-bit register."

Memory, Data Transfer, and Data Conversion

Memory and data transfer instructions do not affect flags.

Effective Address

* LEA r, m load effective address

(r = address of m)

For example, LEA eax, [esi+4] means eax = esi + 4. This instruction is often used to perform arithmetic.

Data Transfer

* | MOV | r1/m, r2/m/#n | r1/m = r/m/#n
* | MOVSX | r1, r/m | move with sign extension
* | MOVZX | r1, r/m | move with zero extension

MOVSX and MOVZX are special versions of the mov instruction that perform sign extension or zero extension from the source to the destination. This is the only instruction that allows the source and destination to be different sizes. (And in fact, they must be different sizes or this instruction becomes useless.)

XCHG r1, r/m swap r1 and r/m

You can swap two registers or swap a register with memory, but you cannot swap memory with memory.

Stack Manipulation

The stack is pointed to by the esp register. The value at esp is the top of the stack (most recently pushed, first to be popped); older stack elements reside at higher addresses.

* | PUSH | r/m/#n | push value onto stack
* | POP | r/m | pop value from stack
 | PUSHFD |  | push flags onto stack
 | POPFD |  | pop flags from stack
 | PUSHAD |  | push all integer registers
 | POPAD |  | pop all integer registers
 | ENTER | #n, #n | build stack frame
* | LEAVE |  | tear down stack frame

The compiler doesn't use an enter instruction. It's for building multiple-level stack frames in Algol-like languages.

The leave instruction is equivalent to

mov esp, ebp
pop ebp

Data Conversion

CBW | convert byte (al) to word (ax)
CWD | convert word (ax) to dword (dx:ax)
CWDE | convert word (ax) to dword (eax)
CDQ | convert dword (eax) to qword (edx:eax)

All conversions perform sign extension.

Arithmetic and Bit Manipulation

All arithmetic and bit manipulation instructions modify flags.

Arithmetic

* | ADD | r1/m, r2/m/#n | r1/m += r2/m/#n
 | ADC | r1/m, r2/m/#n | r1/m += r2/m/#n + carry
* | SUB | r1/m, r2/m/#n | r1/m -= r2/m/#n
 | SBB | r1/m, r2/m/#n | r1/m -= r2/m/#n + carry
* | NEG | r1/m | r1/m = -r1/m
* | INC | r/m | r/m += 1
* | DEC | r/m | r/m -= 1
* | CMP | r1/m, r2/m/#n | Compute r1/m - r2/m/#n

The cmp instruction computes the subtraction and sets flags according to the result, but throws the result away. It is typically followed by a conditional jump instruction that tests the result of the subtraction.

 | MUL | r/m8 | ax = al * r/m8
 | MUL | r/m16 | dx:ax = ax * r/m16
* | MUL | r/m32 | edx:eax = eax * r/m32
 | IMUL | r/m8 | ax = al * r/m8
 | IMUL | r/m16 | dx:ax = ax * r/m16
* | IMUL | r/m32 | edx:eax = eax * r/m32
* | IMUL | r1, r2/m | r1 *= r2/m
* | IMUL | r1, r2/m, #n | r1 = r2/m * #n

Unsigned and signed multiplication. The state of flags after multiplication is undefined.

 | DIV | r/m8 | (ah, al) = (ax % r/m8, ax ÷ r/m8)
 | DIV | r/m16 | (dx, ax) = dx:ax ÷ r/m16
* | DIV | r/m32 | (edx, eax) = edx:eax ÷ r/m32
 | IDIV | r/m8 | (ah, al) = ax ÷ r/m8
 | IDIV | r/m16 | (dx, ax) = dx:ax ÷ r/m16
* | IDIV | r/m32 | (edx, eax) = edx:eax ÷ r/m32

Unsigned and signed division. The first register in the pseudocode explanation receives the remainder and the second receives the quotient. If the result overflows the destination, a division overflow exception is generated.

The state of flags after division is undefined.

* SETcc r/m8 Set r/m8 to 0 or 1

If the condition cc is true, then the 8-bit value is set to 1. Otherwise, the 8-bit value is set to 0.

Binary-coded Decimal

You will not see these instructions unless you are debugging code written in COBOL.

DAA | decimal adjust after addition
DAS | decimal adjust after subtraction

These instructions adjust the al register after performing a packed binary-coded decimal operation.

AAA | ASCII adjust after addition
AAS | ASCII adjust after subtraction

These instructions adjust the al register after performing an unpacked binary-coded decimal operation.

AAM | ASCII adjust after multiplication
AAD | ASCII adjust after division

These instructions adjust the al and ah registers after performing an unpacked binary-coded decimal operation.

Bits

* | AND | r1/m, r2/m/#n | r1/m = r1/m and r2/m/#n
* | OR | r1/m, r2/m/#n | r1/m = r1/m or r2/m/#n
* | XOR | r1/m, r2/m/#n | r1/m = r1/m xor r2/m/#n
* | NOT | r1/m | r1/m = bitwise not r1/m
* | TEST | r1/m, r2/m/#n | Compute r1/m and r2/m/#n

The test instruction computes the logical AND operator and sets flags according to the result, but throws the result away. It is typically followed by a conditional jump instruction that tests the result of the logical AND.

* | SHL | r1/m, cl/#n | r1/m <<= cl/#n
* | SHR | r1/m, cl/#n | r1/m >>= cl/#n zero-fill
* | SAR | r1/m, cl/#n | r1/m >>= cl/#n sign-fill

The last bit shifted out is placed in the carry.

SHLD r1, r2/m, cl/#n Shift left double

Shift r1 left by cl/#n, filling with the top bits of r2/m. The last bit shifted out is placed in the carry.

SHRD r1, r2/m, cl/#n Shift right double

Shift r1 right by cl/#n, filling with the bottom bits of r2/m. The last bit shifted out is placed in the carry.

ROL | r1, cl/#n | rotate r1 left by cl/#n
ROR | r1, cl/#n | rotate r1 right by cl/#n
RCL | r1, cl/#n | rotate r1/C left by cl/#n
RCR | r1, cl/#n | rotate r1/C right by cl/#n

Rotation is like shifting except that the bits that are shifted out reappear as the incoming fill bits. The C-language version of the rotation instructions incorporate the carry bit into the rotation.

BT | r1, r2/#n | copy bit r2/#n of r1 into carry
BTS | r1, r2/#n | set bit r2/#n of r1, copy previous value into carry
BTC | r1, r2/#n | clear bit r2/#n of r1, copy previous value into carry

Control Flow

* | Jcc | dest | branch conditional
* | JMP | dest | jump direct
* | JMP | r/m | jump indirect
* | CALL | dest | call direct
* | CALL | r/m | call indirect

The call instruction pushes the return address onto the stack then jumps to the destination.

* RET #n return

The ret instruction pops and jumps to the return address on the stack. A nonzero #n in the RET instruction indicates that after popping the return address, the value #n should be added to the stack pointer.

LOOP | decrement ecx and jump if result is nonzero
LOOPZ | decrement ecx and jump if result is nonzero and zr was set
LOOPNZ | decrement ecx and jump if result is nonzero and zr was clear
JECXZ | jump if ecx is zero

These instructions are remnants of the x86's CISC heritage and in recent processors are actually slower than the equivalent instructions written out the long way.

String Manipulation

* | MOVST | move T from esi to edi
 | CMPST | compare T from esi with edi
 | SCAST | scan T from edi for accT
 | LODST | load T from esi into accT
* | STOST | store T to edi from accT

After performing the operation, the source and destination register are incremented or decremented by sizeof(T), according to the setting of the direction flag (up or down).

The instruction can be prefixed by REP to repeat the operation the number of times specified by the ecx register.

The rep mov instruction is used to copy blocks of memory.

The rep stos instruction is used to fill a block of memory with accT.

Flags

LAHF | load ah from flags
SAHF | store ah to flags
STC | set carry
CLC | clear carry
CMC | complement carry
STD | set direction to down
CLD | set direction to up
STI | enable interrupts
CLI | disable interrupts

Interlocked Instructions

XCHG | r1, r/m | swap r1 and r/m
XADD | r1, r/m | add r1 to r/m, put original value in r1
CMPXCHG | r1, r/m | compare and exchange conditional

The cmpxchg instruction is the atomic version of the following:

   cmp     accT, r/m
   jz      match
   mov     accT, r/m
   jmp     done
match:
   mov     r/m, r1
done:

Miscellaneous

 | INT | #n | trap to kernel
 | BOUND | r, m | trap if r not in range
* | NOP |  | no operation
 | XLATB |  | al = [ebx + al]
 | BSWAP | r | swap byte order in register

A special case of the int instruction is

INT 3 debugger breakpoint trap

The opcode for INT 3 is 0xCC. The opcode for NOP is 0x90.

When debugging code, you may need to patch out some code. You can do this by replacing the offending bytes with 0x90.

Idioms

* | XOR | r, r | r = 0
* | TEST | r, r | Check if r = 0
* | ADD | r, r | shift r left by 1


Annotated x86 Disassembly

The following section will walk you through a disassembly example.

The Source Code

The following is the code for the function that will be analyzed.

HRESULT CUserView::CloseView(void)
{
    if (m_fDestroyed) return S_OK;

    BOOL fViewObjectChanged = FALSE;
    ReleaseAndNull(&m_pdtgt);

    if (m_psv) {
        m_psb->EnableModelessSB(FALSE);
        if(m_pws) m_pws->ViewReleased();

        IShellView* psv;

        HWND hwndCapture = GetCapture();
        if (hwndCapture && hwndCapture == m_hwnd) {
            SendMessage(m_hwnd, WM_CANCELMODE, 0, 0);
        }

        m_fHandsOff = TRUE;
        m_fRecursing = TRUE;
        NotifyClients(m_psv, NOTIFY_CLOSING);
        m_fRecursing = FALSE;

        m_psv->UIActivate(SVUIA_DEACTIVATE);

        psv = m_psv;
        m_psv = NULL;

        ReleaseAndNull(&_pctView);

        if (m_pvo) {
            IAdviseSink *pSink;
            if (SUCCEEDED(m_pvo->GetAdvise(NULL, NULL, &pSink)) && pSink) {
                if (pSink == (IAdviseSink *)this)
                    m_pvo->SetAdvise(0, 0, NULL);
                pSink->Release();
            }

            fViewObjectChanged = TRUE;
            ReleaseAndNull(&m_pvo);
        }

        if (psv) {
            psv->SaveViewState();
            psv->DestroyViewWindow();
            psv->Release();
        }

        m_hwndView = NULL;
        m_fHandsOff = FALSE;

        if (m_pcache) {
            GlobalFree(m_pcache);
            m_pcache = NULL;
        }

        m_psb->EnableModelessSB(TRUE);

        CancelPendingActions();
    }

    ReleaseAndNull(&_psf);

    if (fViewObjectChanged)
        NotifyViewClients(DVASPECT_CONTENT, -1);

    if (m_pszTitle) {
        LocalFree(m_pszTitle);
        m_pszTitle = NULL;
    }

    SetRect(&m_rcBounds, 0, 0, 0, 0);
    return S_OK;
}

The Assembly Code

This section contains the annotated disassembly example.

Functions with EBP frames will start out the following way:

HRESULT CUserView::CloseView(void)
SAMPLE!CUserView__CloseView:
71517134 55               push    ebp
71517135 8bec             mov     ebp,esp

This sets up the frame so the function can access its parameters as positive offsets from EBP, and local variables as negative offsets.

This is a method on a private COM interface, so the calling convention is Stdcall. This means that parameters are pushed right to left (in this case, there are none), then the "this" pointer is pushed, then the function is called. So on entry to the function, the stack looks like this:

[esp+0] = return address
[esp+4] = this

After the above two instructions, the parameters are accessible as:

[ebp+0] = previous ebp pushed on stack
[ebp+4] = return address
[ebp+8] = this

For a function that uses a standard EBP frame, the first pushed parameter is accessible at [ebp+8]; subsequent parameters are accessible at consecutive higher DWORD addresses.

71517137 51               push    ecx
71517138 51               push    ecx

This function requires only two local stack variables, so it's smaller to push two dummy registers than to do a "sub esp, 8". The pushed values are then available as [ebp-4] and [ebp-8].

For a function that uses a standard EBP frame, stack local variables are accessible at negative offsets from the EBP register.

71517139 56               push    esi

Now the compiler saves the registers that are required to be preserved across function calls. Actually, it saves them in bits and pieces, interleaved with the first line of actual code.

7151713a 8b7508           mov     esi,[ebp+0x8]     ; esi = this
7151713d 57               push    edi               ; save another registers

It so happens that CloseView is a method on ViewState, which is at offset 12 in the underlying object. This method will be referred to as "this," although when there is possible confusion with another base class, it will be more carefully specified as "(ViewState*)this."

    if (m_fDestroyed)
7151713e 33ff             xor     edi,edi           ; edi = 0

XOR'ing a register with itself is a standard way of zeroing it out.

71517140 39beac000000     cmp     [esi+0xac],edi    ; this->m_fDestroyed == 0?
71517146 7407             jz      NotDestroyed (7151714f)  ; jump if equal

The cmp instruction compares two values (by subtracting them). The jz instruction checks if the result is zero, indicating that the two compared values are equal.

The cmp instruction compares two values; a subsequent j instruction jumps based on the result of the comparison.

    return S_OK;
71517148 33c0             xor     eax,eax           ; eax = 0 = S_OK
7151714a e972010000       jmp     ReturnNoEBX (715172c1) ; return, do not pop EBX

The compiler delayed saving the EBX register until later in the function, so if the program is going to "early-out" on this test, then the exit path needs to be the one that doesn't restore EBX.

    BOOL fViewObjectChanged = FALSE;
    ReleaseAndNull(&m_pdtgt);

The execution of these two lines of code is interleaved, so pay attention.

NotDestroyed:
7151714f 8d86c0000000     lea     eax,[esi+0xc0]    ; eax = &m_pdtgt

The lea instruction computes the effect address of a memory access and stores it in the destination. The actual memory address is not dereferenced.

The lea instruction takes the address of a variable.

71517155 53               push    ebx

You should save that EBX register before it is damaged.

71517156 8b1d10195071     mov ebx,[_imp__ReleaseAndNull]

Since you will be calling ReleaseAndNull a lot, it is a good idea to cache its address in EBX.

7151715c 50               push    eax               ; parameter to ReleaseAndNull
7151715d 897dfc           mov     [ebp-0x4],edi     ; fViewObjectChanged = FALSE
71517160 ffd3             call    ebx               ; call ReleaseAndNull
    if (m_psv) {
71517162 397e74           cmp     [esi+0x74],edi    ; this->m_psv == 0?
71517165 0f8411010000     je      No_Psv (7151727c) ; jump if zero

Remember that you zeroed out the EDI register a while back, and that EDI is a register preserved across function calls (so the call to ReleaseAndNull didn't change it). Therefore, it still holds the value zero and you can use it to test for zero quickly.

        m_psb->EnableModelessSB(FALSE);
7151716b 8b4638           mov     eax,[esi+0x38]    ; eax = this->m_psb
7151716e 57               push    edi               ; FALSE
7151716f 50               push    eax               ; "this" for callee
71517170 8b08             mov     ecx,[eax]         ; ecx = m_psb->lpVtbl
71517172 ff5124           call    [ecx+0x24]        ; __stdcall EnableModelessSB

The above pattern is a telltale sign of a COM method call.

COM method calls are pretty popular, so it's a good idea to learn to recognize them. In particular, you should be able to recognize the three IUnknown methods directly from their Vtable offsets: QueryInterface=0, AddRef=4, and Release=8.

        if(m_pws) m_pws->ViewReleased();
71517175 8b8614010000     mov     eax,[esi+0x114]   ; eax = this->m_pws
7151717b 3bc7             cmp     eax,edi           ; eax == 0?
7151717d 7406             jz      NoWS (71517185) ; if so, then jump
7151717f 8b08             mov     ecx,[eax]         ; ecx = m_pws->lpVtbl
71517181 50               push    eax               ; "this" for callee
71517182 ff510c           call    [ecx+0xc]         ; __stdcall ViewReleased
NoWS:
        HWND hwndCapture = GetCapture();
71517185 ff15e01a5071    call [_imp__GetCapture]    ; call GetCapture

Indirect calls through globals is how function imports are implemented in Microsoft® Win32®. The loader fixes up the globals to point to the actual address of the target. This is a handy way to get your bearings when you're investigating a crashed machine. Look for the calls to imported functions and in the target. You'll usually have the name of some imported function, which you can use to figure out where you are in the source code.

        if (hwndCapture && hwndCapture == m_hwnd) {
            SendMessage(m_hwnd, WM_CANCELMODE, 0, 0);
        }
7151718b 3bc7             cmp     eax,edi           ; hwndCapture == 0?
7151718d 7412             jz      No_Capture (715171a1) ; jump if zero

The function return value is placed in the EAX register.

7151718f 8b4e44           mov     ecx,[esi+0x44]    ; ecx = this->m_hwnd
71517192 3bc1             cmp     eax,ecx           ; hwndCapture = ecx?
71517194 750b             jnz     No_Capture (715171a1) ; jump if not

71517196 57               push    edi               ; 0
71517197 57               push    edi               ; 0
71517198 6a1f             push    0x1f              ; WM_CANCELMODE
7151719a 51               push    ecx               ; hwndCapture
7151719b ff1518195071     call    [_imp__SendMessageW] ; SendMessage
No_Capture:
        m_fHandsOff = TRUE;
        m_fRecursing = TRUE;
715171a1 66818e0c0100000180 or    word ptr [esi+0x10c],0x8001 ; set both flags at once

        NotifyClients(m_psv, NOTIFY_CLOSING);
715171aa 8b4e20           mov     ecx,[esi+0x20]    ; ecx = (CNotifySource*)this.vtbl
715171ad 6a04             push    0x4               ; NOTIFY_CLOSING
715171af 8d4620           lea     eax,[esi+0x20]    ; eax = (CNotifySource*)this
715171b2 ff7674           push    [esi+0x74]        ; m_psv
715171b5 50               push    eax               ; "this" for callee
715171b6 ff510c           call    [ecx+0xc]         ; __stdcall NotifyClients

Notice how you had to change your "this" pointer when calling a method on a different base class from your own.

        m_fRecursing = FALSE;
715171b9 80a60d0100007f   and     byte ptr [esi+0x10d],0x7f
        m_psv->UIActivate(SVUIA_DEACTIVATE);
715171c0 8b4674           mov     eax,[esi+0x74]    ; eax = m_psv
715171c3 57               push    edi               ; SVUIA_DEACTIVATE = 0
715171c4 50               push    eax               ; "this" for callee
715171c5 8b08             mov     ecx,[eax]         ; ecx = vtbl
715171c7 ff511c           call    [ecx+0x1c]        ; __stdcall UIActivate
        psv = m_psv;
        m_psv = NULL;
715171ca 8b4674           mov     eax,[esi+0x74]    ; eax = m_psv
715171cd 897e74           mov     [esi+0x74],edi    ; m_psv = NULL
715171d0 8945f8           mov     [ebp-0x8],eax     ; psv = eax

Psv is your first local variable.

        ReleaseAndNull(&_pctView);
715171d3 8d466c           lea     eax,[esi+0x6c]    ; eax = &_pctView
715171d6 50               push    eax               ; parameter
715171d7 ffd3             call    ebx               ; call ReleaseAndNull
        if (m_pvo) {
715171d9 8b86a8000000     mov     eax,[esi+0xa8]    ; eax = m_pvo
715171df 8dbea8000000     lea     edi,[esi+0xa8]    ; edi = &m_pvo
715171e5 85c0             test    eax,eax           ; eax == 0?
715171e7 7448             jz      No_Pvo (71517231) ; jump if zero

Note that the compiler speculatively prepared the address of the m_pvo member because you're going to use it a lot for a while, so having the address handy will result in smaller code.

            if (SUCCEEDED(m_pvo->GetAdvise(NULL, NULL, &pSink)) && pSink) {
715171e9 8b08             mov     ecx,[eax]         ; ecx = m_pvo->lpVtbl
715171eb 8d5508           lea     edx,[ebp+0x8]     ; edx = &pSink
715171ee 52               push    edx               ; parameter
715171ef 6a00             push    0x0               ; NULL
715171f1 6a00             push    0x0               ; NULL
715171f3 50               push    eax               ; "this" for callee
715171f4 ff5120           call    [ecx+0x20]        ; __stdcall GetAdvise
715171f7 85c0             test    eax,eax           ; test bits of eax
715171f9 7c2c             jl      No_Advise (71517227) ; jump if less than zero
715171fb 33c9             xor     ecx,ecx           ; ecx = 0
715171fd 394d08           cmp     [ebp+0x8],ecx     ; _pSink == ecx?
71517200 7425             jz      No_Advise (71517227)

Notice that the compiler concluded that the incoming "this" parameter was not required (since it long ago stashed that into the ESI register), so it reused the memory as the local variable pSink.

If the function uses an EBP frame, then incoming parameters arrive at positive offsets from EBP and local variables are placed at negative offsets. But, as in this case, the compiler is free to reuse that memory for any purpose.

If you're paying really close attention, you'll see that the compiler could've optimized this code a little better. It could've delayed the lea edi, [esi+0xa8] instruction until after the two push 0x0 instructions above, replacing them with push edi. This would've saved two bytes.

                if (pSink == (IAdviseSink *)this)

These next several lines are to compensate for the fact that in C++, (IAdviseSink *)NULL must still be NULL. So if your "this" is really "(ViewState*)NULL", then the result of the cast should be NULL and not the distance between IAdviseSink and IBrowserService.

71517202 8d46ec           lea     eax,[esi-0x14]    ; eax = -(IAdviseSink*)this
71517205 8d5614           lea     edx,[esi+0x14]    ; edx = (IAdviseSink*)this
71517208 f7d8             neg     eax               ; eax = -eax (sets carry if != 0)
7151720a 1bc0             sbb     eax,eax           ; eax = eax - eax - carry
7151720c 23c2             and     eax,edx           ; eax = NULL or edx

Although the Pentium has a conditional move instruction, the base i386 architecture does not, so the compiler uses tricks to simulate a conditional move instruction without taking any jumps.

The general pattern for a conditional evaluation is the following:

        neg     r
        sbb     r, r
        and     r, (val1 - val2)
        add     r, val2

The neg r sets the carry flag if r is nonzero, because neg negates the value by subtracting from zero, and subtracting from zero will generate a borrow (set the carry) if you subtract a nonzero value. It also damages the value in the r register, but that's okay because you're about to overwrite it anyway.

Next, the sbb r, r instruction subtracts a value from itself, which always results in zero, but it also subtracts the carry (borrow) bit, so the net result is to set r to 0 or -1, depending on whether the carry was clear or set, respectively.

Therefore, sbb r, r sets r to zero if the original value of r was zero, or to -1 if the original value was nonzero.

The third instruction performs a mask. Since the r register is 0 or -1, "this" serves either to leave r zero or to change r from -1 to (val1 - val1), since ANDing any value with -1 leaves the original value.

Therefore, the result of "and r, (val1 - val1)" is to set r to 0 if the original value of r was zero, or to "(val1 - val2)" if the original value of r was nonzero.

Finally, you add val2 to r, resulting in val2 or (val1 - val2) + val2 = val1.

So the ultimate result of this series of instructions is to set r to val2 if it was originally zero or to val1 if it was nonzero.

This is the assembly equivalent of r = r ? val1 : val2.

In this particular instance, you can see that val2 = 0 and val1 = (IAdviseSink*)this. (Notice that the compiler elided the final add eax, 0 since it has no effect.)

7151720e 394508           cmp     [ebp+0x8],eax ; pSink == (IAdviseSink*)this?
71517211 750b             jnz     No_SetAdvise (7151721e) ; jump if not equal

Earlier in this section, you set EDI to the addess of the m_pvo member. You're going to be using it now. You also zeroed out the ECX register a while back.

                    m_pvo->SetAdvise(0, 0, NULL);
71517213 8b07             mov     eax,[edi]         ; eax = m_pvo
71517215 51               push    ecx               ; NULL
71517216 51               push    ecx               ; 0
71517217 51               push    ecx               ; 0
71517218 8b10             mov     edx,[eax]         ; edx = m_pvo->lpVtbl
7151721a 50               push    eax               ; "this" for callee
7151721b ff521c           call    [edx+0x1c]        ; __stdcall SetAdvise
No_SetAdvise:
                pSink->Release();
7151721e 8b4508           mov     eax,[ebp+0x8]     ; eax = pSink
71517221 50               push    eax               ; "this" for callee
71517222 8b08             mov     ecx,[eax]         ; ecx = pSink->lpVtbl
71517224 ff5108           call    [ecx+0x8]         ; __stdcall Release
No_Advise:

All these COM method calls should look very familiar.

The evaluation of the next two statements is interleaved. Don't forget that EBX contains the address of ReleaseAndNull.

            fViewObjectChanged = TRUE;
            ReleaseAndNull(&m_pvo);
71517227 57               push    edi               ; &m_pvo
71517228 c745fc01000000   mov     dword ptr [ebp-0x4],0x1 ; fViewObjectChanged = TRUE
7151722f ffd3             call    ebx               ; call ReleaseAndNull
No_Pvo:
        if (psv) {
71517231 8b7df8           mov     edi,[ebp-0x8]     ; edi = psv
71517234 85ff             test    edi,edi           ; edi == 0?
71517236 7412             jz      No_Psv2 (7151724a) ; jump if zero
            psv->SaveViewState();
71517238 8b07             mov     eax,[edi]         ; eax = psv->lpVtbl
7151723a 57               push    edi               ; "this" for callee
7151723b ff5034           call    [eax+0x34]        ; __stdcall SaveViewState

Here are more COM method calls.

            psv->DestroyViewWindow();
7151723e 8b07             mov     eax,[edi]         ; eax = psv->lpVtbl
71517240 57               push    edi               ; "this" for callee
71517241 ff5028           call    [eax+0x28]        ; __stdcall DestroyViewWindow
            psv->Release();
71517244 8b07             mov     eax,[edi]         ; eax = psv->lpVtbl
71517246 57               push    edi               ; "this" for callee
71517247 ff5008           call    [eax+0x8]         ; __stdcall Release
No_Psv2:
        m_hwndView = NULL;
7151724a 83667c00         and     dword ptr [esi+0x7c],0x0 ; m_hwndView = 0

ANDing a memory location with zero is the same as setting it to zero, since anything AND zero is zero. The compiler uses this form because, even though it's slower, it's much shorter than the equivalent mov instruction. (This code was optimized for size, not speed.)

        m_fHandsOff = FALSE;
7151724e 83a60c010000fe   and     dword ptr [esi+0x10c],0xfe
        if (m_pcache) {
71517255 8b4670           mov     eax,[esi+0x70]    ; eax = m_pcache
71517258 85c0             test    eax,eax           ; eax == 0?
7151725a 740b             jz      No_Cache (71517267) ; jump if zero
            GlobalFree(m_pcache);
7151725c 50               push    eax               ; m_pcache
7151725d ff15b4135071     call    [_imp__GlobalFree]    ; call GlobalFree
            m_pcache = NULL;
71517263 83667000         and     dword ptr [esi+0x70],0x0 ; m_pcache = 0
No_Cache:
        m_psb->EnableModelessSB(TRUE);
71517267 8b4638           mov     eax,[esi+0x38]    ; eax = this->m_psb
7151726a 6a01             push    0x1               ; TRUE
7151726c 50               push    eax               ; "this" for callee
7151726d 8b08             mov     ecx,[eax]         ; ecx = m_psb->lpVtbl
7151726f ff5124           call    [ecx+0x24]        ; __stdcall EnableModelessSB
        CancelPendingActions();

In order to call CancelPendingActions, you have to move from (ViewState*)this to (CUserView*)this. Note also that CancelPendingActions uses the __thiscall calling convention instead of __stdcall. According to __thiscall, the "this" pointer is passed in the ECX register instead of being passed on the stack.

71517272 8d4eec           lea     ecx,[esi-0x14]    ; ecx = (CUserView*)this
71517275 e832fbffff       call CUserView::CancelPendingActions (71516dac) ; __thiscall
    ReleaseAndNull(&_psf);
7151727a 33ff             xor     edi,edi           ; edi = 0 (for later)
No_Psv:
7151727c 8d4678           lea     eax,[esi+0x78]    ; eax = &_psf
7151727f 50               push    eax               ; parameter
71517280 ffd3             call    ebx               ; call ReleaseAndNull
    if (fViewObjectChanged)
71517282 397dfc           cmp     [ebp-0x4],edi     ; fViewObjectChanged == 0?
71517285 740d             jz      NoNotifyViewClients (71517294) ; jump if zero
       NotifyViewClients(DVASPECT_CONTENT, -1);
71517287 8b46ec           mov     eax,[esi-0x14]    ; eax = ((CUserView*)this)->lpVtbl
7151728a 8d4eec           lea     ecx,[esi-0x14]    ; ecx = (CUserView*)this
7151728d 6aff             push    0xff              ; -1
7151728f 6a01             push    0x1               ; DVASPECT_CONTENT = 1
71517291 ff5024           call    [eax+0x24]        ; __thiscall NotifyViewClients
NoNotifyViewClients:
    if (m_pszTitle)
71517294 8b8680000000     mov     eax,[esi+0x80]    ; eax = m_pszTitle
7151729a 8d9e80000000     lea     ebx,[esi+0x80]    ; ebx = &m_pszTitle (for later)
715172a0 3bc7             cmp     eax,edi           ; eax == 0?
715172a2 7409             jz      No_Title (715172ad) ; jump if zero
        LocalFree(m_pszTitle);
715172a4 50               push    eax               ; m_pszTitle
715172a5 ff1538125071     call   [_imp__LocalFree]
        m_pszTitle = NULL;

Remember that EDI is still zero and EBX is still &m_pszTitle, since those registers are preserved by function calls.

715172ab 893b             mov     [ebx],edi         ; m_pszTitle = 0
No_Title:
    SetRect(&m_rcBounds, 0, 0, 0, 0);
715172ad 57               push    edi               ; 0
715172ae 57               push    edi               ; 0
715172af 57               push    edi               ; 0
715172b0 81c6fc000000     add     esi,0xfc          ; esi = &this->m_rcBounds
715172b6 57               push    edi               ; 0
715172b7 56               push    esi               ; &m_rcBounds
715172b8 ff15e41a5071     call   [_imp__SetRect]

Notice that you don't need the value of "this" any more, so the compiler uses the add instruction to modify it in place instead of blowing another register to hold the address. This is actually a performance win due to the Pentium u/v pipelining, since the v pipe can do arithmetic but not address computations.

    return S_OK;
715172be 33c0             xor     eax,eax           ; eax = S_OK

Finally, you restore the registers you are required to preserve, clean up the stack, and return to your caller, removing the incoming parameters.

715172c0 5b               pop     ebx               ; restore
ReturnNoEBX:
715172c1 5f               pop     edi               ; restore
715172c2 5e               pop     esi               ; restore
715172c3 c9               leave                     ; restores EBP and ESP simultaneously
715172c4 c20400           ret     0x4               ; return and clear parameters


The IA-64 Processor

This section includes:

The IA-64 Architecture

The IA-64 Instructions

Annotated IA-64 Disassembly


The IA-64 Architecture

The IA-64 processor has several features which do not appear on the x86 processor:

  • EPIC - Explicit Parallel Instruction Computation
  • A large number of registers (Doing as much as possible in registers gets you better performance.)
  • Dedicated register usage (integer registers, branch registers, floating point registers)
  • Conditional execution (predication) on almost all instructions
  • Modulo scheduling for software pipelining

Registers

The IA-64 has a large number of registers.

  • 128 integer registers, each with a NaT bit (r0 - r127)
  • 128 floating point registers (f0 - f127)
  • 64 predicate registers (p0 - p63)
  • 8 branch registers (b0 - b7)
  • An Instruction Pointer (the debugger calls this iip)
  • 128 other special-purpose registers (not all of which yet have been given meanings). These are called the "application register set," or "ar" registers. (They are not covered in this documentation.)
  • A number of miscellaneous registers, not covered in this documentation.

Many of the registers are further subdivided into categories like static, stacked, and rotating.

When discussing register preservation conventions, the term preserved refers to a register whose value must be preserved by a function, and scratch refers to a register whose value can be modified by a function.

When using the ? (Evaluate Expression) command, registers should be prefixed with an "at" sign ( @ ). For example, you should use ? @f0 rather than ? f0. This assures that the debugger recognizes f0 as a register, rather than as a hexadecimal number or a symbol.

However, the "at" sign is not required in the R (Registers) command. For instance, r r32 = 5 will always be interpreted correctly.

Integer Registers

The 128 integer registers are named r0 through r127, and they break down as follows:

r0 – r31 | static general registers
r32 – r127 | stacked general registers

Some of the registers have special meaning, most of which are assigned by convention rather than hardware requirement. (The only one that is a hardware requirement is r0.)

r0 | reads as zero (writing will AV)
gp | global pointer (r1)
ret0 – ret3 | function return values go here (r8 through r11)
sp | stack pointer (r12)
r13 | TEB

By convention, registers r4 through r7 are preserved. You also do not change the TEB pointer if you know what's good for you.

The gp register points to your global variables. To access a global variable, you have to indirect OFF the gp register. The gp register is kept up to date when you jump from one DLL to another by means described later.

The other static registers are scratch.

All integer registers are 64-bit, with a magic NaT bit attached to each one. NaT stands for "not a thing" and is used by speculative execution to indicate that the register values are undefined.

The static integer registers do not participate in register stacking. The behavior of the stacked registers (including their preservation rules) will be described in Procedure Calls and the Register Stack subsection of this section.

The return value registers hold function return values and therefore can be trashed across a function call. Notice that there are four integer return value registers at 64 bits each, for a total of 256 bits or 32 bytes of data that can be returned from a function. (Twice the size of a GUID.)

Floating Point Registers

f0 | reads as 0.0 (writing to it will AV)
f1 | reads as 1.0 (writing to it will AV)
f2 – f31 | static floating point registers
f32 – f127 | rotating floating point registers

This document does not discuss floating point code.

By convention, floating point registers f2 through f5 and f16 through f31 are preserved across calls; the rest are scratch.

Predicate Registers

pr0 | reads as TRUE (writes are ignored)
pr1 – pr15 | static predicate registers
pr16 – pr63 | rotating predicate registers

Predicate registers act as flags. They record the result of comparison instructions, and you can test them later to perform predication. You can predicate almost any instruction, not just jump instructions. For example,

(p1)    add      ret0 = r32, r33

instruction means "set register ret0 equal to register r32 plus register r33 if register p1 is TRUE; otherwise, do nothing." Allowing arbitrary predication helps performance a lot: You have fewer jump instructions and therefore less misprediction You can also pack your instructions tighter since jump targets must begin on a bundle boundary, but predicated instructions can go anywhere.

The parenthesized predicate register is called the "qualifying predicate" (abbreviated "qp"). Since predicate register zero is always TRUE, unconditional instructions are internally encoded as conditional on p0.

By convention, predicate registers pr6 through pr15 are scratch; the rest are preserved.

There is a special pseudo-register called pr (called preds by the debugger) which consists of the 64 predicate registers combined to form a single 64-bit value. This lets you read and write all the predicate registers so you can preserve them across a call.

Branch Registers

The branch registers b0 through b7 are used for computed jump instructions. These are dedicated to computed jumps so the processor can optimize more efficiently for them.

By convention, the following meanings are assigned to the branch registers.

br | return address (b0)
b1 – b5 | preserved across procedure calls
b6 – b7 | scratch

Application Registers

Of the application registers, ar.unat and ar.lc must be preserved across calls.

Procedure Calls and the Register Stack

Each procedure declares how many parameters it has (input registers), how many private registers it needs (local registers), and the maximum number of parameters of any function it calls (output registers). The input registers plus the local registers are together called the "local region." The input registers plus the local registers plus the output registers are together called the "register stack frame".

For example, this function

int sampleFunction(int a, int b)
{
    int c;
    c = someFunction(0) + otherFunction(a, b);
    return c;
}

would specify two input registers, some number of local registers, and two output registers.

When control enters a procedure, the alloc instruction shuffles the registers around.

Suppose the calling function uses five local registers (r32 thrugh r36) and it wanted to execute a sampleFunction(3,4).

Before calling the function, the registers would be arranged like this:

 static         local rgn   output
 r0   ...   r31 r32     r36 r37 r38 r39 ...
+--------------+-----------+-------+-------------
| 0   ...   aaa|bbb ... ccc|  3   4|??? ...
+--------------+-----------+-------+-------------

Registers r37 and r38 are the output registers and contain the parameters to the function.

When sampleFunction gets control, it executes an alloc instruction.

    alloc   r34 = ar.pfs, 2, 2, 2, 0

This means "Set up the register stack frame as follows: 2 input registers, 2 local register, 2 output registers, and 0 rotating registers. Save the previous register frame state (pfs) in register r34 so it can be restored later."

This instruction shuffles the registers like this:

 static         local rgn       output
 r0   ...   r31 r32 r33 r34 r35 r36 r37 ...
+--------------+---------------+-------+----------
| 0   ...   aaa|  3   4 pfs ???|??? ???|...
+--------------+---------------+-------+----------

The static registers didn't change. What used to be the output registers are now the input registers; the local registers are uninitialized. (Except for register r34 which was explicitly set to ar.pfs by the first parameter of the alloc instruction.) What used to be in the local variables got pushed onto the register stack; they are not accessible to the called function.

Note The distinction between input and local registers is purely semantic. It makes no difference for the processor. The only important thing to the encoding of the instructionis the size of the local region, so when you read the instruction in disassembly, the first number is the size of the local region and the second number is always zero. Thus, the above alloc instruction will be disassembled as

alloc r34 = ar.pfs, 4, 0, 2, 0

Note In reality, this register shuffling process happens in two stages. The br.call instruction is the one that renumbers the registers. The alloc instruction is the one that describes the layout of the registers on the receiving side. But in simple cases, you can act as if the alloc instruction does it all. In complicated situations, you might want to execute multiple alloc instructions to "reinterpret" all your registers.

The called function now performs its operation, maybe calls some other functions, and then when it is ready to return, the registers look like this:

 static         local rgn       output
 r0...ret0..r31 r32 r33 r34 r35 r36 r37 ...
+--------------+---------------+-------+----------
| 0...rrr...aaa|xxx yyy zzz www|??? ???|...
+--------------+---------------+-------+----------

It has placed the function return value (rrr) into the ret0 register. All the registers in the local region contain whatever values are left over from the computation.

When control returns to the calling function, the register stack is "popped" and the registers look like this:

 static         local rgn   output
 r0...ret0..r31 r32     r36 r37 r38 r39 ...
+--------------+-----------+-------+-------------
| 0...rrr...aaa|bbb ... ccc|??? ???|??? ...
+--------------+-----------+-------+-------------

All the old registers in the local region are restored from the register stack, and the return value is now available in the ret0 register. Note that the values in the output registers have returned to garbage. You cannot rely on the values of output registers being preserved across a call.

The hardware supports any number of output registers, but by convention, only the first eight are used to contain function parameters. Parameters beyond eight are passed on the stack.

The register stack is itself limited in size. If you push too many registers onto the register stack, it spills into regular memory.

The gp Register

The gp register is used to access global variables in your module. The rules for its management are tricky:

  • On entry to a function, gp is assumed properly initialized.
  • When you call a function within your module, gp must be properly initialized.
  • When you call a function outside your module, the gp register can be trashed on return.
  • When you return from a function, gp must contain the value it did when your function started.

These rules allow for the following procedure call paradigms:

  • Call to function in same module: Just call it, there is no need to use gp. The gp register will still be valid on return.
  • Call to function in other module: Set up gp appropriate for the module you are calling, then restore it after the function returns.

So how do you set up gp for the target? A function pointer on the IA-64 is really a pointer to a block of data that describes the target function. One of the things in that block of data is the value of gp the target function expects.

Return to the sampleFunction example. Suppose this were an exported function. The code to call it would go like this:

        mov     r37 = 3             // set up the function parameters
        mov     r38 = 4
        addl    r31 = 0x108, gp;;   // r31 -> import table entry
        ld8     r30 = [r31];;       // r30 -> sampleFunction descriptor
        ld8     r41 = [r30], 8;;    // r41 = actual address of function
        ld8     gp = [r30]          // set up gp for sampleFunction
        mov     b6 = r41            // set up the branch register
        br.call rp = b6;;           // call the function
        mov     gp = ...            // restore gp to original value

This means that if you try to disassemble at sampleFunction you will end up just looking at the function descriptor rather than the function itself. The function itself begins with a dot, so if you wanted to see the code for sampleFunction you would have to type u .sampleFunction.

Debugger Register Dump

     dbi0 =                0         dbi1 =                0
     dbi2 =                0         dbi3 =                0
     dbi4 =                0         dbi5 =                0
     dbi6 =                0         dbi7 =                0
     dbd0 =                0         dbd1 =                0
     dbd2 =                0         dbd3 =                0
     dbd4 =                0         dbd5 =                0
     dbd6 =                0         dbd7 =                0

       gp =         77560000 0         r2 =      6fbffc90bf0 0
       r3 = c000000000000309 0         r4 =         78190000 0
       r5 =          1010aa0 0         r6 =      6fbfffde000 0
       r7 =                0 0         r8 =      6fbffe8d948 0
       r9 = ffffffffffffffff 0        r10 =                0 0
      r11 =         ffffffff 0         sp =      6fbffe8d520 0
      r13 =      6fbfffdc000 0        r14 =      6fbffc90be8 0
      r15 =                0 0        r16 = e0000165e11ae7f0 0
      r17 = e0000165e11ae910 0        r18 =      6fbffc90bec 0
      r19 =                0 0        r20 =    9804c8a70033f 0
      r21 = e000000086b8ee20 0        r22 = e000000086b96040 0
      r23 =                1 0        r24 =             7f05 0
      r25 =               2f 0        r26 =              14e 0
      r27 =                6 0        r28 =      6fb000006fb 0
      r29 =            6fbff 0        r30 =              103 0
      r31 =                0 0    intnats =                0

    preds =             8941

       b0 =         772b43b0           b1 = e0000000ffa005c0
       b2 =         766e9e88           b3 =                0
       b4 =                0           b5 =                0
       b6 =         772ba2e0           b7 =                0

     unat =                0           lc =                0
       ec =                0          ccv = e000000086c577b0
      dcr =             7f05          pfs = c000000000000309
      bsp =      6fbffe90cc8     bspstore =      6fbffe90cc8
      rsc =                f         rnat =                0
     ipsr =     1013082a6018          iip =         772b4310
      ifs = 8000000000000204          fcr =               40
    eflag =              202          csd = cfbfffff00000000
      ssd = cf3fffff00000000        cflag =              111
      fsr =                0          fir =                0
      fdr =                0

      r32 =      6fbffe8d948 0        r33 =      6fb000006fb 0
      r34 =              104 0        r35 =             8941 0

At the top are eight instruction debug registers (dbi) and eight data debug registers (dbd).

Next come the static integer registers, followed by intnats, which is all the NaT bits combined to form a 32-bit integer.

Preds is all the predicate registers combined into a 64-bit integer.

Then come all the branch registers.

Then a bunch of special-purpose registers. Of them, these are the only ones you will probably ever need to deal with:

  • ar.pfs describes the stack frame of the previous function.
  • ar.ccv is an implicit parameter for the cmpxchg instruction.

Finally, the registers for the current register stack frame. You happen to be in a function that has four registers in its frame, so the debugger showed the first four stacked registers, r32 through r35. If the function used more registers, this part would've been bigger.

Notation

x | 1 (byte), 2 (word), 4 (long) or 8 (quad)
Ra, Rb, Rc... | registers
immn | a signed n-bit constant
Rb/immn | a register or a constant
Ba/addr | a branch register or an address
cc | a condition (eq, ne, etc.)
Rb<n1, n2> | n2 bits from Rb starting at position n1.
f | a floating point type (s, d, e)

For example, Rb<5, 4> means "extract 4 bits from Rb starting at position 5," which is the value (Rb >> 5) & 0x0F.

Many instructions can be modified by suffixes called "completers."

Addressing Modes

Unlike the x86 instruction set, which has more addressing modes than you can shake a stick at, the IA-64 instruction set has only one addressing mode: Register indirect. The notation for register indirect is "[r]" which means "the value stored at memory location r." The thing inside the brackets is always a register.

Instruction Format and Pipelining

Instructions are packaged into groups of three called "bundles." If you execute an .asm verbose command, the instructions that belong to a bundle will be surrounded by curly brackets. Bundles always start on 16-byte boundaries (in other words, the last digit of the hexadecimal address is 0).

You cannot jump into the middle of a bundle.

There are restrictions on what type of instruction can be put into a particular slot in a bundle. For example, one valid bundle type is "MII," which means that slot 0 is a memory access, slot 1 is an integer instruction, and slot 2 is another integer instruction.

Valid instruction types are:

  • M - Memory/Move instruction
  • I - Complex Integer/Multimedia instruction
  • A - Simple Integer/Logic/Multimedia instruction
  • F - Floating Point instruction (Normal/SIMD)
  • B - Branch instruction

Many instructions can be used in multiple slot types, in which case a completer is specified to disambiguate them. For example, there are five different nop instructions (nop.m, nop.i, nop.f, nop.b, nop.x) depending on which type of slot it got placed into.

Each valid combination of instruction categories is called a template. There are 32 different templates. Some of the templates differ only in the placement of stops.

A stop is used to indicate that instructions after the stop depend on instructions before the stop. For example, if you have the following series of instructions

    mov r3 = r2
    add r1 = r2,r4 ;;
    add r2 = r1,r3

there is no dependency between the first two instructions, but the third instruction cannot execute until after the first two have completed. Therefore, the compiler inserts a stop, represented by a double semicolon, after the second instruction.

Note that a stop does not have to go at the end of a bundle. There are some bundle templates that have stops in the middle and some that have more than one stop. For example, template 11 is an "M|MI|" instruction. Slot 0 is a memory access, then there is a stop after slot 0, then slot 1 is another memory access, then slot 2 is an integer instruction, then there is another stop after slot 2.

An instruction group is a sequence of instructions up until the next stop, taken branch, interrupt, or exception. The instructions within an instruction group cannot have dependencies among them. This allows the processor to execute them in parallel.

There are some exceptions to the "no dependencies" rule.

  • A branch instruction is allowed to depend on a predicate register and branch register set elsewhere in the group.
  • You can use the result of a successful ld.c without an intervening stop.
  • Instructions after a branch will implicitly depend on whether the branch was taken; this is okay. But instructions after a branch cannot interfere with instructions before the branch.
  • Comparison instructions .and, .andcm, .or and .orcm are allowed to combine with others of the same type into the same target registers. (Meaning you can't combine an .and with an .or.)
  • You are allowed to write to a register after a previous instruction reads it. (With rare exceptions.)
  • Two instructions in the group cannot both write to the same register. (With the exception of combined comparison instructions as noted above.)

This description omits a number of details that are important only to compiler-writers or people hand-writing IA-64 assembly. When reading disassembly, you can assume that the compiler or author generated correct code. (Unless you're chasing a compiler bug.)

Speculative Execution

The ld instruction (load from memory) supports an .s completer, which means that execution of the instruction is speculated. (Naturally, you can't speculatively write to memory.)

An instruction that can be speculated is called a speculative instruction, rather than a speculatable instruction. Consequently, this documentation will use the word "speculated" to refer to the .s variant of the ld instruction.

A speculated load is just like a regular load, except that if an exception occurs, the processor sets the NaT bit in the destination register instead of raising the exception.

If any input to an integer computation instruction has the NaT bit set, then the result of the computation will also have the NaT bit set. If any input to a comparison instruction has the NaT bit set, then the result of the comparison is always FALSE (in a complicated way that you will probably never need to understand).

You can also speculate floating point instructions, but instead of setting the NaT bit, the entire floating point register is set to a special NaT-like value called NaTVal. As with the integer case, NaTVal infects all subsequent computations.

Perhaps you realize that the speculated execution was not necessary. (Maybe you started going down the TRUE branch of an IF statement, only to discover that the value is FALSE.) In which case, you just ignore the registers that you changed with the speculated execution and continue on your way. (Don't look at them, of course, since they might be NaT.)

If you decide that the speculated execution was worthwhile, you execute a chk.s instruction, which means "verify that this register contains an actual value. If it is a NaT, then jump to the recovery code." The recovery code typically just consists of all the speculated instructions re-executed normally, so that the exception can be raised.

Aside from the instructions mentioned above which can handle NaTs (and a few other special instructions), attempting to use the value of a NaT register will cause an exception. This isn't useful in general because you can't tell which speculated instruction caused the exception.

Advanced Loads

The IA-64 contains special techniques to optimize in the face of aliased pointers. For example, consider this code snippet:

int foo(int *p1, int *p2)
{
    *p1 = 1;
    *p2 = 2;
    return *p1;
}

This function usually returns 1, but if p1 and p2 both point to the same address, then it will return 2.

The advanced load instruction ld.a means "load this value from memory and remember the access as successful." If there is a subsequent write to that address, it is removed from the list, rendering the advance load unsucessful. (Other events can remove an entry from the list; for example, if you ask it to remember too many advanced loads, it starts forgetting the older ones.)

Later on, you can check whether the advance load is still valid. If it is not, it means that somebody modified the value and you have to reload it.

There are two types of checks. The simplest check is ld.c.nc or ld.c.clr. This says, "Check if that advanced load is still valid. If not, then reload the value." The .clr completer means that this advanced load is not important anymore, so the processor can free up the entry for recording new advanced loads; the .nc completer means that this advanced load is still valuable, so don't clear it from the table.

Here's an example that uses ld.c.clr.

    ld8.a   r6 = [r8]       ;;      // read memory at r8, remember the address
    ...                             // perform operation that might modify memory...
    ld8.c.clr r6 = [r8]             // reload r6 from [r8] if necessary
    ...                             // perform operations with the value in r6

The compiler requested to load register r6 from the memory address specified by register r8, doing so way ahead of the time it actually needs the result, in order to avoid a stall. Then it wanted to use the value in r6, but it wasn't sure if in the meantime, some pointer dereference might've modified the value, rendering the prefetched value in r6 useless.

The ld8.c.clr instruction checks if anything has written to that address (even on another processor). If not, then the instruction does nothing. But if something has indeed written to the address, then the instruction refetches the value (taking the memory stall).

The second type of check is if you need more complicated recovery than just reloading the value.

Here's an example that uses chk.a.clr.

    ld8.a   r6 = [r8]       ;;      // read memory at r8, remember the address
    add     r5 = r6, r7     ;;      // precompute based on advanced read
    ...                             // perform operations that might modify memory...
    chk.a.clr r6, failed            // memory was modified
continue:
    ...                             // perform operations with the value in r5

failed:
    ld8     r6 = [r8]       ;;      // load the correct value
    add     r5 = r6, r7             // redo the precomputation
    br      continue                // and then continue as if nothing was wrong

After doing some precomputation with the value you read from r8, you execute a chk.a.clr instruction, which checks if your advanced load is still valid. If not, you jump to failed, where you reload the value and redo the precomputation, then jump back to continue normal execution.

Speculated Advanced Loads

You can combine the above two techniques. The ld.sa instruction performs a speculated advance load.

Register Rotation

Register rotation is an advanced technique where the registers renumber themselves each time they go through a loop. It is not covered in this documentation.

Control Flow

The types of control flow you will see most of the time are jump (br.cond), call (br.call), and return (br.ret). (Conditional jumps are just regular jump instructions with a qualifying predicate attached in front.)

The jump and call instructions also have long versions (brl) if the target of the jump is really far away.

The brl instruction is actually emulated on Itanium, so don't expect it to be fast.

Branch Prediction

Each of the standard jump instructions also includes a bunch of completers. The first completer determines whether the jump should be predicted taken or not taken.

  • .spnt: Static predict not taken. Always predict not taken.
  • .sptk: Static predict taken. Always predict taken.
  • .dpnt: Dynamic predict not taken. Use the prediction hardware. If prediction hardware cannot tell, then predict not taken.
  • .dptk: Dynamic predict taken. Use the prediction hardware. If prediction hardware cannot tell, then predict taken.

Prediction hardware might not be able to tell because this instruction was never encountered before, or it was last encountered so long ago that it fell out of the cache.

The second completer specifies how aggressively you should prefetch after the cache. In other words, how sure are you that the prediction is correct.

  • .few: Prefetch a few instructions. Your prediction could be wrong, or it's just not worth prefetching very much.
  • .many: Prefetch a lot of instructions. You are confident that your prediction is correct.

Most jumps within a procedure will be marked .few, whereas unconditional subroutine calls and unconditional return instructions are usually marked .many.

Finally, there is an optional completer.

  • .clr: Clear this entry.

If you clear the entry, the processor will wipe out any knowledge of this jump instruction. Do this if you know the instruction will not be encountered again for a long time.

There is also a bonus instruction brp whose sole purpose is to hint to the processor: "Psst, I think that computed jump instruction up ahead is going to jump here."

Comparisons

In its simplest form, the comparison instruction compares two values and stores the result into two predicate registers; one gets the the result of the comparison, and the other gets the opposite of the result. For example,

    cmp.eq      p1, p2 = r32, r33

compares the two registers for equality and stores the result into p1. Meanwhile, the p2 register gets the opposite value. For example, if they were equal, then p1 would be TRUE and p2 would be FALSE.

The next most complicated comparison instruction is called the unconditional comparison, and it is always used with a qualifying predicate. Here's a sample unconditional comparison:

(p3)  cmp.eq.unc p1, p2 = r32, r33

If the qualifying predicate p3 is TRUE, then this acts just like a regular comparison instruction. But if the qualifying predicate is FALSE, then both the p1 and p2 registers are set to FALSE. This is a rare case where a qualifying predicate has an effect even though it is FALSE. (Normally, if a qualifying predicate is FALSE, the entire instruction is ignored.)

The next most complicated comparisons are the parallel comparisons. These are used when you have a chain of "a && b && c" or "a || b || c" results. Here is a sample AND parallel comparison:

    cmp.eq.and p1, p2 = r32, r33

This is expressible in C as

    p1 = p1 && (r32 == r33)
    p2 = p2 && (r32 == r33)

In other words, if the comparison is false, then both predicate registers are set to FALSE; otherwise, they are left alone.

The other variations of parallel comparisons are:

    cmp.eq.andcm p1, p2 = r32, r33

        p1 = p1 && !(r32 == r33)
        p2 = p2 && !(r32 == r33)
    cmp.eq.or p1, p2 = r32, r33

        p1 = p1 || (r32 == r33)
        p2 = p2 || (r32 == r33)
    cmp.eq.orcm p1, p2 = r32, r33

        p1 = p1 || !(r32 == r33)
        p2 = p2 || !(r32 == r33)

and the DeMorgan operators...

    cmp.eq.or.andcm p1, p2 = r32, r33

        p1 = p1 || (r32 == r33)
        p2 = p2 && !(r32 == r33)
    cmp.eq.and.orcm p1, p2 = r32, r33

        p1 = p1 && (r32 == r33)
        p2 = p2 || !(r32 == r33)

For example the expression p5 = (r4 == 0) || (r5 == r6) can be computed as follows (assuming that p5 is preinitialized to FALSE):

    cmp.eq.or   p5, p0 = r0, r4
    cmp.eq.or   p5, p0 = r5, r6

Notice that since these are both OR type comparisons, they can be combined into a single instruction group and, therefore, executed in parallel.


The IA-64 Instructions

Only the instructions most likely to be encountered in user-mode code are detailed here. Instructions marked with an asterisk (*) are particularly important.

The general notation for instructions is:

(qp)    op...   dest = src1, src2, ...

where (qp) is the optional qualifying predicate, ... after the opcode are optional completers, dest is the destination (or destinations, for comparison operators), and src is the source.

Memory Access (Aligned)

* | ldx | Ra = [Rb] | load from memory (zero-extended)
* | ldx | Ra = [Rb], Rc/imm9 | load with postincrement

An optional parameter after the comma performs a postincrement of the Rb register. For example, ld8 r1 = [r2], 8 loads a 64-bit value from the address in r2 and then increments the r2 register by 8.

An optional .nt# completer spcifies that the memory will not be accessed again for a while. Higher values of # indicate longer-term abandonment. (.nta is the most aggressive level.)

* | stx | [Ra] = Rb | store to memory
* | stx | [Ra] = Rb, imm9 | store with postincrement

Again, an optional parameter after the comma performs a postincrement of the address register.

* | ldff | Ra = [Rb] | load from memory (zero-extended)
* | ldff | Ra = [Rb], Rc/imm9 | load with postincrement
* | stff | [Ra] = Rb | store to memory
* | stff | [Ra] = Rb, imm9 | store with postincrement

And again for floating point registers.

Memory Access (Advanced/Speculated)

ldx.s | Ra = [Rb] | load speculated
ldx.a | Ra = [Rb] | load advanced
ldx.sa | Ra = [Rb] | load speculated advanced

These were previously discussed.

st.spill... | [Rb] = Ra | save a speculated value
ld.fill... | Ra = [Rb] | restore a speculated value

Read and write a value that might have the NaT bit set. The numerical value is written as usual, and the NaT bit is saved/restored in the ar.unat special register. These allow you to speculate across procedure calls.

lfetch... ... cache line prefetch

Verifying Speculated/Advanced Instructions

ldx.c.clr | Ra = [Rb] | check (or reload) and clear
ldx.c.nc | Ra = [Rb] | check (or reload), no clear
chk.a.clr | Ra = [Rb] | check (or jump) and clear
chk.a.nc | Ra = [Rb] | check (or jump), no clear

Clearing an advanced load means that you have no plans to check the load again.

Special Registers

mov | Ra = S | read from special register
mov | S = Ra | write to special register

Special registers, in general, can only be read from and written to. They do not take part in arithmetic computations and cannot be compared against directly.

mov pr = Ra, mask write to predicate registers

The mask specifies which predicate registers should be loaded from register Ra. The bottom bit of the mask corresponds to predicate register p1, through bit 14 of the mask corresponding to predicate register p15. Bit 15 of the mask represents all the predicate registers p16 through p63. (Recall that predicate register zero is hard-wired to TRUE.)

Recall that the predicate register preservation rules are established by convention, so the only masks are likely to see are -1 (restore all registers) and 0x801F (preserve all the usual registers).

Interlocked Instructions

xchgx... Ra = [Rb], Rc interlocked exchange

Store Rc to [Rb] and return the original value in Ra.

cmpxchgx... Ra = [Rb], Rc, ar.ccv conditional exchange

Check if the value in [Rb] is equal to the special ar.ccv register. If so, store Rc to [Rb]; otherwise, leave it unchanged. In either case, return the original value of [Rb] in Ra.

fetchaddx... Ra = [Rb], Rc/n interlocked add

Atomically adds Rc/n to [Rb], returning the previous value in Ra.

Control Flow

* | br.cond... | Ba/addr | branch
* | br.call... | Ba/addr | call
* | br.ret... | Ba/addr | return

See Control Flow section in The IA-64 Architecture for a description of the various completers.

There are other types of branch instructions as well, but they aren't used as much.

Arithmetic

* | add | Ra = Rb,Rc | Ra = Rb + Rc
* | add | Ra = Rb,Rc,1 | Ra = Rb + Rc + 1
* | adds | Ra = imm14,Rb | Ra = imm14 + Rb
* | addl | Ra = imm22,Rb | Ra = imm22 + Rb
* | subx | Ra = Rb/n,Rc | Ra = Rb/n - Rc
* | subx | Ra = Rb,Rc,1 | Ra = Rb - Rc - 1

shladd Ra = Rb,n,Rc Ra = (Rb SHL n) + Rc

This shifts the first addend left by up to four positions before adding.

Note There is no integer divide or multiply. See Multiplication subsection in this section for a workaround for multiplication. For division, you'll just have to convert to floating point.

Multiplication

There is a special floating point format for handling integer multiplication.

* | setf.sig | Fa = Rb | Fa = Rb (special form)
* | getf.sig | Ra = Fb | Ra = Fb (special form)
* | xma... | Fa = Fb, Fc, Fd | Fa = Fb * Fc + Fd (special form)

The setf.sig and getf.sig instructions transfer between integer registers and floating point registers (in the special form).

The xma instruction performs the operation on numbers in special form, and the result is also in special form.

There are four variations on the xma instruction. The .l version saves the low 64 bits of the result, the .h version saves the high 64 bits of the result, and the .u version performs an unsigned multiplication rather than a signed multiplication.

For example, xma.lu performs the multiplication as two unsigned integers and saves the low 64 bits of the result.

Bits

* | and | Ra = Rb/imm8,Rc | Ra = Rb/imm8 and Rc
* | or | Ra = Rb/imm8,Rc | Ra = Rb/imm8 or Rc
* | andcm | Ra = Rb/imm8,Rc | Ra = Rb/imm8 and not Rc
* | xor | Ra = Rb/imm8,Rc | Ra = Rb/imm8 xor Rc

The andcm instruction clears the bits specified by the last parameter.

* | shl | Ra = Rb,Rc/n | Ra = Rb SHL Rc/n
* | shr | Ra = Rb,Rc/n | Ra = Rb SAR Rc/n
* | shr.u | Ra = Rb,Rc/n | Ra = Rb SHR Rc/n

The sh x instructions do shifting. A more general form of shifting is performed by the extr and dep instructions.

* | extr | Ra = Rb, n1, n2 | Ra = Rb<n1, n2>
* | extr.u | Ra = Rb, n1, n2 | Ra = Rb<n1, n2>

The regular version of the extr (extract) instruction sign-extends the result, whereas the extr.u form zero-extends the result. The bit extraction instructions are also used to handle unaligned data.

* | dep | Ra = Rb, Rc, n1, n2 | Ra<n1, n2> = Rb;
 |  |  | other bits come from Rc

The dep (deposit) instruction builds its output by taking the <n1, n2> part from Rb and the rest of Rc. Think of it as a masked blt.

* shrp Ra = Rb, Rc, n Ra = (Rb:Rc)<n, 64>

The shrp (shift right pair) instruction treats Rb and Rc as a huge 128-bit value and extracts 64 bits of it into the Ra register.

Constants

* movl Ra = n Load 64-bit number

Small numbers (up to 22 bits) can be loaded using add Ra = n, r0 instruction. Larger numbers require the movl instruction. This is one of the few instructions that take up two slots.

Comparisons

* | cmp.cc | p1, p2 = Ra, Rb | compare 64-bit values
* | cmp4.cc | p1, p2 = Ra, Rb | compare 32-bit values

See Comparisons section in The IA-64 Architecture for a detailed explanation.

* tbit p1, p2 = Ra, n test bit

The tbit instruction tests bit n in register Ra, setting both p1 and p2 accordingly.

Bit and Bytes

popcnt | Ra = Rb | Ra = number of set bits in Rb
czx1.l | Ra = Rb | Ra = position of lowest zero byte
czx2.l | Ra = Rb | Ra = position of lowest zero word
czx1.r | Ra = Rb | Ra = position of highest zero byte
czx2.r | Ra = Rb | Ra = position of highest zero word

If there is no zero byte or word, the czx instruction sets the Ra register to 8 (czx1) or 4 (czx2).

Conversion

* | sxtx | Ra = Rb | sign-extend Rb to Ra
* | zxtx | Ra = Rb | zero-extend Rb to Ra

Idioms

* | add | Ra = r0, n | mov Ra = n
* | add | Ra = r0, Rb | mov Ra = Rb
* | add | Ra = Rb, r0, 1 | inc Ra = Rb
* | sub | Ra = Rb, r0, 1 | dec Ra = Rb
* | subx | Ra = r0, Rb | negx Ra = Rb
* | xor | Ra = -1, Rb | not Ra = Rb
 | shrp | Ra = Rb, Rb, n | rotl Ra = Rb, n

You can rotate by doing a paired shift where the two input registers are the same.


Annotated IA-64 Disassembly

The Source Code

The following is the code for the function that will be analyzed.

HRESULT CUserView::CloseView(void)
{
    if (m_fDestroyed) return S_OK;

    BOOL fViewObjectChanged = FALSE;
    ReleaseAndNull(&m_pdtgt);

    if (m_psv) {
        m_psb->EnableModelessSB(FALSE);
        if (m_pws) m_pws->ViewReleased();

        IShellView* psv;

        HWND hwndCapture = GetCapture();
        if (hwndCapture && hwndCapture == m_hwnd) {
            SendMessage(m_hwnd, WM_CANCELMODE, 0, 0);
        }

        m_fHandsOff = TRUE;
        m_fRecursing = TRUE;
        NotifyClients(m_psv, NOTIFY_CLOSING);
        m_fRecursing = FALSE;

        m_psv->UIActivate(SVUIA_DEACTIVATE);

        psv = m_psv;
        m_psv = NULL;

        ReleaseAndNull(&_pctView);

        if (m_pvo) {
            IAdviseSink *pSink;
            if (SUCCEEDED(m_pvo->GetAdvise(NULL, NULL, &pSink)) && pSink) {
                if (pSink == (IAdviseSink *)this)
                    m_pvo->SetAdvise(0, 0, NULL);
                pSink->Release();
            }

            fViewObjectChanged = TRUE;
            ReleaseAndNull(&m_pvo);
        }

        if (psv) {
            psv->SaveViewState();
            psv->DestroyViewWindow();
            psv->Release();
        }

        m_hwndView = NULL;
        m_fHandsOff = FALSE;

        if (m_pcache) {
            GlobalFree(m_pcache);
            m_pcache = NULL;
        }

        m_psb->EnableModelessSB(TRUE);

        CancelPendingActions();
    }

    ReleaseAndNull(&_psf);

    if (fViewObjectChanged)
        NotifyViewClients(DVASPECT_CONTENT, -1);

    if (m_pszTitle) {
        LocalFree(m_pszTitle);
        m_pszTitle = NULL;
    }

    SetRect(&m_rcBounds, 0, 0, 0, 0);
    return S_OK;
}

The Assembly Code

This section contains the annotated disassembly.

HRESULT CUserView::CloseView(void)

On entry to a function, the parameters are passed in registers r32 through r39. Remember that for C++ functions, the first parameter is the secret "this" pointer. Therefore, on entry to CUserView::CloseView, the registers are

r32 = this
br = return address

Parameters are passed in r32 through r39.

The br variable contains the function return address.

The IA-64 separates its registers into several categories. The ones you will see most are r (regular integer registers), b (branch registers, used for branching), and p (predicate registers, which can hold the value TRUE or FALSE).

It so happens that CloseView is a method on ViewState, which is at offset 40 in the underlying object. This method will be referred to as "this," although when there is possible confusion with another base class, it will be more carefully specified as "(ViewState*)this".

sample!.CUserView__CloseView:

Notice that the symbol name is preceded by a dot. Recall that function pointers on the IA-64 are not pointers to code. Instead, they point to a descriptor block (Intel calls it the PLABEL), which contains information about the function (including the address of its first instruction). The symbol without a leading dot represents the function descriptor. The symbol with a leading dot is the first line of code.

{
717796c0   {          alloc    r39 = ar.pfs, 0ah, 00h, 05h, 00h
717796c4              mov      r40 = pr

The alloc instruction builds a stack frame. In this case, the stack framehasthe local region with ten (0ah) registers and it needs five output registers. Recall that in disassembly, the input registers and local registers are combined to form the local region. Since you know that you have only one parameter ("this"), there must be nine local registers.

Every function begins with an alloc instruction.

Since you have a total of ten registers in your local region, and the local region begins with register r32, the local region registers must be r32 through r41, leaving r42 through r46 as the five output registers.

The second instruction saves the predicate registers (pr) into register r40. This allows the predicate registers to be restored before the function returns.

    if (m_fDestroyed) return S_OK;
717796c8              adds     r31 = 0180h, r32          }// r31 = &this->m_fDestroyed

This is equivalent to "r31 = 0180h + r32". The adds instruction adds a small integer to a register. There is a corresponding addl instruction that adds a large integer, but it can only add to registers r0, gp, r2, and r3.

Arithmetic operations are of the form "op dst = src, src, src".

Before proceeding with the computations, you need to finish the function prologue.

717796d0   {          adds     sp = -32, sp ;;    // local stack space
717796d4              ld8.nta  r3 = [sp]          // stack probe
717796d8              mov      r38 = rp       } // save return address
717796e0   {          or       r41 = gp, r0 ;;    // save gp

Notice that the integer argument to the adds sp instruction is disassembled in decimal rather than hexadecimal. However, the debugger default is to assume hexadecimal for all inputs, so the command ?sp-32 will normally display as "sp-0x32". You can use the N (Set Number Base) command to change the default radix to 10. (The default radix can be overridden with the "0x" hexadecimal prefix or the "0n" decimal prefix.)

The next adds instruction allocates some space on the stack. It is followed by a load instruction that looks a little unusual.

The ld instruction loads a register from memory.

The "nta" suffix means "this memory location will not be accessed for a long time" and is a hint to the processor to allow it to optimize its L2 cache better. The only place you'll see it in regular code is at the top of a function to perform a stack probe.

The third instruction saves the return address into register r38 so you know where to go when this function is finished.

The fourth instruction says, "r41 = gp | r0".

The r0 register is hard-wired to the value zero.

Therefore, ORing something with zero and storing the result is the same as copying the value.

"or dest = src, r0" copies a register.

The gp register, by convention, always points to the current module's global variables.

Since you are calling functions that might belong to other DLLs, you need to save the gp register so you can access your global variables after calling those functions. This will require the gp register to point to their global variables.

717796e4              ld4      r31 = [r31]       // r31 = m_fDestroyed
717796e8              nop.i    00h ;;            }

The ld4 instruction is another memory fetch, but this time you load only 32 bits (4 bytes) from memory instead of a full 64 bits.

The ld4 instruction zero-extends the loaded value to 64 bits.

The next instruction is a NOP. The suffix indicates that this is actually an integer NOP However, this is not important, because the instructionl does nothing.

717796f0   {          cmp4.eq  p14, p15 = r0, r31         // if m_fDestroyed
717796f4              nop.f    00h
717796f8     (p15)    br.cond.dpnt.few  $+07c0h ;;       }// jump if not to ReturnSOK

The cmp4.eq instruction compares the bottom 32 bits of the two registers r0 and r31. The result of the comparison is saved into the p14 register, and the opposite result is saved to p15.

The cmp instruction compares two registers. The result of the comparison is saved in the first destination register; the opposite is saved in the second destination register.

The cmp4.eq instruction compares the r31 register (which you just loaded) with r0 (which is zero). If the registers are equal, then p14 is set to TRUE; otherwise, p14 is set to FALSE. The p15 register is set to the opposite of p14 (that is, FALSE or TRUE, respectively).

After another NOP, check the result of the comparison.

A parenthesized register in the left margin indicates that the instruction is executed only if that register is TRUE.

In this case, you execute the branch instruction only if the p15 register is TRUE, which happens when the previous comparison is FALSE, since p15 was the second destination of the comparison.

The suffixes on the br.cond instruction are hints to the processor for optimization and do not affect the execution semantics.

The target of the branch instruction isn't quite right. The target is disassembled as $+07c0h, but the actual target address is 07b8h bytes away. That's because the branch target is computed relative to the beginning of the instruction bundle; that is, relative to the preceding open brace. So when you're disassembling through code, trying to follow the flow of the code, be careful how you compute your jump targets.

Jump instructions are relative to the start of the bundle, not to the start of the instruction.

Now you get to see how that gp register gets used. The compiler has interleaved some instructions for performance, so the next thing it does is actually the first steps of calling an imported function.

    ReleaseAndNull(&m_pdtgt);
71779700   {          addl     r31 = -2025856, gp         // r31 = &__imp__ReleaseAndNull
71779704              adds     r42 = 0198h, r32           // r42 = &this->m_pdtgt

Since the gp register points to your global variables, the addl instruction against the gp register is computing the address of a global variable. In this case, it's the import table entry for the ReleaseAndNull function.

As you computed at the beginning of the function, the output registers start at r42, and here you see the first output register being loaded with the address of the m_pdtgt member, which is the first (and in this case, the only) parameter of ReleaseAndNull.

    if (m_psv)
71779708              adds     r33 = 0110h, r32          }// r33 = &this->m_psv

The compiler is being even more aggressive and has started emitting instructions for the line two ahead of where you are.

    BOOL fViewObjectChanged = FALSE;
71779710   {          or       r37 = r0, r0 ;;             ; r37 = 0

The compiler chose to use the r37 register to represent the local variable fViewObjectChanged. Since the r0 register is hard-wired to zero, the OR instruction zeros out the r37 register.

    ReleaseAndNull(&m_pdtgt);
71779714              ld8      r31 = [r31]                // r31 = &ReleaseAndNull
71779718              nop.i    00h ;;                    }
71779720   {          ld8      r30 = [r31], 08h ;;        // r30 = .ReleaseAndNull
71779724              ld8      gp = [r31]                 // gp  = gp.ReleaseAndNull
71779728              mov      b6 = r30, $+0x0           }// b6  = .ReleaseAndNull
71779730   {          nop.m    00h
71779734              nop.f    00h
71779738              br.call.dptk.many  rp = b6 ;;      }// call .ReleaseAndNull

Here is the remainder of the function call. Recall that a function pointer is really a pointer to a descriptor. So after getting the address of the descriptor, you read the actual code address and the gp of the target function.

The following diagram outlines this concept.

__imp__Function    Function            .Function
+--------------+   +---------------+   +-----------------------+
| Function    ---> | code pointer ---> | code...               |
+--------------+   +---------------+   |                       |
                   | gp            |   |                       |
                   +---------------+   |                       |

Remember, a function name without a period in front of it refers to the function descriptor. The function with a period represents the first line of code.

"ld dest = [src], n" is a post-incremented load.

In this case, "ld8 r30 = [r31], 08h" means "load the r30 register from the 8 bytes pointed to by r31, and then increment r31 by 8."

After you load the code address into r30, you move it into the b6 register so you can branch to it. You cannot move from memory directly into a branch register; you have to go through a regular integer register.

Finally, execute a br.call instruction to call the target function. (Again, the other suffixes are optimization hints.)

You will see this pattern repeatedly; it is the template for calling an imported function.

To call an imported function

  1. Load the address of the import table
  2. Load from the import table to get the descriptor
  3. Load the code address from the descriptor, with postincrement +8
  4. Load the gp register from the descriptor
  5. Move the code address into a branch register
  6. Call through the branch register
    if (m_psv)
71779740   {          ld8      r29 = [r33]                // r29 = m_psv
71779744              or       gp = r41, r0 ;;            // restore gp
71779748              cmp.eq   p14, p15 = r0, r29        }// m_psv == 0?
71779750   {          nop.m    00h
71779754              nop.f    00h
71779758     (p14)    br.cond.dpnt.few  $+0620h ;;       }// Y: jump to NoPSV

After control returns, dereference the r33 register, which you set up before calling ReleaseAndNull. The processor automatically preserves the local region across calls, so the r33 register still contains the value you set up earlier.

After returning from theimported function call, restore the gp register to point to your own global registers so you can access them once again. (Though theoretically this often isn't necessary because you don't access any global variables before the next call that trashes it anyway.)

The following is again a comparison followed by a predicated branch instruction. You check if the value you loaded is zero and branch it if so.

        m_psb->EnableModelessSB(FALSE);
71779760   {          adds     r36 = 0a0h, r32            // r36 = &this->m_psb
71779764              addl     r43 = 00h, r0              // r43 = 0
71779768              nop.b    00h ;;                    }
71779770   {          ld8      r42 = [r36] ;;             // r42 = this->m_psb
71779774              ld8      r31 = [r42]                // r31 = this->m_psb.vtbl
71779778              nop.i    00h ;;                    }
71779780   {          adds     r31 = 048h, r31 ;;         // r31 = &vtbl.EnableModelessSB
71779784              ld8      r30 = [r31]                // r30 = &EnableModelessSB
71779788              nop.i    00h ;;                    }
71779790   {          ld8      r29 = [r30], 08h ;;        // r29 = .EnableModelessSB
71779794              ld8      gp = [r30]                 // gp  = gp.EnableModelessSB
71779798              mov      b6 = r29, $+0x0           }// b6  = .EnableModelessSB
717797a0   {          nop.m    00h
717797a4              nop.f    00h
717797a8              br.call.dptk.many  rp = b6 ;;      }// call .EnableModelessSB

Now you get to see how a virtual C++ method call gets compiled. As before, registers r42 and r43 receive the parameters to the function.

This time, instead of getting the function pointer from your gp, you load the vtbl out of m_psb, step forward to the method you want to call, then set up for another function call.

The following diagram outlines this process.

object      object vtbl
+-------+   +-----------------+
| vtbl ---> | QueryInterface  |
+-------+   +-----------------+
| ...   |   | AddRef          |
            +-----------------+
            | Release         |
            +-----------------+
            | ...             |   EnableModeless      .EnableModeless
            +-----------------+   +---------------+   +-----------------------+
            | EnableModeless ---> | code pointer ---> | code...               |
            +-----------------+   +---------------+   |                       |
            | ...             |   | gp            |   |                       |
                                  +---------------+   |                       |

The following is a pattern you should recognize.

How to compile a virtual C++ method

  1. Load the object into an output register
  2. Load the vtbl from the object
  3. Add to the vtbl to get to the function you want to call
  4. Load from the vtbl to get the descriptor
  5. Load the code address from the descriptor, with postincrement +8
  6. Load the gp register from the descriptor
  7. Move the code address into a branch register
  8. Call through the branch register
        if (m_pws) m_pws->ViewReleased();
717797b0   {          adds     r28 = 0228h, r32           // r28 = &this->m_pws
717797b4              or       gp = r41, r0               // restore gp after call
717797b8              nop.b    00h ;;                    }
717797c0   {          ld8      r42 = [r28] ;;             // r42 = this->m_pws
717797c4              cmp.eq   p14, p15 = r0, r42         // equal to zero?
717797c8              nop.i    00h                       }
717797d0   {          nop.m    00h
717797d4              nop.f    00h
717797d8     (p14)    br.cond.dpnt.few  $+050h ;;        }// Y: Jump to NoWS
717797e0   {          ld8      r31 = [r42] ;;             // r31 = this->m_pws.vtbl
717797e4              adds     r31 = 018h, r31            // r31 = &vtbl.ViewReleased
717797e8              nop.i    00h ;;                    }
717797f0   {          ld8      r30 = [r31] ;;             // r30 = &ViewReleased
717797f4              ld8      r29 = [r30], 08h           // r29 = .ViewReleased
717797f8              nop.i    00h ;;                    }
71779800   {          ld8      gp = [r30]                 // gp  = gp.ViewReleased
71779804              mov      b6 = r29, $+0x0            // b6  = ViewReleased
71779808              br.call.dptk.many  rp = b6 ;;      }// call  .ViewReleased
71779810   {          or       gp = r41, r0               // restore gp after call
71779814              nop.f    00h
71779818              nop.b    00h ;;                    }
NoWS:

Now you already know enough to read this entire code sequence. Another variable test, conditional jump, and method call.

        HWND hwndCapture = GetCapture();
71779820   {          addl     r31 = -2024992, gp ;;      // r31 = &__imp__GetCapture
71779824              ld8      r30 = [r31]                // r30 = &GetCapture
71779828              nop.i    00h ;;                    }
71779830   {          ld8      r29 = [r30], 08h ;;        // r29 = .GetCapture
71779834              ld8      gp = [r30]                 // gp  = gp.GetCapture
71779838              mov      b6 = r29, $+0x0           }// b6  = .GetCapture
71779840   {          nop.m    00h
71779844              nop.f    00h
71779848              br.call.dptk.many  rp = b6 ;;      }// call .GetCapture
71779850   {          or       gp = r41, r0               // restore gp after call

Again, a pattern you already recognize, this time a call to an imported function.

        if (hwndCapture && hwndCapture == m_hwnd) {
71779854              cmp.eq   p14, p15 = r0, ret0        // hwndCapture == NULL?
71779858     (p14)    br.cond.dpnt.few  $+080h ;;        }// Y: Jump to NoCapture
71779860   {          adds     r31 = 0b8h, r32 ;;         // r31 = &this->m_hwnd
71779864              ld8      r42 = [r31]                // r42 = this->m_hwnd
71779868              nop.i    00h ;;                    }
71779870   {          cmp.eq   p15, p14 = ret0, r42       // hwndCapture == this->m_hwnd?
71779874              nop.f    00h
71779878     (p14)    br.cond.dptk.few  $+060h ;;        }// Y: Jump to NoCapture

Functions return their value in the ret0 register.

Check if hwndCapture is NULL or equal to m_hwnd and jump if either condition is met.

            SendMessage(m_hwnd, WM_CANCELMODE, 0, 0);
        }
71779880   {          addl     r31 = -2025920, gp         // r31 = &__imp__SendMessage
71779884              addl     r45 = 00h, r0              // r45 = 0 (lParam)
71779888              addl     r44 = 00h, r0             }// r44 = 0 (wParam)
71779890   {          addl     r43 = 01fh, r0 ;;          // r43 = WM_CANCELMODE (uMsg)
71779894              ld8      r30 = [r31]                // r30 = &SendMessage
71779898              nop.i    00h ;;                    }
717798a0   {          ld8      r29 = [r30], 08h ;;        // r29 = .SendMessage
717798a4              ld8      gp = [r30]                 // gp  = gp.SendMessage
717798a8              mov      b6 = r29, $+0x0           }// b6  = .SendMessage
717798b0   {          nop.m    00h
717798b4              nop.f    00h
717798b8              br.call.dptk.many  rp = b6 ;;      }// call .SendMessage
717798c0   {          or       gp = r41, r0               // restore gp after call
717798c4              nop.f    00h
717798c8              nop.b    00h                       }
NoCapture:

This time, you have to call a function that takes four parameters, so you fill the output registers r42 through r45 with the parameters. Note that you set up r42 ahead of time while you were still deciding whether or not to call SendMessage.

        m_fHandsOff = TRUE;
        m_fRecursing = TRUE;
        NotifyClients(m_psv, NOTIFY_CLOSING);
717798d0   {          ld8      r43 = [r33]                // r43 = m_psv
717798d4              adds     r42 = 040h, r32            // r42 = (CNotifySource*)this
717798d8              adds     r35 = 0218h, r32          }// r35 = &this->bitfield
717798e0   {          addl     r31 = 08001h, r0 ;;        // r31 = 0x8001
717798e4              addl     r44 = 04h, r0              // r44 = 4
717798e8              nop.i    00h ;;                    }
717798f0   {          ld8      r29 = [r42]                // r29 = (CNotifySource*)this->vtbl
717798f4              ld4      r30 = [r35]                // r30 = bitfield
717798f8              nop.b    00h ;;                    }
71779900   {          or       r31 = r31, r30 ;;          // set the two bits in r30
71779904              st4      [r35] = r31                // store the result

Now you get to see how bitfields get compiled, with some instructions from the upcoming method call interleaved. Recall that you set up the r33 register to point to the m_psv member, so all you have to do is dereference it to fetch the value.

The other instructions prepare for the method call by setting up the output registers (r42 through r44) and loading the vtbl of m_psv.

Meanwhile, the two bits in the bitfield are set by loading the full bitfield, ORing the values, then storing the result.

        NotifyClients(m_psv, NOTIFY_CLOSING);
71779908              adds     r29 = 018h, r29 ;;        }// r29 = &vtbl.NotifyClients
71779910   {          ld8      r30 = [r29] ;;             // r30 = NotifyClients
71779914              ld8      r31 = [r30], 08h           // r31 = .NotifyClients
71779918              nop.i    00h ;;                    }
71779920   {          ld8      gp = [r30]                 // gp  = gp.NotifyClients
71779924              mov      b6 = r31, $+0x0            // b6  = .NotifyClients
71779928              br.call.dptk.many  rp = b6 ;;      }// call .NotifyClients

Here's the rest of the method call.

        m_fRecursing = FALSE;
71779930   {          ld4      r28 = [r35]                // r28 = bitfield
71779934              ld8      r42 = [r33]                // r42 = m_psv
71779938              addl     r29 = -32769, r0 ;;       }// r29 = ~0x8000
71779940   {          and      r29 = r29, r28             // r29 = bitfield & ~0x8000
71779944              or       gp = r41, r0               // restore gp after call
71779948              addl     r43 = 00h, r0 ;;          }// r43 = 0 (SVUIA_DEACTIVATE)
71779950   {          st4      [r35] = r29                // store updated bitfield

This is how to clear a bit in a bitfield.

        m_psv->UIActivate(SVUIA_DEACTIVATE);
71779954              ld8      r31 = [r42]                // r31 = m_psv.vtbl
71779958              nop.b    00h ;;                    }
71779960   {          adds     r31 = 038h, r31 ;;         // r31 = &vtbl.UIActivate
71779964              ld8      r30 = [r31]                // r30 = &UIActivate
71779968              nop.i    00h ;;                    }
71779970   {          ld8      r29 = [r30], 08h ;;        // r29 = .UIActivate
71779974              ld8      gp = [r30]                 // gp  = gp.UIActivate
71779978              mov      b6 = r29, $+0x0           }// b6  = .UIActivate
71779980   {          nop.m    00h
71779984              nop.f    00h
71779988              br.call.dptk.many  rp = b6 ;;      }// call .UIActivate

These method calls are becoming routine.

        psv = m_psv;
        m_psv = NULL;
        ReleaseAndNull(&_pctView);
71779990   {          ld8      r34 = [r33]                // r34 (psv) = m_psv
71779994              or       gp = r41, r0               // restore gp after call
71779998              adds     r42 = 0100h, r32          }// r42 = &this->_bbt._pctView
717799a0   {          st8      [r33] = r0 ;;              // m_psv = 0
717799a4              addl     r31 = -2025856, gp         // r31 = &__imp__ReleaseAndNull
717799a8              nop.i    00h ;;                    }
717799b0   {          ld8      r30 = [r31] ;;             // r30 = &ReleaseAndNull
717799b4              ld8      r29 = [r30], 08h           // r29 = .ReleaseAndNull
717799b8              nop.i    00h ;;                    }
717799c0   {          ld8      gp = [r30]                 // gp  = gp.ReleaseAndNull
717799c4              mov      b6 = r29, $+0x0            // b6  = .ReleaseAndNull
717799c8              br.call.dptk.many  rp = b6 ;;      }// call .ReleaseAndNull

Another method call, with some variable shuffling in it.

        if (m_pvo) {
717799d0   {          adds     r33 = 0178h, r32           // r33 = &this->m_pvo
717799d4              or       gp = r41, r0               // restore gp after call
717799d8              nop.b    00h ;;                    }
717799e0   {          ld8      r42 = [r33] ;;             // r42 = this->m_pvo
717799e4              cmp.eq   p14, p15 = r0, r42         // m_pvo == NULL?
717799e8              nop.i    00h                       }
717799f0   {          nop.m    00h
717799f4              nop.f    00h
717799f8     (p14)    br.cond.dpnt.few  $+01a0h ;;       }// Y: Jump to NoPVO

Just checking a variable, nothing special.

            IAdviseSink *pSink;
            if (SUCCEEDED(m_pvo->GetAdvise(NULL, NULL, &pSink)) ...
71779a00   {          ld8      r31 = [r42]                // r31 = this->m_pvo->vtbl
71779a04              adds     r45 = 010h, sp             // r45 = &pSink
71779a08              addl     r44 = 00h, r0             }// r44 = NULL
71779a10   {          addl     r43 = 00h, r0 ;;           // r43 = NULL
71779a14              adds     r37 = 010h, sp             // r37 = &pSink
71779a18              nop.i    00h ;;                    }
71779a20   {          adds     r31 = 040h, r31 ;;         // r31 = &vtbl.GetAdvise
71779a24              ld8      r30 = [r31]                // r30 = &GetAdvise
71779a28              nop.i    00h ;;                    }
71779a30   {          ld8      r29 = [r30], 08h ;;        // r29 = .GetAdvise
71779a34              ld8      gp = [r30]                 // gp  = gp.GetAdvise
71779a38              mov      b6 = r29, $+0x0           }// b6  = .GetAdvise
71779a40   {          nop.m    00h
71779a44              nop.f    00h
71779a48              br.call.dptk.many  rp = b6 ;;      }// call .GetAdvise

You call the GetAdvise method, and check the return value.

            if (SUCCEEDED(...) && pSink) {
71779a50   {          ld8      r42 = [r37]                // r42 = pSink
71779a54              cmp4.eq  p14, p15 = 01h, r0         // p14 = FALSE, p15 = TRUE
71779a58              or       gp = r41, r0 ;;           }// restore gp after call
71779a60   {          cmp4.gt.or.andcm  p14, p15 = r0, ret0 // if (0 > ret0) { p14 = TRUE; p15 = FALSE }
71779a64              cmp.eq.or.andcm  p14, p15 = r0, r42 // if (0 == pSink) { p14 = TRUE; p15 = FALSE }
71779a68     (p14)    br.cond.dpnt.few  $+0f0h ;;        }// if FAILED or NULL, jump to NoSink

Now you get to see the odd conditional instructions in action.

The first comparison instruction seems pointless. Why compare one against zero? So you can initialize the predicate registers p14 to FALSE and p15 to TRUE.

The next two comparison instructions execute in parallel. The first one checks if 0 > ret0; that is, if the return value is negative. The next two suffixes say that the result is ORed into the first destination and complemented and ANDed (andcm) with the second destination.

After doing the combination testing, you jump if p14 is TRUE, which happens if one of the combination tests was true.

There are two interesting things to note about this sequence. First, the two combination comparisons were executed in parallel. (Notice that they execute as part of the same instruction group.) Second, you only executed a single conditional jump. What's more, that conditional jump was part of the same instruction group, so it all executes in a single cycle.

A traditional CPU would've had to test the return value, jump conditionally, then test pSink, and jump conditionally again.Those four operations are dependent on each other, so it would take four cycles to perform the combination test instead of the one cycle that the IA-64 required.

                if (pSink == (IAdviseSink *)this)
71779a70   {          adds     r31 = -40, r32 ;;          // r31 = (CUserView*)this
71779a74              cmp.eq   p14, p15 = r0, r31         // r31 == NULL?
71779a78              adds     r31 = 028h, r32           }// r31 = (IAdviseSink*)this
71779a80   {          nop.m    00h
71779a84              nop.f    00h
71779a88     (p15)    br.cond.dpnt.few  $+020h ;;        }// N: Jump to NotNULL
71779a90   {          or       r31 = r0, r0               // r31 = NULL
71779a94              nop.f    00h
71779a98              nop.b    00h ;;                    }
NotNULL:

This is a quirk of the C++ spec, namely that if p is a NULL pointer, then (T*)p must be equal to NULL for all types T. This means that changing from one base class to another requires the compiler to stick in special checks for NULL.

At the end of this sequence, the r31 register contains the result of the cast (IAdviseSink*) this.

                if (pSink == (IAdviseSink *)this)
                    m_pvo->SetAdvise(0, 0, NULL);
71779aa0   {          cmp.eq   p15, p14 = r42, r31        // r31 == pSink?
71779aa4              nop.f    00h
71779aa8     (p14)    br.cond.dptk.few  $+070h ;;        }// N: Jump to NotSameSink
71779ab0   {          ld8      r42 = [r33]                // r42 = this->m_pvo
71779ab4              addl     r45 = 00h, r0              // r45 = 0
71779ab8              addl     r44 = 00h, r0             }// r44 = 0
71779ac0   {          addl     r43 = 00h, r0 ;;           // r43 = NULL
71779ac4              ld8      r31 = [r42]                // r31 = this->m_pvo->vtbl
71779ac8              nop.i    00h ;;                    }
71779ad0   {          adds     r31 = 038h, r31 ;;         // r31 = &vtbl.SetAdvise
71779ad4              ld8      r30 = [r31]                // r30 = SetAdvise
71779ad8              nop.i    00h ;;                    }
71779ae0   {          ld8      r29 = [r30], 08h ;;        // r29 = .SetAdvise
71779ae4              ld8      gp = [r30]                 // gp  = gp.SetAdvise
71779ae8              mov      b6 = r29, $+0x0           }// b6  = .SetAdvise
71779af0   {          nop.m    00h
71779af4              nop.f    00h
71779af8              br.call.dptk.many  rp = b6 ;;      }// call .SetAdvise
71779b00   {          ld8      r42 = [r37]                //r42 = pSink (restore register variable)
71779b04              or       gp = r41, r0               // restore gp after call
71779b08              nop.b    00h ;;                    }
NotSameSink:

Notice that the compiler had to reload the r42 register after the call since r42 is an output register, and output registers can be modified across a call. (That's not important in this case, since you also explicitly trashed the r42 register.)

                pSink->Release();
            }
71779b10   {          ld8      r31 = [r42] ;;             // r31 = pSink->vtbl
71779b14              adds     r31 = 010h, r31            // r31 = &vtbl.Release
71779b18              nop.i    00h ;;                    }
71779b20   {          ld8      r30 = [r31] ;;             // r30 = &Release
71779b24              ld8      r29 = [r30], 08h           // r29 = .Release
71779b28              nop.i    00h ;;                    }
71779b30   {          ld8      gp = [r30]                 // gp  = gp.Release
71779b34              mov      b6 = r29, $+0x0            // b6  = .Release
71779b38              br.call.dptk.many  rp = b6 ;;      }// call .Release
71779b40   {          or       gp = r41, r0               // restore gp after call
71779b44              nop.f    00h
71779b48              nop.b    00h ;;                    }
NoSink:

Another method call.

            fViewObjectChanged = TRUE;
            ReleaseAndNull(&m_pvo);
        }
71779b50   {          addl     r31 = -2025856, gp         // r31 = &__imp__ReleaseAndNull
71779b54              or       r42 = r33, r0              // r42 = r33 = &this->m_pvo
71779b58              addl     r37 = 01h, r0 ;;          }// r37 (fViewObjectChanged) = 1 = TRUE
71779b60   {          ld8      r30 = [r31] ;;             // r30 = &ReleaseAndNull
71779b64              ld8      r29 = [r30], 08h           // r29 = .ReleaseAndNull
71779b68              nop.i    00h ;;                    }
71779b70   {          ld8      gp = [r30]                 // gp  = gp.ReleaseAndNull
71779b74              mov      b6 = r29, $+0x0            // b6  = .ReleaseAndNull
71779b78              br.call.dptk.many  rp = b6 ;;      }// call .ReleaseAndNull
71779b80   {          or       gp = r41, r0               // restore gp after call
71779b84              nop.f    00h
71779b88              nop.b    00h                       }

Recall that the fViewObjectChanged local variable is being kept in the r37 register.

        if (psv) {
            psv->SaveViewState();
            psv->DestroyViewWindow();
            psv->Release();
        }
71779b90   {          cmp.eq   p14, p15 = r0, r34         // r34 (psv) == NULL?
71779b94              nop.f    00h
71779b98     (p14)    br.cond.dptk.few  $+0d0h ;;        }// Y: Jump to NoPSV2
71779ba0   {          ld8      r31 = [r34]                // r31 = psv->vtbl
71779ba4              or       r42 = r34, r0 ;;           // r42 = psv
71779ba8              adds     r31 = 068h, r31 ;;        }// r31 = &vtbl.SaveViewState
71779bb0   {          ld8      r30 = [r31] ;;             // r30 = &SaveViewState
71779bb4              ld8      r29 = [r30], 08h           // r29 = .SaveViewState
71779bb8              nop.i    00h ;;                    }
71779bc0   {          ld8      gp = [r30]                 // gp  = gp.SaveViewState
71779bc4              mov      b6 = r29, $+0x0            // b6  = .SaveViewState
71779bc8              br.call.dptk.many  rp = b6 ;;      }// call .SaveViewState

71779bd0   {          ld8      r28 = [r34]                // r28 = psv->vtbl
71779bd4              or       gp = r41, r0               // restore gp after call (pointless)
71779bd8              or       r42 = r34, r0 ;;          }// r42 = psv
71779be0   {          adds     r31 = 050h, r28 ;;         // r31 = &vtbl.DestroyViewWindow
71779be4              ld8      r29 = [r31]                // r29 = &DestroyViewWindow
71779be8              nop.i    00h ;;                    }
71779bf0   {          ld8      r27 = [r29], 08h ;;        // r27 = .DestroyViewWindow
71779bf4              ld8      gp = [r29]                 // gp  = gp.DestroyViewWindow
71779bf8              mov      b6 = r27, $+0x0           }// b6  = .DestroyViewWindow
71779c00   {          nop.m    00h
71779c04              nop.f    00h
71779c08              br.call.dptk.many  rp = b6 ;;      }// call .DestroyViewWindow

71779c10   {          ld8      r30 = [r34]                // r30 = psv->vtbl
71779c14              or       gp = r41, r0               // restore gp after call (pointless)
71779c18              or       r42 = r34, r0 ;;          }// r42 = psv
71779c20   {          adds     r31 = 010h, r30 ;;         // r31 = &vtbl.Release
71779c24              ld8      r28 = [r31]                // r28 = &Release
71779c28              nop.i    00h ;;                    }
71779c30   {          ld8      r29 = [r28], 08h ;;        // r29 = .Release
71779c34              ld8      gp = [r28]                 // gp  = gp.Release
71779c38              mov      b6 = r29, $+0x0           }// b6  = .Release
71779c40   {          nop.m    00h
71779c44              nop.f    00h
71779c48              br.call.dptk.many  rp = b6 ;;      }// call .Release
71779c50   {          or       gp = r41, r0               // restore gp after call
71779c54              nop.f    00h
71779c58              nop.b    00h                       }
NoPSV2:

The restores of gp after the function call are pointless since the next function call is going to destroy it anyway. This is an actual compiler error; its optimizer should've noticed that gp is not read before it is rewritten.

        m_hwndView = NULL;
        m_fHandsOff = FALSE;
71779c60   {          ld4      r30 = [r35]                // r30 = this->bitfield
71779c64              adds     r31 = 0120h, r32           // r31 = &m_hwndView
71779c68              adds     r33 = 0108h, r32 ;;       }// r33 = &m_pcache
71779c70   {          ld8      r42 = [r33]                // r42 = m_pcache
71779c74              st4      [r31] = r0, 04h            // [r31] = NULL, r31 += 4
71779c78              and      r30 = -2, r30 ;;          }// r30 = r30 & ~-2 (clear bit)
71779c80   {          st4      [r31] = r0                 // [r31] = NULL (other half)
71779c84              st4      [r35] = r30                // bitfield = r30

The compiler is making additional errors. It splits the m_hwndView into two parts, storing the NULL two DWORDs at a time instead of as a single 64-bit store. The compiler thinks that the m_hwndView member is unaligned so it has to split the store. But the compiler's loss is your gain: you get to see a postincremented store.

"st [dest] = src, n" is a post-incremented store.

The "and r30 = -2, r30" clears the bottom bit.

        if (m_pcache) {
71779c88              cmp.eq   p14, p15 = r0, r42        }// m_pcache == NULL?
71779c90   {          nop.b    00h
71779c94              nop.b    00h
71779c98     (p14)    br.cond.dpnt.few  $+090h ;;        }// Y: Jump to NoCache

The r42 register was set up while you were clearing bits in the previous block of code.

            GlobalFree(m_pcache);
71779ca0   {          addl     r31 = -2029288, gp ;;      // r31 = &__imp__GlobalFree
71779ca4              ld8      r30 = [r31]                // r30 = &GlobalFree
71779ca8              nop.i    00h ;;                    }
71779cb0   {          ld8      r29 = [r30], 08h ;;        // r29 = .GlobalFree
71779cb4              ld8      gp = [r30]                 // gp  = gp.GlobalFree
71779cb8              mov      b6 = r29, $+0x0           }// b6  = .GlobalFree
71779cc0   {          nop.m    00h
71779cc4              nop.f    00h
71779cc8              br.call.dptk.many  rp = b6 ;;      }// call .GlobalFree

Recall that r42 already contains the value of m_pcache.

            m_pcache = NULL;
        }
71779cd0   {          st1      [r33] = r0, 01h            // [r33] = 0, r33++
71779cd4              or       gp = r41, r0               // restore gp after call
71779cd8              nop.b    00h ;;                    }
71779ce0   {          st1      [r33] = r0, 01h ;;         // [r33] = 0, r33++
71779ce4              st1      [r33] = r0, 01h            // [r33] = 0, r33++
71779ce8              nop.i    00h ;;                    }
71779cf0   {          st1      [r33] = r0, 01h ;;         // [r33] = 0, r33++
71779cf4              st1      [r33] = r0, 01h            // [r33] = 0, r33++
71779cf8              nop.i    00h ;;                    }
71779d00   {          st1      [r33] = r0, 01h ;;         // [r33] = 0, r33++
71779d04              st1      [r33] = r0, 01h            // [r33] = 0, r33++
71779d08              nop.i    00h ;;                    }
71779d10   {          st1      [r33] = r0                 // [r33] = 0
71779d14              nop.f    00h
71779d18              nop.b    00h                       }
NoCache:

More compiler errors. It thinks that m_pcache is unaligned so it has to zero it out by writing eight bytes, one at a time. Nevermind that back at address 71779c70 it had no qualms about loading the value assuming the address was aligned.

        m_psb->EnableModelessSB(TRUE);
71779d20   {          ld8      r42 = [r36]                // r42 = this->m_psb
71779d24              addl     r43 = 01h, r0              // r43 = TRUE
71779d28              nop.b    00h ;;                    }
71779d30   {          ld8      r31 = [r42] ;;             // r31 = this->m_psb.vtbl
71779d34              adds     r31 = 048h, r31            // r31 = &vtl.EnableModeless
71779d38              nop.i    00h ;;                    }
71779d40   {          ld8      r30 = [r31] ;;             // r30 = &EnableModeless
71779d44              ld8      r29 = [r30], 08h           // r29 = .EnableModeless
71779d48              nop.i    00h ;;                    }
71779d50   {          ld8      gp = [r30]                 // gp  = gp.EnableModeless
71779d54              mov      b6 = r29, $+0x0            // b6  = .EnableModeless
71779d58              br.call.dptk.many  rp = b6 ;;      }// call .EnableModeless
71779d60   {          or       gp = r41, r0               // restore gp after call
        CancelPendingActions();
    }
71779d64              adds     r42 = -40, r32            // r42 = (CUserView*)this
71779d68              br.call.sptk.many  rp = $-15424 ;;  } // call .CancelPendingActions
NoPSV:

This is a direct call rather than an imported function or a virtual method call. Notice that you didn't have to set up the gp register because CancelPendingActions is not a virtual method, so you know that it resides in your own DLL, and therefore its gp is equal to your gp. It also means that you don't need to restore gp after the call.

    ReleaseAndNull(&_psf);
71779d70   {          addl     r31 = -2025856, gp         // r31 = &__imp__ReleaseAndNull
71779d74              adds     r42 = 0118h, r32           // r42 = &this->_psf
71779d78              nop.b    00h ;;                    }
71779d80   {          ld8      r30 = [r31] ;;             // r30 = &ReleaseAndNull
71779d84              ld8      r29 = [r30], 08h           // r29 = .ReleaseAndNull
71779d88              nop.i    00h ;;                    }
71779d90   {          ld8      gp = [r30]                 // gp  = gp.ReleaseAndNull
71779d94              mov      b6 = r29, $+0x0            // b6  = .ReleaseAndNull
71779d98              br.call.dptk.many  rp = b6 ;;      }// call .ReleaseAndNull
71779da0   {          or       gp = r41, r0               // restore gp after call
    if (fViewObjectChanged)
        NotifyViewClients(DVASPECT_CONTENT, -1);
71779da4              cmp4.eq  p14, p15 = r0, r37         // r36 (fViewObjectChanged) == FALSE?
71779da8     (p14)    br.cond.dpnt.few  $+060h ;;        }// Y: Jump to NoChange
71779db0   {          adds     r42 = -40, r32             // r42 = (CBaseBrowser*)this
71779db4              addl     r44 = -1, r0               // r44 = -1
71779db8              addl     r43 = 01h, r0 ;;          }// r43 = 1 = DVASPECT_CONTENT
71779dc0   {          ld8      r31 = [r42] ;;             // r31 = this.vtbl
71779dc4              adds     r31 = 048h, r31            // r31 = &vtbl.NotifyViewClients
71779dc8              nop.i    00h ;;                    }
71779dd0   {          ld8      r30 = [r31] ;;             // r30 = &NotifyViewClients
71779dd4              ld8      r29 = [r30], 08h           // r29 = .NotifyViewClients
71779dd8              nop.i    00h ;;                    }
71779de0   {          ld8      gp = [r30]                 // gp  = gp.NotifyViewClients
71779de4              mov      b6 = r29, $+0x0            // b6  = .NotifyViewClients
71779de8              br.call.dptk.many  rp = b6 ;;      }// call .NotifyViewClients
71779df0   {          or       gp = r41, r0               // restore gp after call
71779df4              nop.f    00h
71779df8              nop.b    00h                       }
NoChange:
    if (m_pszTitle) {
        LocalFree(m_pszTitle);
        m_pszTitle = NULL;
    }
71779e00   {          adds     r33 = 0128h, r32 ;;        // r33 = &this->m_pszTitle
71779e04              ld8      r42 = [r33]                // r42 = this->m_pszTitle
71779e08              nop.i    00h ;;                    }
71779e10   {          cmp.eq   p14, p15 = r0, r42         // r42 == NULL?
71779e14              nop.f    00h
71779e18     (p14)    br.cond.dpnt.few  $+050h ;;        }// Y: Jump to NoTitle
71779e20   {          addl     r31 = -2029752, gp ;;      // r31 = &__imp__LocalFree
71779e24              ld8      r30 = [r31]                // r30 = &LocalFree
71779e28              nop.i    00h ;;                    }
71779e30   {          ld8      r29 = [r30], 08h ;;        // r29 = .LocalFree
71779e34              ld8      gp = [r30]                 // gp  = gp.LocalFree
71779e38              mov      b6 = r29, $+0x0           }// b6  = .LocalFree
71779e40   {          nop.m    00h
71779e44              nop.f    00h
71779e48              br.call.dptk.many  rp = b6 ;;      }// call .LocalFree
71779e50   {          st8      [r33] = r0                 // this->m_pszTitle = 0
71779e54              or       gp = r41, r0               // restore gp after call
71779e58              nop.b    00h ;;                    }
NoTitle:

Nothing new here.

    SetRect(&m_rcBounds, 0, 0, 0, 0);
71779e60   {          addl     r31 = -2024936, gp         // r31 = &__imp__SetRect
71779e64              addl     r46 = 00h, r0              // r46 = 0
71779e68              addl     r45 = 00h, r0             }// r45 = 0
71779e70   {          addl     r44 = 00h, r0 ;;           // r44 = 0
71779e74              ld8      r30 = [r31]                // r30 = &SetRect
71779e78              addl     r43 = 00h, r0             }// r43 = 0
71779e80   {          adds     r42 = 0208h, r32 ;;        // r42 = &this->m_rcBounds
71779e84              ld8      r29 = [r30], 08h           // r29 = .SetRect
71779e88              nop.i    00h ;;                    }
71779e90   {          ld8      gp = [r30]                 // gp  = gp.SetRect
71779e94              mov      b6 = r29, $+0x0            // b6  = .SetRect
71779e98              br.call.dptk.many  rp = b6 ;;      }// call .SetRect
71779ea0   {          or       gp = r41, r0               // restore gp after call
71779ea4              nop.f    00h
71779ea8              nop.b    00h                       }
    return S_OK;
ReturnSOK:
71779eb0   {          or       ret0 = r0, r0

Finally you get to set the return value.

}
71779eb4              mov      rp = r38, $+0x0            // restore return address
71779eb8              adds     sp = 020h, sp ;;          }// clean up stack
71779ec0   {          nop.m    00h
71779ec4              mov      pr = r40, -2 ;;            // restore predicate registers
71779ec8              mov.i    ar.pfs = r39              }// clean up stack frame
71779ed0   {          nop.m    00h
71779ed4              nop.f    00h
71779ed8              br.ret.sptk.many  rp ;;            }// return to caller

And this is the function epilogue.

You restore the rp register to contain your return address that you saved in the prologue.

You clean up the stack.

You restore the predicate registers.

You restore the original stack frame with the value you stashed into r39 when you created your stack frame.

Finally, you return to your caller through the rp register.


Application Verifier

This section includes:

Introduction to Application Verifier

Application Verifier Options

Beginning an Application Verifier Session

Injecting Faults Into the Application

Reading Application Verifier Logs

Debugging Application Verifier Stops


Introduction to Application Verifier

Application Verifier is a tool for testing user-mode applications. It can monitor their actions, put them through a variety of stresses and tests, and report on possible flaws and errors in their design.

Application Verifier requires a utility named AppVerif.exe. This tool can be used alone or in conjunction with a user-mode debugger.

Application Verifier reports information on the target process in several different ways:

  • By recording information in logs that can be viewed through AppVerif.exe
  • By recording information in logs that can be viewed through the debugger
  • By raising an exception, causing the application to break into the debugger and display information about the exception
  • By issuing an Application Verifier Stop, causing the application to break into the debugger and display a status message

Application Verifier runs on Microsoft® Windows® 2000 SP3 and later, Windows XP, Windows .NET Server 2003, and all later versions of Windows.


Application Verifier Options

Application Verifier has a wide variety of options that can be used to stress and test your application. These options are activated in several different ways, and their output is accessed in several different ways.

The following Application Verifier options are activated through AppVerif.exe. The output from these options is viewed through AppVerif.exe. No debugger is involved unless the "Break in after each logged event" feature is activated:

  • Log potential security issues
  • Log installation of kernel-mode drivers
  • Log calls made to obsolete API functions
  • Log file system changes
  • Log DirectX file checks
  • Log changes to Windows File Protection files
  • Log registry changes
  • Check registry usage
  • Check version handling
  • Log application starts and stops

The following Application Verifier option is activated through AppVerif.exe. If no exception occurs, its output is viewed through AppVerif.exe. If an exception does occur, control will pass to the debugger:

  • Check system path usage

The following Application Verifier options are activated through the AppVerif.exe utility. The output from these options is viewed through the debugger:

  • Check for adequate initial stack commitment
  • Detect invalid handle usage
  • (Windows XP and later) Check lock usage
  • (Windows .NET Server 2003 and later) Remote procedure call checks
  • Full page heap
  • Fast fill heap

    Note In releases of AppVerif.exe prior to version 2.29, Full page heap was called "Detect heap corruptions". The Fast fill heap option had no name; it was automatically active whenever "Detect heap corruptions" was not selected.

The following Application Verifier options are automatically activated whenever you have chosen at least one other option in the AppVerif.exe utility. The output from these options is viewed through the debugger:

  • Log heap operations
  • Log virtual space operations
  • Log exceptions

The following Application Verifier option is activated in two steps. First, use the AppVerif.exe utility to select the target application and activate at least one other option. Second, use the !avrf debugger extension to select the fault injection settings. The output from this option is viewed through the debugger:

  • Injecting faults into the application

Only the final four options listed here are documented in Using Debugging Tools for Windows. For information on the other options, start the AppVerif.exe utility and press the Help button.


Beginning an Application Verifier Session

To use Application Verifier, you must install and run the AppVerif.exe utility. Many of Application Verifier's features also require that you set up a user-mode debugger.

This section includes:

Installing AppVerif.exe

Configuring AppVerif.exe

Setting Up a Debugger for Application Verifier

Running and Debugging the Application


Installing AppVerif.exe

The AppVerif.exe utility is part of the Application Compatibility Toolkit. This kit can be downloaded and installed from http://www.microsoft.com/windows/appexperience/.


Configuring AppVerif.exe

To use Application Verifier with your application, start the AppVerif.exe utility by typing "appverif" into Windows' Run box.

Press the Add button and locate your application's executable file. Double-click on it, or press Open.

Now select the name of your application in the Applications list. The Test settings list will now show you the settings for your application. Select whichever options you wish.

Note The individual Application Verifier options are not documented in Debugging Tools for Windows. Choose the Help button in AppVerif.exe for full documentation of each option.

As soon as a box has been checked or unchecked, Application Verifier will be aware of the changes. You do not have to "save" the changes in any way. You can close the AppVerif.exe utility by clicking on the "X" in the upper-right corner, or you can leave it open — Application Verifier will work the same, either way. When your application is started, the currently-selected Application Verifier settings will be detected, and these settings will be used for the application.

Even if the settings are later changed through AppVerif.exe, the application will "remember" the settings that existed at its launch. If you wish, you can take advantage of this property by launching several instances of your application at different times. They can all run simultaneously, and each can have different Application Verifier settings in effect.

Breaking Into the Debugger After Logged Events

If you select the Options button and choose Break into the debugger after each logged event, you can use the drop-down box to choose a debugger. Choose "WinDbg" if you are using WinDbg as your debugger. Choose "NTSD" if you are using CDB or NTSD as your debugger.


Setting Up a Debugger for Application Verifier

To use the !avrf extension, you must have access to Windows symbols — in particular, symbols for the system libraries ntdll.dll and verifier.dll. For details, see Installing Windows Symbol Files. Of course, symbols for your target application are also necessary.

Some Application Verifier actions can result in an exception being raised. The debugger must be set to catch these exceptions on the second chance, because Application Verifier itself will be handling the first chance exceptions.

The exceptions raised are of three types:

  • An access violation exception (0xC000000A) is generated if the Full page heap option detects a heap buffer overrun. In some cases the Check system path usage option can cause an access violation as well.
  • An invalid handle exception (0xC0000008) is generated when the Detect invalid handle usage option detects an invalid handle operation.
  • A stack overflow exception (0xC00000FD) is generated when the Check for adequate stack option detects that the initial stack was too short.

The easiest way to prepare for these events is to start the debugger on a command line as follows:

windbg -xd av -xd ch -xd sov ApplicationCommandLine

or

cdb -xd av -xd ch -xd sov ApplicationCommandLine

If you have already started the debugger, you can use the SXD (Set Exceptions) command to catch all access violations, invalid handles, and stack overflows as second-chance exceptions:

0:000> sxd av
0:000> sxd ch
0:000> sxd sov

Note It is theoretically possible to control Application Verifier through a kernel debugger. However, this is not recommended — it requires frequent use of the .process and .pagein commands, yet it gives you no more power than using a user-mode debugger.


Running and Debugging the Application

The easiest way to start the target application is from the command line of the debugger. See Setting Up a Debugger for Application Verifier for an example.

Any time the application is started after its name has been entered into AppVerif.exe, Application Verifier will monitor the application. You can always attach a debugger to the process after it is running — but if you want to make sure you don't miss any Application Verifier messages, it is better to launch the application from the debugger.

If you use AppVerif.exe to change which options are active, these changes will not take effect until the application is restarted. This can be done with the .restart (Restart Target Application) command.

If Application Verifier raises an exception or issues an Application Verifier Stop while no debugger is attached, the postmortem debugger (JIT debugger) will become active. See Enabling Postmortem Debugging for details.

Using the Debugger

Once the debugger is running, you may want to begin with the !avrf extension. When this extension is used with no switches, it will show the current status of Application Verifier. It will also let you know if you have symbol problems.

Here is an example:

0:001> !avrf

Global flags: 00010100
Application verifier global flag is set.

Application verifier settings (0000008E):

   - no heap checking enabled!
   - lock checks (critical section verifier)
   - handle checks
   - stack checks (disable automatic stack extensions)

Page heap is not active for this process.

No verifier stop active.

Note. Sometimes bugs found by verifier manifest themselves
as raised exceptions (access violations, stack overflows, invalid handles
and it is not always necessary to have a verifier stop.

Note This display shows those basic Application Verifier settings that are active. However, some of the more esoteric settings, such as Log potential security issues, will not be listed in this display.

For other uses of the debugger, see Injecting Faults Into the Application, Reading Application Verifier Logs, and Debugging Application Verifier Stops.


Injecting Faults Into the Application

Application Verifier can automatically break into the debugger when certain events occur.

Application Verifier also allows you to deliberately cause faults in the target application. This lets you simulate several classes of failures — for example, heap operations, file operations, and registry operations.

You can choose which events will fail, and how often these failures will occur. You can also restrict these failures to specific modules or memory regions.

This section includes:

Requesting Breaks on Certain Events

Choosing Which Events to Fault

Choosing Where to Fault


Requesting Breaks on Certain Events

You can use the !avrf -brk BreakEventType extension command to request a break on an event. Whenever this event occurs, Application Verifier will cause the application to break into the debugger.

You can use this opportunity to debug your application, or simply use the G (Go) command to resume execution.

The following break event types are supported:

Break event type | Nature of event
000 | A null handle is closed
001 | A pseudo-handle is closed
002 | The CreateEvent routine fails
003 | A heap allocation fails
004 | A wait with timeout fails
005 | A virtual allocation fails
006 | A map view operation fails
007 | A create file or open file operation fails
008 | A create registry key or open registry key operation fails
009 | An OLE string allocation fails

Using !avrf -brk BreakEventType a second time for the same BreakEventType deactivates the break.

To display the current break event settings, use !avrf -brk. This will show a list of all event types. Each break event type will be followed by a 1 (break requested) or a 0 (no break requested).


Choosing Which Events to Fault

Application Verifier lets you cause a variety of events to simulate failure or return error codes.

The types of faults that can be simulated are as follows:

Event type | Nature of fault
000 | Calls to WaitForSingleObject and WaitForMultipleObjects with a timeout parameter other than INFINITE will return WAIT_TIMEOUT.
001 | Attempts to allocate heap using the NT heap manager (for example, malloc, new, GlobalAlloc, RtlAllocateHeap) will fail.
002 | Calls to VirtualAlloc will fail.
003 | Attempts to create or open registry keys will fail.
004 | Attempts to create or open a file will fail.
005 | Attempts to create or open an event will fail.
006 | Attempts to map a view into the process space will fail.
007 | Attempts to allocate BSTR OLE strings will fail.

To display the current fault injection settings, use !avrf -flt. This will show a list of all event types. For each event type, the following information will be displayed:

  • The probability of a fault being injected. This is a number between 0 and 100. It determines the percentage chance of a fault being injected whenever this event occurs. The !avrf output always displays this as a hexadecimal number (between 0x0 and 0x64), but you can enter it as a decimal number by using the prefix 0n.
  • Whether Application Verifier should break into the debugger whenever a fault is injected. A "1" indicates that a break will happen; a "0" indicates that it will not happen.
  • The number of events of this time that have succeeded and the number that have failed.
  • Here is an example:
0:001> !avrf -flt
Fault injection settings:   Probability (break, success/failed)
==============================================
000 : Wait APIs:                 00 (0, 0 / 0)
001 : Heap allocations:          64 (0, 0 / 2)
002 : Virtual space allocations: 48 (0, 2F / 91)
003 : Registry APIs:             00 (0, 0 / 0)
004 : File APIs:                 32 (1, 3 / 4)
005 : Event APIs:                16 (1, 2 / 0)
006 : Map view operations:       00 (0, 0 / 0)
007 : OLE string allocations:    00 (0, 0 / 0)

In this example, the line for event 002 shows that virtual space allocations will fail 75% of the time (0x48 / 0x64), that Application Verifier will not break into the debugger when a fault of this type is injected, that 0x2F events of this type have occurred without faults being injected, and that 0x91 events of this type have been deliberately failed.

To change the probability for an event, use the syntax !avrf -flt EventType Probability. To break when a fault is injected, use the syntax !avrf -flt break EventType. Repeated use of the latter command will toggle the break status on and off.

Here is an example. The following commands change the probability of event 002 occurring to 90%, and cause a break to occur after each fault:

0:001> !avrf -flt 2 0n90
0:001> !avrf -flt break 2

If the application is restarted from the debugger, all fault injection settings are cleared.

When a break occurs after a fault has been injected, you will see this message in the debugger:

AVRF: fault injecting call made from XXXXXXXX

If the program crashes or leaks using fault injection, the best debugging aid is a history of the operations that were fault injected. This can be obtained with the syntax !avrf -flt stacks Length. This will output the stack traces for the most recent fault-injected operations. Length specifies the number of operations to display.

Sample Debugging Session

Here is a sample debugging session that illustrates these extension commands.

0:006> !avrf -flt 0 0n50
Probability for event 0 is now set to 32.

0:006> !avrf -flt break 0
Will break for fault injection event 0.

0:006> g
AVRF: fault injecting call made from 77236D62
Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=009fb710 ecx=77f75236 edx=019bda02 esi=009fb710 edi=00000001
eip=77f75084 esp=019bdc14 ebp=019bdc48 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
ntdll!DbgBreakPoint:
77f75084 cc               int     3

0:001> k
019bdc10 5ad164fe ntdll!DbgBreakPoint
019bdc48 5ad16673 verifier!AVrfpShouldFaultInject+0xae
019bdc5c 77236d62 verifier!AVrfpWaitForSingleObject+0x43
019bdc74 77233e7f ole32!CNotify::QueryNotify+0x31
019bdc90 77234432 ole32!CCache::CheckNotify+0x35
019bdcb4 772345bc ole32!CCache::GetElement+0xa8
019bdcf8 772331e2 ole32!CCache::GetElement+0xb0
019bdd54 772338f5 ole32!CComCatalog::GetClassInfoInternal+0x147
019bdd74 7722b3df ole32!CComCatalog::GetClassInfoW+0x1b
019bdd88 7722b408 ole32!GetClassInfoFromClsid+0x21
019bdda4 7722c0e5 ole32!GetActivationPropertiesIn+0x26

0:006> !avrf -flt stacks 2
- - - - - - - - - - - - - - - - - - - - - - - - -
    5ad16673 verifier!AVrfpWaitForSingleObject+0x00000043
    77236d62 ole32!CNotify::QueryNotify+0x00000031
    77233e7f ole32!CCache::CheckNotify+0x00000035
    77234432 ole32!CCache::GetElement+0x000000a8
    772345bc ole32!CCache::GetElement+0x000000b0
    772331e2 ole32!CComCatalog::GetClassInfoInternal+0x00000147
    772338f5 ole32!CComCatalog::GetClassInfoW+0x0000001b
    7493a84d mshtml!CErrorInfo::GetSource+0x00000039
    74907aee mshtml!CBase::ContextInvokeEx+0x000005fa
    748a5977 mshtml!CElement::ContextInvokeEx+0x0000005e
    74a365b1 mshtml!COleSite::ContextInvokeEx+0x0000008c
    74a36159 mshtml!COleSite::ContextThunk_InvokeEx+0x0000002f
- - - - - - - - - - - - - - - - - - - - - - - - -
    5ad16673 verifier!AVrfpWaitForSingleObject+0x00000043
    7730fb03 SHLWAPI!SHGlobalCounterGetValue+0x00000022
    7746689e SHELL32!_UpdateShellFolderCache+0x00000017
    77466955 SHELL32!SHGetFolderPathW+0x0000008f
    76a54ad6 shdocvw!IsCSIDLFolder+0x0000001e
    76a61698 shdocvw!CHistFolder::Initialize+0x00000022
    77494c94 SHELL32!CFSFolder::_Bind+0x0000005c
    77494f1c SHELL32!CFSFolder::BindToObject+0x0000009e
    774d1c3b SHELL32!CDrivesFolder::BindToObject+0x00000067
    7747e0d7 SHELL32!CRegFolder::BindToObject+0x00000043
    7747e072 SHELL32!CRegFolder::_BindToItem+0x00000083
    7747e0c0 SHELL32!CRegFolder::BindToObject+0x0000002c
    76a67d0e shdocvw!SHBindToObjectEx+0x0000003d
    76a68782 shdocvw!SHBindToObject+0x00000017
    769e714e shdocvw!CBaseBrowser2::Exec+0x00000621
    76a41928 shdocvw!CWebBrowserSB::Exec+0x000000f6


Choosing Where to Fault

When you instruct Application Verifier to cause certain events to fault, you can target specific modules or memory regions, or skip over other modules or memory regions.

To select a target memory range — a range in which faults can occur — use the syntax !avrf -trg Start End. To select a module in which faults can occur, use !avrf -trg dll Module. Without any additional parameters, !avrf -trg will display the current target memory range settings.

The default target range is the entire memory space. Use !avrf -trg all to reset all target ranges and restore the default.

You may wish to skip part of a targeted range. Use the syntax !avrf -skp Start End to define a range to be skipped. To skip a module, use !avrf -skp dll Module. Without any additional parameters, !avrf -skp will display the current excluded memory range settings.

By default, there is no excluded memory. Use !avrf -skp all to reset all excluded ranges and restore the default.

You can also use !avrf -skp Time to suppress all faults for Time milliseconds after execution resumes.

Example: Overlapping Ranges

Consider the following example. It begins with the default settings:

0:001> !avrf -trg
Fault injection target ranges (START END HITS):
============================================================
0000000000000000    FFFFFFFFFFFFFFFF    0

0:001> !avrf -trg 2000 6000
Target range 2000 - 7000 activated.

0:001> !avrf -trg 4000 9000
Target range 4000 - 9000 activated.

0:001> !avrf -skp 7000 8000
Exclusion range 7000 - 8000 activated.

0:001> !avrf -skp B000 D000
Exclusion range B000 - D000 activated.

0:001> !avrf -trg
Fault injection target ranges (START END HITS):
============================================================
0000000000002000    0000000000006000    0
0000000000004000    0000000000009000    0

0:001> !avrf -skp
Fault injection exclusion ranges (START END HITS):
============================================================
0000000000007000    0000000000008000    0
000000000000B000    000000000000D000    0

This shows how the !avrf -trg and !avrf -skp commands will echo back to you the exact ranges you input. In this example, the actual ranges targeted are 0x2000-0x6FFF and 0x8001-0x9000. In particular, the final exclusion range of 0xB000-0xD000 has no effect, since that isn't part of a targeted range at all.

The Hits column shows how many times an event was caught by thsi filter. A hit in an exclusion range means an event occurred in this range and therefore no fault was injected. A hit in a target range means that a fault may have been injected (subject to the probabilities set with the !avrf -flt command). In this example, an event at address 0x5000 could be credited to either of the target ranges, but not to both.

Up to 128 target ranges and 128 exclusion ranges can be defined.

Example: Targetting a Module

Here is another example. Suppose you wish to let faults occur within the shlwapi.dll module. One method is to use the following command:

0:001> !avrf -trg dll shlwapi.dll
Target range 772E0000 - 77349000 activated.

Here is another method which is longer but more instructive. You can use the !dlls extension to determine the start address and the end address of this module:

0:001> !dlls
......
0x00bb23d0: D:\WINDOWS\system32\SHLWAPI.dll
      Base   0x772e0000  EntryPoint  0x00bc5640  Size        0x00069000
      Flags  0x000c4006  LoadCount   0x0000ffff  TlsIndex    0x00000000
             LDRP_STATIC_LINK
             LDRP_IMAGE_DLL
             LDRP_ENTRY_PROCESSED
             LDRP_DONT_CALL_FOR_THREADS
             LDRP_PROCESS_ATTACH_CALLED
......

This shows that the shlwapi.dll module starts at 0x772E0000 has length 0x69000. To find its ending address, you can do a calculation in the debugger console:

0:001> ? 0x772e0000+69000
Evaluate expression: 1999933440 = 77349000

So the module ends at 0x77349000. Now you can set up this target range:

0:001> !avrf -trg 772e0000 77349000
Target range 772E0000 - 77349000 activated.


Reading Application Verifier Logs

Application Verifier creates several different kinds of logs. Some of these are viewed through the AppVerif.exe utility. For a description of these logs, start the AppVerif.exe and press Help.

This section describes the logs that are viewed through the debugger:

Heap Operation Logs

Virtual Space Operation Logs

Exception Logs

Other Logs and Displays


Heap Operation Logs

Heap information can be displayed in two different ways: by the !avrf extension with no switches, and by the !avrf -hp extension.

Basic Heap Information

To display basic heap information, use the !avrf extension with no switches.

If the Full page heap option is active, you will see a display similar to this:

0:001> !avrf

Global flags: 02000100
Application verifier global flag is set.
Page heap global flag is set.

Application verifier settings (00000007):

   - full page heap
   - lock checks (critical section verifier)
   - handle checks

Page heaps active in the process (format: pageheap, lightheap, flags):

    00891000 , 00990000 , 3 (pageheap traces )
    00a91000 , 00b90000 , 3 (pageheap traces )
    00c01000 , 00d00000 , 3 (pageheap traces )
    01331000 , 01430000 , 3 (pageheap traces )
    01571000 , 01670000 , 3 (pageheap traces )

No verifier stop active.

If the Fast fill heap option is active, you will see a display similar to this:

0:001> !avrf

Global flags: 02000100
Application verifier global flag is set.
Page heap global flag is set.

Application verifier settings (00008000):

   - fast fill heap (a.k.a light page heap)

Page heaps active in the process (format: pageheap, lightheap, flags):

    00891000 , 00990000 , 2 (lightheap traces )
    00a91000 , 00b90000 , 2 (lightheap traces )
    00c01000 , 00d00000 , 2 (lightheap traces )
    01331000 , 01430000 , 2 (lightheap traces )
    01471000 , 01570000 , 2 (lightheap traces )

No verifier stop active.

The Heap Operation Log

The heap operation log tracks all heap routines. These include HeapAlloc, HeapReAlloc, and HeapFree.

You can use the !avrf -hp Length extension command to display the last several records; Length specifies the number of records.

You can use !avrf -hp -a Address to display all heap space operations that affected the specified Address. For an allocation, it is sufficient that Address be contained in the allocated heap block. For a free, the exact address of the beginning of the block must be given.

For each entry in the log, the following information is displayed:

  • The heap function called
  • The thread ID of the thread that called the routine
  • The address involved in the call — this is the address that was returned by an allocation routine or that was passed to a free routine
  • The size of the region involved in the call
  • The stack trace of the call

The most recent entries are displayed first.

In this example, the two most recent entries are displayed:

0:001> !avrf -hp 2
alloc (tid: 0xFF4):
address: 00ea2fd0
size: 00001030
        00403062: Prymes!_heap_alloc_dbg+0x1A2
        00402e69: Prymes!_nh_malloc_dbg+0x19
        00402e1e: Prymes!_malloc_dbg+0x1E
        00404ff3: Prymes!_stbuf+0xC3
        00401c23: Prymes!printf+0x43
        00401109: Prymes!main+0xC9
        00402039: Prymes!mainCRTStartup+0xE9
        77e7a278: kernel32!BaseProcessStart+0x23

alloc (tid: 0xFF4):
address: 00ea07d0
size: 00000830
        00403062: Prymes!_heap_alloc_dbg+0x1A2
        00402e69: Prymes!_nh_malloc_dbg+0x19
        00402e1e: Prymes!_malloc_dbg+0x1E
        00403225: Prymes!_calloc_dbg+0x25
        00401ad5: Prymes!__initstdio+0x45
        00401f38: Prymes!_initterm+0x18
        00401da1: Prymes!_cinit+0x21
        00402014: Prymes!mainCRTStartup+0xC4
        77e7a278: kernel32!BaseProcessStart+0x23

Heap Operation Log Limitations

The heap operation log does not include heap calls performed inside ntdll.dll, nor those made by kernel-mode drivers.

This log has a limited length. Once it passes this length, the oldest entries are removed to make room for the newest entries. Only on rare occasions will this hinder debugging, since the allowable log length is quite large, and since most bugs are caused by relatively recent events.


Virtual Space Operation Logs

The virtual space operation log tracks all routines that modify the virtual space of a process in any way. These include VirtualAlloc, VirtualFree, MapViewOfFile, and UnmapViewOfFile.

You can use the !avrf -vs Length extension command to display the last several records; Length specifies the number of records.

You can use !avrf -vs -a Address to display all virtual space operations that affected the specified Address. For an allocation, it is sufficient that Address be contained in the allocated block. For a free, the exact address of the beginning of the region must be given.

For each entry in the log, the following information is displayed:

  • The function called
  • The thread ID of the thread that called the routine
  • The address involved in the call — this is the address that was returned by an allocation routine or that was passed to a free routine
  • The size of the region involved in the call
  • The type of memory operation (the AllocationType parameter)
  • The type of protection requested
  • The stack trace of the call

The most recent entries are displayed first.

In this example, the two most recent entries are displayed:

0:001> !avrf -vs 2
VirtualFree (tid: 0xB4): addr:04bb0000 sz:00400000 op:8000 prot:0
        00aa1ac2: verifier!VsLogCall+0x42
        00aa19c1: verifier!AVrfpNtFreeVirtualMemory+0x30
        68925d17: kernel32!VirtualFreeEx+0x35
        6892611c: kernel32!VirtualFree+0x13
        75ef6525: mshtml+0x116525
        75ef68af: mshtml+0x1168AF
        6a20787c: ntdll!LdrpCallInitRoutine+0x14
        6a211c6f: ntdll!LdrUnloadDll+0x39A
        689275c1: kernel32!FreeLibrary+0x3B
        77b22d69: ole32!CoQueryReleaseObject+0x1E6
        77b02bd2: ole32!SetErrorInfo+0x1ED

VirtualFree (tid: 0xB4): addr:04bb0000 sz:00001000 op:4000 prot:0
        00aa1ac2: verifier!VsLogCall+0x42
        00aa19c1: verifier!AVrfpNtFreeVirtualMemory+0x30
        68925d17: kernel32!VirtualFreeEx+0x35
        6892611c: kernel32!VirtualFree+0x13
        75ef65ae: mshtml+0x1165AE
        75ef68af: mshtml+0x1168AF
        6a20787c: ntdll!LdrpCallInitRoutine+0x14
        6a211c6f: ntdll!LdrUnloadDll+0x39A
        689275c1: kernel32!FreeLibrary+0x3B
        77b22d69: ole32!CoQueryReleaseObject+0x1E6
        77b02bd2: ole32!SetErrorInfo+0x1ED

It can be seen from the output that thread 0xB4 first decommitted a page and then released the whole virtual region.

Here is a display of all operations affecting the address 0x4BB1000:

0:001> !avrf -vs -a 4bb1000
Searching in vspace log for address 04bb1000 ...

VirtualFree (tid: 0xB4): addr:04bb0000 sz:00400000 op:8000 prot:0
        00aa1ac2: verifier!VsLogCall+0x42
        00aa19c1: verifier!AVrfpNtFreeVirtualMemory+0x30
        68925d17: kernel32!VirtualFreeEx+0x35
        6892611c: kernel32!VirtualFree+0x13
        75ef6525: mshtml+0x116525
        75ef68af: mshtml+0x1168AF
        6a20787c: ntdll!LdrpCallInitRoutine+0x14
        6a211c6f: ntdll!LdrUnloadDll+0x39A
        689275c1: kernel32!FreeLibrary+0x3B
        77b22d69: ole32!CoQueryReleaseObject+0x1E6
        77b02bd2: ole32!SetErrorInfo+0x1ED

VirtualFree (tid: 0xB4): addr:04bb1000 sz:00001000 op:4000 prot:0
        00aa1ac2: verifier!VsLogCall+0x42
        00aa19c1: verifier!AVrfpNtFreeVirtualMemory+0x30
        68925d17: kernel32!VirtualFreeEx+0x35
        6892611c: kernel32!VirtualFree+0x13
        75ef65ae: mshtml+0x1165AE
        75ef68af: mshtml+0x1168AF
        6a20787c: ntdll!LdrpCallInitRoutine+0x14
        6a211c6f: ntdll!LdrUnloadDll+0x39A
        689275c1: kernel32!FreeLibrary+0x3B
        77b22d69: ole32!CoQueryReleaseObject+0x1E6
        77b02bd2: ole32!SetErrorInfo+0x1ED

VirtualAlloc (tid: 0xB4): addr:04bb0000 sz:00010000 op:1000 prot:4
        00aa1ac2: verifier!VsLogCall+0x42
        00aa1988: verifier!AVrfpNtAllocateVirtualMemory+0x37
        68925ca3: kernel32!VirtualAllocEx+0x61
        68926105: kernel32!VirtualAlloc+0x16
        75ef63f3: mshtml+0x1163F3

VirtualAlloc (tid: 0xB4): addr:04bb0000 sz:00400000 op:2000 prot:4
        00aa1ac2: verifier!VsLogCall+0x42
        00aa1988: verifier!AVrfpNtAllocateVirtualMemory+0x37
        68925ca3: kernel32!VirtualAllocEx+0x61
        68926105: kernel32!VirtualAlloc+0x16
        75ef63d9: mshtml+0x1163D9

To read this, remember that the entries are dumped starting with the most recent one. So this log shows that thread 0xB4 allocated a big region in which it committed a page. Later it decommitted the page, and then released the entire virtual region.

Virtual Space Operation Log Limitations

The virtual space operation log does not include virtual space calls performed inside ntdll.dll, nor those made by kernel-mode drivers.

This log has a limited length. Once it passes this length, the oldest entries are removed to make room for the newest entries. Only on rare occasions will this hinder debugging, since the allowable log length is quite large, and since most bugs are caused by relatively recent events.


Exception Logs

The exception log records all exceptions that have occurred in the target process.

You can use the !avrf -ex Length extension command to display the last several exceptions; Length specifies the number of exceptions. If Length is omitted, all exceptions are displayed.

Here is an example:

0:000> !avrf -ex 4
=================================
Thread ID: 0000052c
Exception code: c0000008
Exception address: 6a226663
Exception record: 0012fb50
Context record: 0012fb64

Displayed 1 exception log entries.

Exception Log Limitations

The exception log has a limited length. Once it passes this length, the oldest entries are removed to make room for the newest entries. Only on rare occasions will this hinder debugging, since the allowable log length is quite large, and since most bugs are caused by relatively recent events.


Other Logs and Displays

The !avrf, !cs, and !htrace extensions can display a number of other Application Verifier data logs:

  • The !avrf -cnt extension displays a list of global counters.
  • The !avrf -trm extension displays a log of all terminated and suspended threads.
  • The !avrf -threads [ThreadID] extension displays a list of all threads in the process, or displays the one specified thread. For child threads, the stack size and the CreateThread flags specified by the parent are displayed as well.
  • The !avrf -trace TraceIndex extension displays a stack trace for the specified TraceIndex. Some structures use this 16-bit index number to identify a stack trace; this index points to a location within the stack trace database. If you are analyzing such a structure, you will find this syntax useful.
  • The !cs -t [TreeAddress] extension displays the critical section tree at the specified address, or the critical section tree for the target process. Application Verifier's Check lock usage option must be active for this to work.
  • The !htrace [Handle] extension can display stack trace information for the specified handle, or for all handles in the target process. Application Verifier's Detect invalid handle usage option must be active for this to work.


Debugging Application Verifier Stops

If the target application fails certain Application Verifier tests, it will break into the debugger.

Prior to an Application Verifier Stop, the debugger must be attached to the target, and certain exceptions must be configured as "second-chance exceptions." See Setting Up a Debugger for Application Verifier for details.

This section includes:

Debugging a Continuable Stop

Debugging a Non-Continuable Stop


Debugging a Continuable Stop

Here is an example of an invalid handle exception that has been raised by the Detect invalid handle usage option.

First, the following message appears:

Invalid handle - code c0000008 (first chance)
===========================================================
VERIFIER STOP 00000300: pid 0x558: invalid handle exception for current stack trace

        C0000008 : Exception code.
        0012FBF8 : Exception record. Use .exr to display it.
        0012FC0C : Context record. Use .cxr to display it.
        00000000 :
===========================================================
This verifier stop is continuable.
After debugging it use 'go' to continue.
===========================================================

Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=6a27c280 ecx=6a226447 edx=0012fa4c esi=00942528 edi=6a27c260
eip=6a22629c esp=0012facc ebp=0012faf0 iopl=0         nv up ei pl zr na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!DbgBreakPoint:
6a22629c cc               int     3

Notice that the message tells you that this Application Verifier Stop is continuable. Once you understand what has transpired, you can continue running the target application.

First, you should use the !avrf extension. This gives information about the current failure:

0:000> !avrf

Global flags: 00000100
Application verifier global flag is set.

Application verifier settings (00000004):

   - no heap checking enabled!
   - handle checks

Page heap is not active for this process.

Current stop 00000300 : c0000008 0012fbf8 0012fc0c 00000000 .

    Using an invalid handle (either closed or simply bad).

The final line of this display summarizes the problem.

You may wish to look at some logs at this point. See Reading Application Verifier Logs for details.

Once you are done, use the G (Go) command to set the application running again:

0:000> g


Debugging a Non-Continuable Stop

Here is an example of an access violation that has been raised by the Full page heap option.

First, the following message appears:

Access violation - code c0000005 (first chance)

===========================================================
VERIFIER STOP 00000008: pid 0x504: exception raised while verifying block header

        00EC1000 : Heap handle
        00F10FF8 : Heap block
        00000000 : Block size
        00000000 :
===========================================================
This verifier stop is not continuable. Process will be terminated
when you use the 'go' debugger command.
===========================================================

Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=6a226447 edx=0012fab7 esi=00f10ff8 edi=00000008
eip=6a22629c esp=0012fb5c ebp=0012fb80 iopl=0         nv up ei pl zr na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!DbgBreakPoint:
6a22629c cc               int     3

In this case, the message tells you that this Application Verifier Stop is not continuable. The error is too severe for the process to continue running, and there is no way for Application Verifier to salvage the process.

The !avrf extension can be used to give information about the current failure:

0:000> !avrf

Global flags: 02000100
Application verifier global flag is set.
Page heap global flag is set.

Application verifier settings (00000001):

   - full page heap

Page heaps active in the process (format: pageheap, lightheap, flags):

    00941000 , 00a40000 , 3 (pageheap traces )
    00b41000 , 00c40000 , 3 (pageheap traces )
    00cb1000 , 00db0000 , 3 (pageheap traces )
    00ec1000 , 00fc0000 , 3 (pageheap traces )

Current stop 00000008 : 00ec1000 00f10ff8 00000000 00000000 .

    Corrupted heap block.

The final line of this display summarizes the problem.

You may wish to look at some logs at this point. See Reading Application Verifier Logs for details.

You may wish to use the .restart (Restart Target Application) command at this point. Or perhaps you may prefer to end your Application Verifier session and begin fixing the bugs in your code.


RPC Debugging

This section includes:

Overview of RPC Debugging

Enabling RPC State Information

Displaying RPC State Information

Common RPC Debugging Techniques

RPC State Information Internals


Overview of RPC Debugging

Microsoft® Remote Procedure Call (RPC) makes it easy to cross process and machine boundaries and carry data around. This network programming standard is one reason that networking with Microsoft Windows® is so powerful.

But since RPC hides network calls from individual processes, it obscures the details of the interactions between the computers. This can make it hard to be sure why threads are doing what they are doing — or fail to do what they are supposed to do. As a result, debugging and troubleshooting RPC errors can be difficult. In addition, the vast majority of problems that appear to be RPC errors are actually configuration issues, or network connectivity issues, or other component issues.

Debugging Tools for Windows contains a tool called DbgRpc, as well as RPC-related debugger extensions. These can be used to analyze a variety of RPC problems on Windows XP and Windows .NET Server 2003.

These Windows versions can be configured to save RPC Runtime state information. Different amounts of state information can be saved; this allows you to obtain the information you need without placing a significant burden on your computer. See Enabling RPC State Information for details.

This information can then be accessed through either the debugger or the DbgRpc tool. In each case, a collection of queries is available. See Displaying RPC State Information for details.

In many cases, you can troubleshoot a problem by using the techniques outlined in Common RPC Debugging Techniques.

If you are curious about the mechanics of how this information is stored, or if you wish to devise your own techniques for state information analysis, see RPC State Information Internals.

These tools and techniques do not work on Windows NT® 4.0 or Windows 2000.


Enabling RPC State Information

Two different levels of RPC Runtime state information can be gathered: Server information and Full information. This information gathering must be enabled before the debugger or DbgRpc can be used to analyze state information.

Only Windows XP and Windows .NET Server 2003 support the gathering of RPC state information.

Gathering Server state information is very lightweight. It costs about 100 machine instructions per RPC call, resulting in no detectable load, even during performance tests. However, gathering this information does use memory (about 4KB per RPC server), so it is not recommended on a machine that is already experiencing memory pressure. Server information includes data about endpoints, threads, connection objects, and Server Call (SCALL) objects. This is sufficient to debug most RPC problems.

Gathering Full state information is more heavyweight. It includes all the information gathered at the Server level, and in addition includes Client Call (CCALL) objects. Full state information is usually not needed.

To enable the gathering of state information on an individual machine, run the Group Policy Editor (gpedit.msc). Under the Local Computer Policy, navigate to Computer Configuration/Administrative Templates/System/Remote Procedure Call. Under this node you will see the RPC Troubleshooting State Information item. When you edit its properties, you will see five possible states:

None
No state information will be maintained. Unless your machine is experiencing memory pressure, this is not recommended.
Server
Server state information will be gathered. This is the recommended setting on a single computer.
Full
Full state information will be gathered.
Auto1
On a computer with less than 64 MB RAM, this is the same as None. On a computer with at least 64 MB RAM, this is the same as Server.
Auto2
On a computer running Windows .NET Server 2003 with less than 128 MB RAM, or on any Windows XP computer, this is the same as None. On a Windows .NET Server 2003 computer with at least 128 MB RAM, this is the same as Server. This is the default.

If you want to simultanously set these levels on a set of networked computers, use the Group Policy Editor to roll out a machine policy to the desired set of machines. The policy engine will take care that the settings you want are propagated to the desired set of machines. The Auto1 and Auto2 levels are especially useful in this case, since the operating system and amount of RAM on each computer may vary.

If the network includes computers running versions of Windows earlier than Windows XP, the settings will be ignored on those machines.


Displaying RPC State Information

All RPC Runtime state information is contained in cells. A cell is the smallest unit of information that can be viewed and updated individually. Both the DbgRpc tool and the RPC debugger extensions allow you to view the contents of any given cell or to run high-level queries.

Each key object in the RPC Runtime will maintain one or more cells of information about its state. Each cell has a cell ID. When an object refers to another object, it does so by specifying that object's cell ID.

The key objects that the RPC Runtime can maintain information about are endpoints, threads, connection objects, Server Call (SCALL) objects, and Client Call (CCALL) objects. Server Call objects are usually referred to simply as "call objects".

The RPC state inforrmation queries produce the same information whether you are using the DbgRpc tool or the RPC debugger extensions. The following sections describe how queries are used in each vehicle:

Using the RPC Debugger Extensions

Using the DbgRpc Tool

The most basic query simply displays an individual cell:

Get RPC Cell Information

The following high-level queries are also available:

Get RPC Endpoint Information

Get RPC Thread Information

Get RPC Call Information

Get RPC Client Call Information


Using the RPC Debugger Extensions

A variety of RPC debugger extensions are exported from rpcexts.dll.

The RPC extensions used to display RPC state information will only run in user mode. They can be used from CDB (or NTSD) or from user-mode WinDbg.

The user-mode debugger must have a target application, but the target is irrelevant to the RPC extensions. If the debugger is not already running, you can simply start it with an uninteresting target — for example, windbg notepad or cdb winmine. Then use CTRL+C in CDB or Debug | Break in WinDbg to stop the target and access the Debugger Command window.

If you need to analyze RPC state information on a remote computer, you should start the user-mode debugger on the computer that needs to be analyzed, and then use Remote Debugging.

Accessing RPC state information through the debugger is especially useful in stress environments, or when a debugger already happens to be running.


Using the DbgRpc Tool

The DbgRpc tool (dbgrpc.exe) is located in the root directory of the Debugging Tools for Windows installation. It must be started in a Microsoft MS-DOS® Command Prompt window; double-clicking the icon will not start this tool.

The MS-DOS window must be running under an account with administrative privileges on the local computer, or with domain administrative privileges.

DbgRpc makes no calls to any system services (such as LSASS). This makes it useful for debugging even if a system service has crashed, as long as the kernel is still running.

Using DbgRcp on a Remote Computer

DbgRpc can also be used to examine information on a remote machine. For this to work, the remote machine must be able to accept remote connections and authenticate remote users. If the remote machine's RPCSS (RPC Endpoint Mapper) service has crashed, DbgRcp will not be able to work. Administrative or domain administrative privileges on the remote machine are required.

The -s command-line option is used to specify the server name, and the -p parameter is used to specify the transport protocol. Both TCP and named pipe protocols are available. TCP is the recommended protocol; it should work in almost every situation.

Here is an example:

G:\>dbgrpc -s MyServer -p ncacn_ip_tcp -l -P 1e8 -L 0.1
Getting remote cell info ...
Endpoint
Status: Active
Protocol Sequence: LRPC
Endpoint name: OLE18

DbgRpc Command Line

For a description of the the full command syntax, see DbgRpc Command-Line Options.


Get RPC Cell Information

Detailed cell information is displayed by the !rpcexts.getdbgcell extension, or by DbgRpc when the -l switch is used.

The process ID of the process that contains the desired cell must be specified, as well as the cell number.

In the following example, the process ID is 0x278, and the cell number is 0000.0002:

D:\wmsg>dbgrpc -l -P 278 -L 0.2
Getting cell info ...
Thread
Status: Dispatched
Thread ID: 0x1A4 (420)
Last update time (in seconds since boot):470.25 (0x1D6.19)

For details on the optional parameters, see DbgRpc Command-Line Options.

For a similar example using the RPC debugger extensions, see !rpcexts.getdbgcell.


Get RPC Endpoint Information

Endpoint information is displayed by the !rpcexts.getendpointinfo extension, or by DbgRpc when the -e switch is used.

If an endpoint number is specified, information about that endpoint is shown. If it is omitted, the endpoints for all processes on the system are displayed.

The following example displays all endpoints. This is often a useful way to obtain process IDs and cell numbers that can be used as arguments for additional commands:

D:\wmsg>dbgrpc -e
Searching for endpoint info ...
PID  CELL ID   ST PROTSEQ        ENDPOINT
-------------------------------------------------------
00a8 0000.0001 01            NMP \PIPE\InitShutdown
00a8 0000.0003 01            NMP \PIPE\SfcApi
00a8 0000.0004 01            NMP \PIPE\ProfMapApi
00a8 0000.0007 01            NMP \pipe\winlogonrpc
00a8 0000.0008 01           LRPC OLE5
00c4 0000.0001 01           LRPC ntsvcs
00c4 0000.0003 01            NMP \PIPE\ntsvcs
00c4 0000.0008 01            NMP \PIPE\scerpc
00d0 0000.0001 01            NMP \PIPE\lsass
00d0 0000.0004 01            NMP \pipe\WMIEP_d0
00d0 0000.000b 01            NMP \PIPE\POLICYAGENT
00d0 0000.000c 01           LRPC policyagent
0170 0000.0001 01           LRPC epmapper
0170 0000.0003 01            TCP 135
0170 0000.0005 01            SPX 34280
0170 0000.0006 01             NB 135
0170 0000.0007 01             NB 135
0170 0000.000b 01            NMP \pipe\epmapper
01b8 0000.0001 01            NMP \pipe\spoolss
01b8 0000.0003 01           LRPC spoolss
01b8 0000.0007 01           LRPC OLE7
00ec 0000.0001 01           LRPC OLE2
00ec 0000.0003 01           LRPC senssvc
00ec 0000.0007 01            NMP \pipe\tapsrv
00ec 0000.0008 01           LRPC tapsrvlpc
00ec 0000.000c 01            NMP \PIPE\ROUTER
00ec 0000.0010 01            NMP \pipe\WMIEP_ec
0214 0000.0001 01            NMP \PIPE\winreg
022c 0000.0001 01           LRPC LRPC0000022c.00000001
022c 0000.0003 01            TCP 1058
022c 0000.0005 01            SPX 24576
022c 0000.0006 01            NMP \PIPE\atsvc
02a8 0000.0001 01           LRPC OLE3
0370 0000.0001 01           LRPC OLE9
0278 0000.0001 01            TCP 1120
030c 0000.0001 01           LRPC OLE12

For details on the optional parameters, see DbgRpc Command-Line Options.

For a similar example using the RPC debugger extensions, see !rpcexts.getendpointinfo.


Get RPC Thread Information

Thread information is displayed by the !rpcexts.getthreadinfo extension, or by DbgRpc when the -t switch is used.

The PID of a process must be specified. You may specify a thread within that process as well; if the thread is omitted, all threads within that process will be displayed.

In the following example, the process ID is 0x278, and the thread ID is omitted:

D:\wmsg>dbgrpc -t -P 278
Searching for thread info ...
PID  CELL ID   ST TID      LASTTIME
-----------------------------------
0278 0000.0002 01 000001a4 00072c09
0278 0000.0005 03 0000031c 00072bf5

For details on the optional parameters, see DbgRpc Command-Line Options.

For a similar example using the RPC debugger extensions, see !rpcexts.getthreadinfo.


Get RPC Call Information

Server-side call (SCALL) information is displayed by the !rpcexts.getcallinfo extension, or by DbgRpc when the -c switch is used.

Four optional parameters are permitted. Three of these — CallID, IfStart, and ProcNum — are identifying information used by RPC to keep track of its calls. The fourth parameter, ProcessID, is the PID of the server process that owns the call. You should supply whatever parameters you know to narrow down the search.

If no parameters are supplied, all known SCALLs in the system will be displayed. The following is an example of this long display:

D:\wmsg>dbgrpc -c
Searching for call info ...
PID  CELL ID   ST PNO IFSTART  TIDNUMBER CALLFLAG CALLID   LASTTIME CONN/CLN
----------------------------------------------------------------------------
00c4 0000.0002 00 00f 82273fdc 0000.0007 00000001 00000002 0003595d 0000.0010
00c4 0000.0006 00 009 367abb81 0000.0015 00000001 0000004d 000185bd 0000.0005
00c4 0000.000a 00 007 367abb81 0000.002d 00000001 0000009f 00014672 0000.0009
00c4 0000.000c 00 007 367abb81 0000.002d 00000001 00000083 000122e3 0000.000b
00c4 0000.000d 00 03b 8d9f4e40 0000.002d 00000001 000000f7 0001aba5 0000.0020
00c4 0000.000e 00 03b 8d9f4e40 0000.0026 00000001 00000002 00023056 0000.0021
00c4 0000.000f 00 008 82273fdc 0000.001e 00000009 baadf00d 000366b4 00ec.03bc
00c4 0000.0012 00 00d 8d9f4e40 0000.0004 00000001 00000051 0000a334 0000.0011
00c4 0000.0014 00 000 367abb81 0000.0015 00000001 0000004c 0002db53 0000.0013
00c4 0000.0017 00 007 367abb81 0000.0015 00000001 00000006 0000d102 0000.0016
00c4 0000.0019 00 007 367abb81 0000.0004 00000001 00000006 0000f09e 0000.0018
00c4 0000.001b 00 009 65a93890 0000.0007 00000001 0000012e 00630f65 0000.001a
00c4 0000.001e 00 026 8d9f4e40 0000.0015 00000001 0000037d 0005e579 0000.002c
00c4 0000.001f 00 008 82273fdc 0000.0033 00000009 baadf00d 000145b3 00c4.02f8
00c4 0000.0023 00 000 367abb81 0000.0004 00000001 0000007e 000372f3 0000.0022
00c4 0000.0025 00 03b 8d9f4e40 0000.0026 00000001 0000000b 000122e3 0000.0024
00c4 0000.0027 00 000 367abb81 0000.002d 00000001 0000000b 00012e27 0000.0028
00c4 0000.002a 00 008 82273fdc 0000.0033 00000009 baadf00d 0001245f 022c.0290
00c4 0000.002f 00 007 367abb81 0000.0026 00000001 0000000a 0002983c 0000.002e
00c4 0000.0031 00 004 3ba0ffc0 0000.0026 00000001 00000007 0005c439 0000.001c
00c4 0000.0032 00 00b 82273fdc 0000.0039 00000009 baadf00d 00687db6 00d0.01d4
00c4 0000.0036 00 007 367abb81 0000.0030 00000001 00000065 0003a5e1 0000.0035
00c4 0000.0037 00 00d 8d9f4e40 0000.0015 00000001 0000033f 000376fa 0000.002b
00c4 0000.0038 00 008 8d9f4e40 0000.0015 00000001 00000803 0018485c 0000.003b
00c4 0000.003c 00 00b 82273fdc 0000.0034 00000009 baadf00d 0001f956 00a8.0244
00c4 0000.003d 00 008 82273fdc 0000.0034 00000009 baadf00d 0001ff02 01b8.037c
0170 0000.0009 00 002 e60c73e6 0000.0013 00000009 baadf00d 0005a371 00ec.031c
0170 0000.000a 00 002 0b0a6584 0000.0002 00000009 baadf00d 000126ae 00c4.0130
0170 0000.000c 00 002 0b0a6584 0000.0010 00000009 baadf00d 00012bc4 022c.0290
0170 0000.000d 00 003 00000136 0000.001b 00000009 baadf00d 0005ba71 00ec.0310
0170 0000.000e 00 000 412f241e 0000.0002 00000009 baadf00d 00012f21 02a8.029c
0170 0000.0010 00 003 00000136 0000.0013 00000009 00000003 000341da 0370.0060
0170 0000.0011 00 006 e60c73e6 0000.001b 00000009 baadf00d 000f1d00 0370.0328
0170 0000.0017 00 002 0b0a6584 0000.001b 00000009 baadf00d 0006c803 0278.0184
0170 0000.001a 00 004 00000136 0000.0012 00000001 baadf00d 00038e9b 00ec.0348
00ec 0000.0006 00 009 00000134 0000.0011 00000009 baadf00d 000b233f 0170.0244
00ec 0000.000b 00 001 2f5f6520 0000.001c 00000009 baadf00d 00035510 00ec.0334
00ec 0000.000e 00 001 629b9f66 0000.0014 00000009 baadf00d 00035813 00ec.01c4
00ec 0000.0012 00 000 629b9f66 0000.0014 00000009 baadf00d 00026cc6 00a8.0164
00ec 0000.001b 00 001 2f5f6520 0000.0004 00000001 baadf00d 000352c1 00ec.03a8
02a8 0000.0004 00 009 00000134 0000.0002 00000009 baadf00d 0009a540 0170.0244
0370 0000.0006 00 003 00000134 0000.0005 0000000b baadf00d 0002e7cd 00ec.0350
0370 0000.0008 00 009 00000134 0000.0007 0000000b 01cee9e4 000838fa 0170.0244
0278 0000.0004 02 000 19bb5061 0000.0002 00000001 00000001 00072c09 0000.0003

For details on the optional parameters, see DbgRpc Command-Line Options.

For a similar example using the RPC debugger extensions, see !rpcexts.getcallinfo.


Get RPC Client Call Information

Client call (CCALL) call information is displayed by the !rpcexts.getclientcallinfo extension, or by DbgRpc when the -a switch is used.

Four optional parameters are permitted. Three of these — CallID, IfStart, and ProcNum — are identifying information used by RPC to keep track of its calls. The fourth parameter, ProcessID, is the PID of the process that owns the call. You should supply whatever parameters you know to narrow down the search.

If no parameters are supplied, all known CCALLs in the system will be displayed. The following is an example of this long display:

D:\wmsg>dbgrpc -a
Searching for call info ...
PID  CELL ID   PNO  IFSTART  TIDNUMBER CALLID   LASTTIME PS CLTNUMBER ENDPOINT
------------------------------------------------------------------------------
0390 0000.0001 0000 19bb5061 0000.0000 00000001 00072bff 07 0000.0002 1120

For details on the optional parameters, see DbgRpc Command-Line Options.

For a similar example using the RPC debugger extensions, see !rpcexts.getclientcallinfo.

Note Information about Client Call objects is only gathered if the Full state information is being gathered. See Enabling RPC State Information for details.


Common RPC Debugging Techniques

This section describes four common RPC-related problems. RPC state information can be used to troubleshoot these problems.

Either the DbgRpc tool or the RPC debugger extensions can be used in any of these four situations.

Analyzing a Stuck Call Problem

Tracking Contention in the Server Process

Checking for Stuck Threads

Identifying the Caller From the Server Thread


Analyzing a Stuck Call Problem

A common problem occurs when some process makes an RPC call, directly or indirectly, while holding a critical section or a resource. The RPC call goes to another process or to another machine, and dispatches to the manager routine (server routine) — which in turn hangs or takes too long. This causes the original caller to encounter a critical section timeout.

When examined through the debugger, RPC is on top of the stack of the thread owning the critical section, but it is not clear what it is waiting for.

Here is one example of such a stack. Many variations are possible:

0:002> ~1k
ChildEBP RetAddr
0068fba0 77e9e8eb ntdll!ZwWaitForSingleObject+0xb
0068fbc8 4efeff73 KERNEL32!WaitForSingleObjectEx+0x5a
0068fbe8 4eff0012 RPCRT4!UTIL_WaitForSyncIO+0x21
0068fc0c 4efe6e2b RPCRT4!UTIL_GetOverlappedResultEx+0x44
0068fc44 4ef973bf RPCRT4!WS_SyncRecv+0x12a
0068fc68 4ef98d5a RPCRT4!OSF_CCONNECTION__TransSendReceive+0xcb
0068fce4 4ef9b682 RPCRT4!OSF_CCONNECTION__SendFragment+0x297
0068fd38 4ef9a5a8 RPCRT4!OSF_CCALL__SendNextFragment+0x272
0068fd88 4ef9a9cb RPCRT4!OSF_CCALL__FastSendReceive+0x165
0068fda8 4ef9a7f8 RPCRT4!OSF_CCALL__SendReceiveHelper+0xed
0068fdd4 4ef946a7 RPCRT4!OSF_CCALL__SendReceive+0x37
0068fdf0 4efd56b3 RPCRT4!I_RpcSendReceive+0xc4
0068fe08 01002850 RPCRT4!NdrSendReceive+0x4f
0068ff40 01001f32 rtclnt+0x2850
0068ffb4 77e92ca8 rtclnt+0x1f32
0068ffec 00000000 KERNEL32!CreateFileA+0x11b

Here's how to troubleshoot this problem.

Troubleshooting a Stuck Call Problem

  1. Make sure the debugger is debugging the process that owns the stuck cell. (This is the process containing the client thread that is suspected of hanging in RPC.)
  2. Get the stack pointer of this thread. The stack will look like the one shown above. In this example, the stack pointer is 0x68FBA0.
  3. Get the call information for this thread. In order to do that, use the !rpcexts.rpcreadstack extension with the thread stack pointer as its parameter, as follows:
    0:001> !rpcexts.rpcreadstack 68fba4
CallID: 1
IfStart: 19bb5061
ProcNum: 0
        Protocol Sequence:      "ncacn_ip_tcp"  (Address: 00692ED8)
        NetworkAddress: ""      (Address: 00692F38)
        Endpoint:       "1120"  (Address: 00693988)

    The information displayed here will allow you to trace the call.

  4. The network address is empty, which indicates the local machine. The endpoint is 1120. You need to determine which process hosts this endpoint. This can be done by passing this endpoint number to the !rpcexts.getendpointinfo extension, as follows:
    0:001> !rpcexts.getendpointinfo 1120
Searching for endpoint info ...
PID  CELL ID   ST PROTSEQ        ENDPOINT
--------------------------------------------
0278 0000.0001 01            TCP 1120
  5. From the information above, you can see that process 0x278 contains this endpoint. You can determine if this process knows anything about this call by using the !rpcexts.getcallinfo extension. This extension needs four parameters: CallID, IfStart, and ProcNum (which were found in step three), and the ProcessID of 0x278:
    0:001> !rpcexts.getcallinfo 1 19bb5061 0 278
Searching for call info ...
PID  CELL ID   ST PNO IFSTART  TIDNUMBER CALLFLAG CALLID   LASTTIME CONN/CLN
----------------------------------------------------------------------------
0278 0000.0004 02 000 19bb5061 0000.0002 00000001 00000001 00072c09 0000.0003
  6. The information above is useful, but somewhat abbreviated. The cell ID is given in the second column as 0000.0004. If you pass the process ID and this cell number to the !rpcexts.getdbgcell extension, you will see a more readable display of this cell:
    0:001> !rpcexts.getdbgcell 278 0.4
Getting cell info ...
Call
Status: Dispatched
Procedure Number: 0
Interface UUID start (first DWORD only): 19BB5061
Call ID: 0x1 (1)
Servicing thread identifier: 0x0.2
Call Flags: cached
Last update time (in seconds since boot):470.25 (0x1D6.19)
Owning connection identifier: 0x0.3

    This shows that the call is in state "dispatched", which means is has left the RPC Runtime. The last update time is 470.25. You can learn the current time by using the !rpcexts.rpctime extension:

    0:001> !rpcexts.rpctime
Current time is: 6003, 422

    This shows that the last contact with this call was approximately 5533 seconds ago, which is about 92 minutes. So this must be a stuck call.

  7. As a last step before you attach a debugger to the server process, you can isolate the thread that should currently service the call, using the Servicing thread identifier. This is another cell number; it appeared in step 6 as "0x0.2". You can use it as follows:
    0:001> !rpcexts.getdbgcell 278 0.2
Getting cell info ...
Thread
Status: Dispatched
Thread ID: 0x1A4 (420)
Last update time (in seconds since boot):470.25 (0x1D6.19)

    Now you know that you are looking for thread 0x1A4 in process 0x278.

It is possible that the thread was making another RPC call. If necessary, you can trace this call by repeating this procedure.

Note The example here shows how to find the server thread if you know the client thread. For an example of the reverse technique, see Identifying the Caller From the Server Thread.


Tracking Contention in the Server Process

In order to service incoming requests, RPC will maintain a set of worker threads. Ideally, the number of threads will be small. However, this ideal situation has only been seen in lab environments, where the server manager routines are carefully tuned. In a real situation, the number of threads will vary depending on server workload — but it can be anywhere from 1 to 50.

If the number of worker threads is above 50, you may have excessive contention in the server process. Common causes of this are indiscriminate use of the heap, memory pressure, or serializing most activities in a server through a single critical section.

To see the number of threads in a given server process, use the !rpcexts.getthreadinfo extension, or use DbgRpc with the -t switch. Supply the process ID (in this example, 0xC4):

D:\wmsg>dbgrpc -t -P c4
Searching for thread info ...
PID  CELL ID   ST TID      LASTTIME
-----------------------------------
00c4 0000.0004 03 0000011c 000f164f
00c4 0000.0007 03 00000120 008a6290
00c4 0000.0015 03 0000018c 008a6236
00c4 0000.0026 03 00000264 0005c443
00c4 0000.002d 03 00000268 000265bb
00c4 0000.0030 03 0000026c 000f1d32
00c4 0000.0034 03 00000388 007251e9

In this case, there are only seven worker threads, which is reasonable.

If there are over 100 threads, someone should attach a debugger to this process and investigate the cause of this.

Note Running queries like dbgrpc -t remotely is expensive to the server and the network. If you use this query in a script, you should make sure this command is not run too often.


Checking for Stuck Threads

RPC needs its worker threads to be available in order to perform normally. A common problem is that some component in the same process will deadlock while holding one of the global critical sections (for example, loader lock or heap lock). This will cause many threads to hang — very possibly including some RPC worker threads.

If this occurs, the RPC server will not respond to the outside world. RPC calls to it will return RPC_S_SERVER_UNAVAILABLE or RPC_S_SERVER_TOO_BUSY.

A similar problem can result if a faulty driver prevents IRPs from completing and reaching the RPC server.

If you suspect that one of these problems may be occurring, use DbgRpc with the -t switch (or use the !rpcexts.getthreadinfo extension). The process ID should be used as a parameter — in this example, assume the process ID is 0xC4:

D:\wmsg>dbgrpc -t -P c4
Searching for thread info ...
PID  CELL ID   ST TID      LASTTIME
-----------------------------------
00c4 0000.0004 03 0000011c 000f164f
00c4 0000.0007 03 00000120 008a6290
00c4 0000.0015 03 0000018c 008a6236
00c4 0000.0026 03 00000264 0005c443
00c4 0000.002d 03 00000268 000265bb
00c4 0000.0030 03 0000026c 000f1d32
00c4 0000.0034 03 00000388 007251e9

The TID column gives the thread ID for each thread. The LASTTIME column contains the time stamp of the last change in state for each thread.

Whenever the server receives a request, at least one thread will change state, and its time stamp will be updated. Therefore if an RPC request is made to the server and the request fails, but none of the time stamps change, this indicates that the request is not actually reaching the RPC runtime. You should investigate the cause of this.


Identifying the Caller From the Server Thread

It is possible to determine who made a given RPC call, even if the only information you have is the server thread which serviced the call.

This can be very useful — for example, to find out who passed invalid parameters to an RPC call.

Depending on which protocol sequence is used by this particular call, you can get varying degrees of detail. Some protocols (such as NetBios) don't have this information at all.

Identifying the Caller From the Server Thread

  1. Start a user-mode debugger with the server thread as the target.
  2. Get the process ID by using the | (Process Status) command:
    0:001> |
  0     id: 3d4 name: rtsvr.exe
  3. Get the active calls in this process by using the !rpcexts.getcallinfo extension. (See the reference page for an explanation of the syntax.) You need to supply the process ID of 0x3D4:
    0:001> !rpcexts.getcallinfo 0 0 FFFF 3d4
Searching for call info ...
PID  CELL ID   ST PNO IFSTART  THRDCELL  CALLFLAG CALLID   LASTTIME CONN/CLN
----------------------------------------------------------------------------
03d4 0000.0004 02 000 19bb5061 0000.0002 00000001 00000001 00a1aced 0000.0003

    Look for calls with status 02 or 01 (dispatched or active). In this example, the process only has one call. If there were more, you would have to use the !rpcexts.getdbgcell extension with the cell number in the THRDCELL column; this would allow you to examine the thread ID's so you could determine which call you were interested in.

  4. Once you know which call you are interested in, look at the cell number in the CONN/CLN column. This is the cell ID of the connection object. In this case, the cell number is 0000.0003. Pass this cell number and the process ID to !rpcexts.getdbgcell:
    0:001> !rpcexts.getdbgcell 3d4 0.3
Getting cell info ...
Connection
Connection flags: Exclusive
Authentication Level: Default
Authentication Service: None
Last Transmit Fragment Size: 24 (0x6F56D)
Endpoint for the connection: 0x0.1
Last send time (in seconds since boot):10595.565 (0x2963.235)
Last receive time (in seconds since boot):10595.565 (0x2963.235)
Getting endpoint info ...
Process object for caller is 0xFF9DF5F0

This extension will display all the information available about the client of this connection. The amount of actual information will vary depending on the transport being used.

In this example, local named pipes are being used as the transport, and the process object address of the caller is displayed. If you attach a kernel debugger (or start a local kernel debugger) you can use the !process extension to interpret this process address.

If LRPC is used as the transport, the process ID and thread ID of the caller will be displayed.

If TCP is used as the transport, the IP address of the caller will be displayed.

If remote named pipes are used as the transport, no information will be available.

Note The example here shows how to find the client thread if you know the server thread. For an example of the reverse technique, see Analyzing a Stuck Call Problem.


RPC State Information Internals

This section gives some details of the internal structure of the state information gathered by the RPC Runtime.

All RPC Runtime state information is contained in cells. A cell is the smallest unit of information that can be viewed and updated individually.

Each key object in the RPC Runtime will maintain one or more cells of information about its state. Each cell has a cell ID. When an objects refers to another object, it does so by specifying that object's cell ID. The key objects that the RPC Runtime can maintain information about are endpoints, threads, connection objects, Server Call (SCALL) objects, and Client Call (CCALL) objects.

When an RPC server is running, the RPC Runtime listens on a set of endpoints, using one or more worker threads. Whenever data is transmitted to the server, a thread picks up the data and determines what the incoming request is. If the request is to create a connection, a Connection object is created, and this object then services all calls on the connection. When an RPC call is made on the connection, the Connection object instantiates a Server Call (SCALL) object corresponding to the Client Call (CCALL) object. This Server Call object then handles this particular call.

When an RPC client is running, the RPC Runtime creates a Client Call object each time a call is made. This Client Call object contains information about this particular call.

Endpoint Cells

From the RPC Runtime's point of view, an endpoint is an entry point through which the particular server can be contacted. The endpoint is always associated with a given RPC transport. The endpoint state information is used to associate a client call with a particular process on the server.

The fields in an endpoint cell are:

ProtseqType
The protocol sequence for this endpoint.
Status
The status value: allocated, active, or inactive. Most endpoints are active. An endpoint has allocated status when the creation process has started but is not complete yet. An endpoint is inactive if it is no longer in use (for example, when a protocol has been uninstalled).
EndpointName
The first 28 characters of the endpoint name.

Thread Cells

Server threads are worker threads (standard Win32 threads for use by RPC).

The fields in a thread cell are:

Status
The status value: processing, dispatched, allocated, or idle. A processing thread is one that is within the runtime and is processing information. A dispatched thread has already dispatched (called) to the server-provided manager routine (usually just called the "server routine"). An allocated thread has been cached. An idle thread is available to service requests.
LastUpdateTime
The time (in milliseconds after boot) when the information was last updated.
TID
The thread ID of this thread. This is useful when trying to correlate with the thread list in the debugger.

Connection Object Cells

The fields in a connection object cell are:

Flags
Flag values include exclusive/non-exclusive, authentication level, and authentication service.
LastTransmitFragmentSize
The size of the last fragment transmitted over the connection.
Endpoint
The cell ID of the endpoint this connection was picked up from.
LastSendTime
The last time data was sent on a connection.
LastReceiveTime
The last time data was received on a connection.

Server Call Object Cells

The fields in a Server Call (SCALL) object cell are:

Status
The status value: allocated, active, or dispatched. An allocated call is inactive and cached. When a call is active, the RPC Runtime is processing information related to this call. When a call is dispatched, the manager routine (server routine) has been called and has not returned yet.
ProcNum
The procedure number (operation number, in netmon capture files) of this call. The RPC Runtime identifies individual routines from an interface by numbering them by position in the IDL file. The first routine in the interface will be number 0, the second 1, and so on.
InterfaceUUIDStart
The first DWORD of the interface UUID.
ServicingTID
The cell ID of the thread that is servicing this call. If the call is not active or dispatched, this contains stale information.
CallFlags
These flag values indicate such things as whether this is the cached call in an exclusive connection, whether this is an asynchronous call, whether this is a pipe call, and whether this is an LRPC or OSF call.
LastUpdateTime
The time (in milliseconds after boot) when the call object state information was last updated.
PID
The Process ID of the caller. Valid only for LRPC calls.
TID
The Thread ID of the caller. Valid only for LRPC calls.

Client Call Object Cells

A Client Call (CCALL) object is broken into two cells, since the information about a client call is too large to fit in one cell. The first cell is called Client Call Information, and the second is called Call Target Information. Most tools will show the information together, so you don't need to distinguish between them.

Information about client calls is not maintained unless you are gathering "Full" state information. There is one exception to this rule: information about client calls made within a server call is maintained even when only "Server" state information is being gathered. This allows you to trace calls spanning multiple hops.

The fields in the Client Call Information cell are:

ProcNum
The procedure number (operation number, in netmon capture files) of the method being called. The RPC Runtime identifies individual routines from an interface by numbering them by position in the IDL file. The first routine in the interface will be number 0, the second 1, and so on.
ServicingThread
The cell ID of the thread on which this call is made.
IfStart
The first DWORD of the interface UUID on which the call is made.
Endpoint
The first 12 characters of the endpoint on the server to which the call was made.

The fields in the Call Target Information cell are:

ProtocolSequence
The protocol sequence for this call.
LastUpdateTime
The time (in milliseconds after boot) when the information about the client call or the call target was updated.
TargetServer
The first 24 characters of the name of the server to which the call is made.


ACPI Debugging

This section includes:

The AMLI Debugger

Other ACPI Debugging Extensions


The AMLI Debugger

This section includes:

Introduction to the AMLI Debugger

Setting Up an AML Debugging Session

Basic AML Debugging

Using AMLI Debugger Extensions

Using AMLI Debugger Commands

AML Debugging Examples


Introduction to the AMLI Debugger

There are significant differences between debugging standard kernel-mode code and debugging an ACPI (Advanced Configuration and Power Interface) BIOS.

Whereas Windows and its drivers are composed of binary machine code compiled for a specific processor, the core of an ACPI BIOS is not in machine code. Rather, it is stored as ACPI Machine Language (AML), and is processed by the Microsoft® AML interpreter as it is run.

The Microsoft AMLI Debugger is a special debugging tool that can debug AML code. The AMLI Debugger is not actually a free-standing program. Rather, it consists of two components. One component is the checked build of the Microsoft® Windows® ACPI driver (acpi.sys). The other component is located in certain debugger extensions included in the Debugging Tools for Windows package.

AMLI Debugger versions exist for Windows 9x, Windows 2000, Windows XP, and Windows .NET Server 2003. The Windows 9x version is not described in this documentation, although its use is very similar to that of the NT-based version.

On Windows XP and Windows .NET Server 2003, the AMLI Debugger is completely 64-bit aware. No matter what processor is being used by the target computer or the host computer, the AMLI Debugger will function correctly.


Setting Up an AML Debugging Session

The AMLI Debugger resides within the checked build of acpi.sys. In order to fully perform AML debugging, this driver must be installed on your target computer. The free build of acpi.sys does not contain the AMLI Debugger itself, although it does support some of the AMLI Debugger extensions.

If you are running the checked build of Windows on your target computer, then the checked driver is already installed.

If you are running the free build, you must either install the entire checked build of Windows, or simply install the checked version of acpi.sys.

For instructions on how to install a full checked build or individual checked files, see the Windows DDK.


Basic AML Debugging

The AMLI Debugger supports two types of specialized commands: AMLI Debugger extensions and AMLI Debugger commands.

When you are performing AML debugging, you should carefully distinguish between two different kinds of prompts that will appear in the Debugger Command window:

  • When you see the kd> prompt, you are controlling the kernel debugger. All the standard kernel debugger commands and extensions are available. In addition, the AMLI Debugger extensions are also available. In Windows 2000, these extensions have a syntax of !acpikd.amli command. In Windows XP and Windows .NET Server 2003, these extensions have a syntax of !amli command. The AMLI Debugger commands are not available in this mode.
  • When you see the AMLI(? for help)-> prompt, you are controlling the AMLI Debugger. (When you are using WinDbg, this prompt will appear in the top pane of the Debugger Command window, and an Input> prompt will appear in the bottom pane.) From this prompt you can enter any AMLI Debugger command. You can also enter any AMLI Debugger extension; these extensions should not be prefixed with !amli. The standard kernel debugging commands are not available in this mode.
  • When you see no prompt at all, the target computer is running.

At the beginning of any debugging session, you should set your AMLI Debugger options with the !amli set extension. The verboseon, traceon, and errbrkon options are also very useful. And when you target computer is running Windows XP and Windows .NET Server 2003, you should always activate the spewon option. See the extension reference page for details.

There are several ways for the AMLI Debugger to become active:

  • If a breakpoint in AML code is encountered, ACPI will break into the AMLI Debugger.
  • If a serious error or exception occurs within AML code (such as an int 3), ACPI will break into the AMLI Debugger.
  • If the errbrkon option has been set, any AML error will cause ACPI to break into the AMLI Debugger.
  • If you want to deliberately break into the AMLI Debugger, use the !amli debugger extension and then the G (Go) command. The next time any AML code is executed by the interpreter, the AMLI Debugger will take over.

When you are at the AMLI Debugger prompt, you can type q to return to the kernel debugger, or type g to resume normal execution.

The following extensions are especially useful for AML debugging:

  • The !amli dns extension displays the ACPI namespace for a particular object, the namespace tree subordinate to that object, or even the entire namespace tree. This command is especially useful in determining what a particular namespace object is — whether it is a method, a fieldunit, a device, or another type of object.
  • The !amli find extension takes the name of any namespace object and returns its full path.
  • The !amli u extension unassembles AML code.
  • The !amli lc extension displays brief information about all active ACPI contexts.
  • The !amli r extension displays detailed information about the current context of the interpreter. This is useful when the AMLI Debugger prompt appears after an error is detected.
  • Breakpoints can be set and controlled within AML code. Use !amli bp to set a breakpoint, !amli bc to clear a breakpoint, !amli bd to disable a breakpoint, !amli be to re-enable a breakpoint, and !amli bl to list all breakpoints.
  • The AMLI Debugger is able to run, step, and trace through AML code. Use the run, p, and t commands to perform these actions.

For a full list of extensions and commands, see Using AMLI Debugger Extensions and Using AMLI Debugger Commands .


Using AMLI Debugger Extensions

In Windows XP and Windows .NET Server 2003, AMLI Debugger extension commands are contained in the extension module kdexts.dll and use the following syntax:

kd> !amli command [parameters]

In Windows 2000, these extension commands are contained in acpikd.dll and use the following syntax:

kd> !acpikd.amli command [parameters]

As with any extension module, once it has been loaded you can omit the acpikd prefix.

If you are at the AMLI Debugger prompt, you can execute any of these extension commands by simply entering the command name without the !amli prefix:

AMLI(? for help)-> command [parameters]

When you are at this prompt, the !amli debugger command is not available (since it would be meaningless). Also, the help command ( ? ) at this prompt shows all AMLI Debugger extensions and commands, while the !amli ? extension only displays help on actual extensions.

Action | Extension Command
Display Help | !amli ?
Set AML Breakpoint | !amli bp
List AML Breakpoints | !amli bl
Disable AML Breakpoint | !amli bd
Enable AML Breakpoint | !amli be
Clear AML Breakpoint | !amli bc
Enter AMLI Debugger | !amli debugger
Display Event Log | !amli dl
Clear Event Log | !amli cl
Display Heap | !amli dh
Display Data Object | !amli do
Display Stack | !amli ds
Display Namespace Object | !amli dns
Find Namespace Object | !amli find
Display Nearest Method | !amli ln
List All Contexts | !amli lc
Display Context Information | !amli r
Unassemble AML Code | !amli u
Set AMLI Debugger Options | !amli set


Using AMLI Debugger Commands

The following commands can be issued from the AMLI Debugger prompt.

General Category | Specific Action | AMLI Debugger Commands
Controlling the Debugger | Continue Execution Break to Kernel Debugger | g q
Controlling AML Execution | Run Method Step Over AML Code Trace Into AML Code | run p t
Controlling Trace Mode Settings | Configure Trace Mode | trace
Notifying a Namespace Object | Notify Namespace Object | notify
Displaying the Object Count Table | Display Object Count Table | dc
Accessing Memory | Display Data Display Data Bytes Display Data Words Display Data DWORDs Display Data String Edit Memory | d db dw dd da e
Accessing Ports | Read Byte from Port Read Word from Port Read DWORD from Port Write Byte to Port Write Word to Port Write DWORD to Port | i iw id o ow od
Displaying Help | Display Help | ?

Controlling the Debugger

These commands exit the AMLI Debugger. The g command will resume normal execution of the target computer. The q command will freeze the target computer and break into the kernel debugger.

g

q

Controlling AML Execution

These commands allow you to run or step through AML methods. The run command begins execution at a specified point. The p and t commands allow you to step through one instruction at a time. If a function call is encountered, the p command treats the function as a single step, while the t command traces into the new function one instruction at a time.

run MethodName [ArgumentList]

run CodeAddress [ArgumentList]

p

t
MethodName
Specifies the full path and name of a method. Execution will start at the beginning of this method's memory location.
CodeAddress
Specifies the address where execution is to begin.
ArgumentList
Specifies a list of arguments to be passed to the method. Each argument must be an integer. Multiple arguments should be separated with spaces.

Controlling Trace Mode Settings

The trace command controls the AML interpreter's trace mode settings. If this command is used with no parameters, the current trace mode settings are displayed.

trace [trigon|trigoff] [level=Level] [add=TPStrings] [zap=TPNumbers]
trigon
Activates trace trigger mode.
trigoff
Deactivates trace trigger mode.
Level
Specifies the new setting for the trace level.
TPStrings
Specifies one or more trigger points to be added. Each trigger point is specified by name. Multiple trigger point strings should be separated by commas.
TPNumbers
Specifies one or more trigger points to be deleted. Each trigger point is specified by number. Multiple trigger point numbers should be separated by commas. To see a list of trigger point numbers, use the trace command with no parameters.

Notifying a Namespace Object

The notify command sends a notification to an ACPI namespace object. The notification will be placed in the specified object's queue.

notify ObjectName Value

notify ObjectAddress Value
ObjectName
Specifies the full namespace path of the object to be notified.
ObjectAddress
Specifies the address of the object to be notified.
Value
Specifies the notification value.

Displaying the Object Count Table

The dc command displays the memory object count table.

dc

Accessing Memory

The memory access commands allow you to read and write to memory. When reading memory, you can choose the size of the memory units with the db, dw, dd, or da command. A simple d command displays memory in the most recently-chosen units; if this is the first display command used, byte units are used.

If no address or method is specified, display will begin where the previous display command ended.

These commands have the same effect as the standard kernel debugger memory commands; they are duplicated within the AMLI Debugger for easy access.

d[b|w|d|a] [ [l=Length] [ Method | [%%]Address ] ]

e [%%]Address DataList
b
Specifies that the data should be displayed in byte units.
w
Specifies that the data should be displayed in word (16 bit) units.
d
Specifies that the data should be displayed in DWORD (32 bit) units.
a
Specifies that the data should be displayed as a string. The data is displayed as ASCII characters. The display terminates when a NULL character is read, or when Length characters have been displayed.
Length
Specifies the number of bytes to be displayed. Length must be a hexadecimal number (without an 0x prefix). If Length is omitted, the default display size is 0x80 bytes.
Method
Specifies the full path and name of a method. The display will start at the beginning of this method's memory location.
Address
Specifies the memory address where reading or writing will begin. If the address is prefixed with two percent signs (%%), it is interpreted as a physical address. Otherwise it is interpreted as a virtual address.
DataList
Specifies the data to be written to memory. Each item in the list can be either a hexadecimal byte or a string. When a string is used, it must be enclosed in quotation marks. Multiple items should be separated by spaces.

Accessing Ports

The port commands allow you to send output or receive input from a data port. The i and o commands transfer single bytes, the iw and ow commands transfer words (16 bits), and the id and od commands transfer DWORDS (32 bits).

These commands have the same effect as the standard kernel debugger port commands; they are duplicated within the AMLI Debugger for easy access.

i Port

iw Port

id Port

o Port DataForPort

ow Port DataForPort

od Port DataForPort
Port
Specifies the address of the port to be accessed. The port size must match the command chosen.
DataForPort
Specifies the data to be written to the port. The size of this data must match the command chosen.

Displaying Help

This command displays help text for the AMLI Debugger commands.

? [Command]
Command
Specifies the command to display help for. If this is omitted, a list of all AMLI Debugger commands and AMLI Debugger extensions is displayed.


AML Debugging Examples

Here are examples that illustrate how to get started with AML debugging.

Investigating a Frozen Computer

If the target computer has frozen and you suspect it may be an ACPI problem, begin by using the !amli lc extension to display all the active contexts:

kd> !amli lc
*Ctxt=ffffffff8128d000, ThID=ffffffff81277880, Flgs=----R----, pbOp=ffffffff8124206c, Obj=\_SB.PCI0.ISA0.FDC0._CRS

If no contexts are displayed, the error is probably not ACPI-related.

If there are contexts shown, look for the one marked with an asterisk. This is the current context (the one which is being executed by the interpreter at this moment).

In this example, the target computer is running Windows XP or Windows .NET Server 2003 on a 32-bit processor. Therefore all addresses are cast to 64 bits, producing a gratuitous FFFFFFFF in the high 32 bits. The abbreviation pbOp indicates the instruction pointer ("pointer to binary op codes"). The Obj field gives the full path and name of the method as it appears in the ACPI tables. For a description of the flags, see !amli lc.

You can use the !amli u command to disassemble the _CRS method indicated here:

kd> !amli u \_SB.PCI0.ISA0.FDC0._CRS

ffffffff80e4a535 : CreateDWordFieldCRES, 0x76, RAMT)
ffffffff80e4a540 : CreateDWordField(CRES, 0x82, PCIT)
ffffffff80e4a54b : Add(MLEN(), 0x100000, RAMT)
ffffffff80e4a559 : Subtract(0xffe00000, RAMT, PCIT)
ffffffff80e4a567 : Return(CRES)

Breaking Into the AMLI Debugger

The !amli debugger command causes the AML interpreter to break into the AMLI Debugger the next time any AML code is executed.

Once the AMLI Debugger prompt appears, you can use any of the AMLI Debugger commands. You can also use !amli extension commands without prefixing them with "!amli":

kd> !amli debugger
kd> g

AMLI(? for help)-> find _crs
\_SB.LNKA._CRS
\_SB.LNKB._CRS
\_SB.LNKC._CRS
\_SB.LNKD._CRS
\_SB.PCI0._CRS
\_SB.PCI0.LPC.NCP._CRS
\_SB.PCI0.LPC.PIC._CRS
\_SB.PCI0.LPC.TIME._CRS
\_SB.PCI0.LPC.IDMA._CRS
\_SB.PCI0.LPC.RTC._CRS
\_SB.PCI0.LPC.SPKR._CRS
\_SB.PCI0.LPC.FHUB._CRS
\_SB.PCI0.SBD1._CRS
\_SB.PCI0.SBD2._CRS
\_SB.MBRD._CRS

AMLI(? for help)-> u \_SB.PCI0._CRS

ffffffff80e4a535 : CreateDWordFieldCRES, 0x76, RAMT)
ffffffff80e4a540 : CreateDWordField(CRES, 0x82, PCIT)
ffffffff80e4a54b : Add(MLEN(), 0x100000, RAMT)
ffffffff80e4a559 : Subtract(0xffe00000, RAMT, PCIT)
ffffffff80e4a567 : Return(CRES)

Using Breakpoints

In this example, you wish to break into the AMLI Debugger before the method _BST is executed.

Even if you have located a _BST object, you should verify that it is indeed a method. You can use the !amli dns extension to do this:

kd> !amli dns /s \_sb.pci0.isa.bat1._bst

ACPI Name Space: \_SB.PCI0.ISA.BAT1._BST (c29c2044)
Method(_BST:Flags=0x0,CodeBuff=c29c20a5,Len=103)

Now you can use the !amli bp command to place the breakpoint:

kd> !amli bp \_sb.pci0.isa.bat1._bst

You may also wish to place breakpoints within the method. You could use the !amli u command to disassemble _BST, and then place a breakpoint on one of its steps:

kd> !amli u _sb.pci0.isa.bat1._bst

ffffffffc29c20a5: Acquire(\_SB_.PCI0.ISA_.EC0_.MUT1, 0xffff)
ffffffffc29c20c0: Store("CMBatt - _BST.BAT1", Debug)
ffffffffc29c20d7: \_SB_.PCI0.ISA_.EC0_.CPOL()
ffffffffc29c20ee: Release(\_SB_.PCI0.ISA_.EC0_.MUT1)
ffffffffc29c2107: Return(PBST)

kd> !amli bp c29c20ee

Responding to a Triggered Breakpoint

In the following example, the method _WAK is running and then it encounters a breakpoint.

Running \_WAK method
Hit Breakpoint 0.

Use the !amli ln extension to see the nearest method to the current program counter. This example is taken from a Windows 2000 system, so the addresses are shown in 32-bit form:

kd> !amli ln
c29accf5: \_WAK

The !amli lc extension displays all the active contexts:

kd> !amli lc
 Ctxt=c18b6000, ThID=00000000, Flgs=A-QC-W----, pbOp=c29bf8fe, Obj=\_SB.PCI0.ISA.EC0._Q09
*Ctxt=c18b4000, ThID=c15a6618, Flgs=----R-----, pbOp=c29accf5, Obj=\_WAK

This shows that the active contexts are associated with the methods _Q09 and _WAK. The current context is _WAK.

Now you can use the !amli r command to display more details about the current context. From this you can see useful thread and stack information, as well as arguments passed to _WAK and the local data objects.

kd> !amli r
Context=c18b4000*, Queue=00000000, ResList=00000000
ThreadID=c15a6618, Flags=00000010
StackTop=c18b5eec, UsedStackSize=276 bytes, FreeStackSize=7636 bytes
LocalHeap=c18b40c0, CurrentHeap=c18b40c0, UsedHeapSize=88 bytes
Object=\_WAK, Scope=\_WAK, ObjectOwner=c18b4108, SyncLevel=0
AsyncCallBack=ff06b5d0, CallBackData=0, CallBackContext=c99efddc

MethodObject=\_WAK
c18b40e4: Arg0=Integer(:Value=0x00000001[1])
c18b5f3c: Local0=Unknown()
c18b5f54: Local1=Unknown()
c18b5f6c: Local2=Unknown()
c18b5f84: Local3=Unknown()
c18b5f9c: Local4=Unknown()
c18b5fb4: Local5=Unknown()
c18b5fcc: Local6=Unknown()
c18b5fe4: Local7=Unknown()
c18b4040: RetObj=Unknown()

Tracing, Stepping, and Running AML Code

If you want to trace through the code, you can turn on full tracing information by using the !amli set extension as follows:

kd> !amli set spewon verboseon traceon

Now you can step through the AML code, watching the code execute line by line. The p command steps over any function calls. The t command will step into function calls.

AMLI(? for help)-> p

c29bfcb7: Store(\_SB_.PCI0.ISA_.ACAD.CHAC(SEL0=0x10e1)
c29c17b1: {
c29c17b1: | Store(LGreater(And(Arg0=0x10e1,0xf0,)=0xe0,0x80)=0xffffffff,Local0)=0xffffffff

AMLI(? for help)-> p

c29c17bb: | If(LNot(LEqual(Local0=0xffffffff,ACP_=0xffffffff)=0xffffffff)=0x0)
c29c17ce: | {
c29c17ce: | | Return(Zero)
c29c17d0: | }
c29c17d0: },Local1)=0x0

AMLI(? for help)-> t

c29bfcd4: Store(\_SB_.PCI0.ISA_.BAT1.CHBP(SEL0=0x10e1)
c29c293d: {
c29c293d: | Store("CMBatt - CHBP.BAT1",Debug)String(:Str="CMBatt - CHBP.BAT1")="CMBatt - CHBP.BAT1"

You may also run methods from within the AMLI Debugger if you choose. For example, you might evaluate the status of the LNKA device by running its control method _STA:

AMLI(? for help)-> run \_sb.lnka._sta
PCI OpRegion Access on region c29b2268 device c29b2120

\_SB.LNKA._STA completed successfully with object data:
Integer(:Value=0x0000000b[11])


Other ACPI Debugging Extensions

The following extension commands are useful for debugging problems with an ACPI (Advanced Configuration and Power Interface) BIOS:

  • !facs displays a Firmware ACPI Control Structure
  • !fadt displays a Fixed ACPI Description Table
  • !mapic displays an ACPI Multiple APIC Table
  • !nsobj displays an ACPI namespace object
  • !nstree displays a section of the ACPI namespace tree
  • !rsdt displays the ACPI Root System Description Table

You can use !acpikd.help to see a complete list of ACPI-related extensions.

For details on the !amli xxx extensions, see The AMLI Debugger.


Plug and Play Debugging

This section includes:

Extensions for Debugging Plug and Play Drivers

Determining the Status of a Device

Device Node Status Flags

Device Manager Problem Codes

Checking for Resource Conflicts


Extensions for Debugging Plug and Play Drivers

When you debug Plug and Play drivers, you may find the following debugger extensions useful.

!arbiter

Displays the current system resource arbiters. An arbiter is a piece of code that is exposed by the bus driver which arbitrates requests for resources, and attempts to solve the resource conflicts among the devices connected on that bus.

!cmreslist

Displays the CM_RESOURCE_LIST for the specified device object.

You must know the address of the CM Resource List.

Here is an example:

kd> !cmreslist 0xe12576e8

CmResourceList at 0xe12576e8  Version 0.0  Interface 0x1  Bus #0
  Entry 0 - Port (0x1) Device Exclusive (0x1)
    Flags (0x01) - PORT_MEMORY PORT_IO
    Range starts at 0x3f8 for 0x8 bytes
  Entry 1 - Interrupt (0x2) Shared (0x3)
    Flags (0x01) - LATCHED
    Level 0x4, Vector 0x4, Affinity 0xffffffff

This shows that the device with this CM resource list is using I/O Range 3F8-3FF and IRQ 4.

!dcs

This extension is obsolete — its functionality has been subsumed by !pci. See the !pci 100 example later on this page.

!devext

Displays bus-specific device extension information for a variety of devices.

!devnode

Displays information about a node in the device tree.

Device node 0 (zero) is the root of the device tree.

Here is an example:

kd> !devnode 0xff0d4a08

DevNode 0xff0d4a08 for PDO 0xff0d4af0 at level 0
  Parent 0xff0daf48   Sibling 0xff0d4848   Child 0000000000
  InterfaceType 0xffffffff  Bus Number 0xfffffff0
  InstancePath is "Root\*PNP0501\PnPBIOS_2"
  ServiceName is "Serial"
  TargetDeviceNotify List - f 0xff0d4a6c  b 0xff0d4a6c
  Flags (0x6000122b)  DNF_PROCESSED, DNF_STARTED,
                      DNF_ENUMERATED, DNF_MADEUP,
                      DNF_RESOURCE_ASSIGNED, DNF_ADDED,
                      DNF_HAS_BOOT_CONFIG
                      Unknown flags 0x40000000

!devobj

Displays detailed information about a DEVICE_OBJECT.

Here is an example:

kd> !devobj 0xff0d4af0

Device object (ff0d4af0) is for:
 00252d \Driver\PnpManager DriverObject ff0d9030
Current Irp 00000000 RefCount 0 Type 00000004 Flags 00001040AttachedDev ff0b59e0

DevExt ff0d4ba8 DevNode ff0d4a08
Device queue is not busy.

!drivers

Displays memory usage information and a lists each driver that is loaded on the target computer.

!drvobj

Displays detailed information about a DRIVER_OBJECT.

Lists all the device objects created by the specified driver.

Here is an example:

kd> !drvobj serial

Driver object (ff0ba630) is for:
 \Driver\Serial
Driver Extension List: (id , addr)

Device Object list:
ffba3040  ff0b4040  ff0b59e0  ff0b5040

!ecb, !ecd, !ecw

(x86 target computers only) Writes a sequence of values into the PCI configuration space.

ib, iw, id

Reads data from an I/O port.

These three commands are useful for determining whether a certain I/O range is claimed by a device other than the driver being debugged. A byte value of 0xFF at a port indicates the port is not in use.

!ioreslist

Displays the specified IO_RESOURCE_REQUIREMENTS_LIST.

!irp

Displays information about an IRP.

!irpfind

Displays information about all IRPs currently allocated in the target system, or information about those IRPs whose fields match the specified search criteria.

!pci

(x86 target computers only) Displays the current status of the PCI buses and any devices attached to them. It can also display the PCI configuration space.

The following example displays the devices on the primary bus:

kd> !pci
PCI Bus 0
00:0  8086:1237.02  Cmd[0106:.mb..s]  Sts[2280:.....]  Device  Host bridge
0d:0  8086:7000.01  Cmd[0007:imb...]  Sts[0280:.....]  Device  ISA bridge
0d:1  8086:7010.00  Cmd[0005:i.b...]  Sts[0280:.....]  Device  IDE controller
0e:0  1011:0021.01  Cmd[0107:imb..s]  Sts[0280:.....]  PciBridge 0->1-1  PCI-PCI
 bridge
10:0  5333:8811.43  Cmd[0023:im.v..]  Sts[0200:.....]  Device  VGA compatible controller

The following example displays the devices for the secondary bus, with verbose output:

kd> !pci 1 1

PCI Bus 1
08:0  10b7:5900.00  Cmd[0107:imb..s]  Sts[0200:.....]  Device  Ethernet
      cf8:80014000  IntPin:1  IntLine:f  Rom:fa000000  cis:0  cap:0
      IO[0]:fce1

09:0  9004:8178.00  Cmd[0117:imb..s]  Sts[0280:.....]  Device  SCSI controller
      cf8:80014800  IntPin:1  IntLine:f  Rom:fa000000  cis:0  cap:0
      IO[0]:f801       MEM[1]:f9fff000

0b:0  9004:5800.10  Cmd[0116:.mb..s]  Sts[0200:.....]  Device  SubID:9004:8940
1394 host controller
      cf8:80015800  IntPin:1  IntLine:e  Rom:fa000000  cis:0  cap:0
      MEM[0]:f9ffec00

The following example displays the PCI configuration space for the SCSI controller (bus 1, device 9, function 0):

kd> !pci 100 1 9 0
00: 9004    ;VendorID=9004
02: 8178    ;DeviceID=8178
04: 0117    ;Command=SERREnable,MemWriteEnable,BusInitiate,MemSpaceEnable,IOSpac
eEnable
06: 0280    ;Status=FB2BCapable,DEVSELTiming:1
08: 00      ;RevisionID=00
09: 00      ;ProgIF=00 (SCSI bus controller)
0a: 00      ;SubClass=00
0b: 01      ;BaseClass=01 (Mass storage controller)
0c: 08      ;CacheLineSize=Burst8DW
0d: 20      ;LatencyTimer=20
0e: 00      ;HeaderType=00
0f: 00      ;BIST=00
10: 0000f801;BAR0=0000f801
14: f9fff000;BAR1=f9fff000
18: 00000000;BAR2=00000000
1c: 00000000;BAR3=00000000
20: 00000000;BAR4=00000000
24: 00000000;BAR5=00000000
28: 00000000;CBCISPtr=00000000
2c: 0000    ;SubSysVenID=0000
2e: 0000    ;SubSysID=0000
30: fa000000;ROMBAR=fa000000
34: 00000000;Reserved=00000000
38: 00000000;Reserved=00000000
3c: 0f      ;IntLine=0f
3d: 01      ;IntPin=01
3e: 08      ;MinGnt=08
3f: 08      ;MaxLat=08
40: 00001580,00001580,00000000,00000000,00000000,00000000,00000000,00000000
60: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000
80: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000
a0: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000
c0: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000
e0: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000

!pcitree

Displays information on PCI device objects, including child PCI buses and CardBus buses, as well as the devices attached to them.

!pnpevent

Displays the PnP device event queue.

!rellist

Displays a PnP relation list, and any related CM_RESOURCE_LIST and IO_RESOURCE_LIST structures.


Determining the Status of a Device

To display the whole device tree, starting with the root, use !devnode 0 1:

kd> !devnode 0 1

Identify the devnode for which you are searching, either by examining the driver or the bus that exposed it.

The devnode status flags describe the status of the device. For details, see Device Node Status Flags.

In the example for the !devnode command in the Extensions for Debugging Plug and Play Drivers section, the on-board serial device was created by the PnP Manager, so the DNF_MADEUP (0x00000020) flag is set.

The following example shows a device that was created by the PCI bus. This device does not have the DNF_MADEUP flag set:

kd> !devnode 0xff0d1588

DevNode 0xff0d1588 for PDO 0xff0d1030 at level 0x2
  Parent 0xff0d2e28   Sibling 0xff0d14c8   Child 0xff0c8268
  InterfaceType 0xffffffff  Bus Number 0xfffffff0
  InstancePath is "PCI\VEN_9004&DEV_6178\0&70"
  ServiceName is "aic78xx"
  TargetDeviceNotify List - f 0xff0d15ec  b 0xff0d15ec
  Flags (0x6000120b)  DNF_PROCESSED, DNF_STARTED,
                      DNF_ENUMERATED, DNF_RESOURCE_ASSIGNED,
                      DNF_ADDED, DNF_HAS_BOOT_CONFIG
                      Unknown flags 0x40000000
kd> !devobj 0xff0d1030

Device object (ff0d1030) is for:
 NTPNP_PCI0002 \Driver\PCI DriverObject ff0d2830
Current Irp 00000000 RefCount 0 Type 00000022 Flags 00001040AttachedDev ff0ce710

DevExt ff0d10e8 DevNode ff0d1588
Device queue is not busy.

Examples

1. A devnode for a device with insufficient resources:

kd> !devnode 0xff0d06e8 6

DevNode 0xff0d06e8 for PDO 0xff0d07d0 at level 0x3
  Parent 0xff0d1408   Sibling 0000000000   Child 0000000000
  InterfaceType 0xffffffff  Bus Number 0xfffffff0
  InstancePath is "ISAPNP\SUP2171\00000067"
  ServiceName is "Modem"
  TargetDeviceNotify List - f 0xff0d074c  b 0xff0d074c
  Flags (0x60001109)  DNF_PROCESSED, DNF_ENUMERATED,
                      DNF_INSUFFICIENT_RESOURCES, DNF_ADDED,
                      DNF_HAS_BOOT_CONFIG
                      Unknown flags 0x40000000

  IoResList at 0xe133e7a8 : Interface 0x1  Bus 0  Slot 0
    Alternative 0 (Version 1.1)
      Preferred Descriptor 0 - NonArbitrated/ConfigData (0x80) Shared (0x3)
        Flags (0000) -
        Data:              : 0x0 0x61004d 0x680063
      Preferred Descriptor 1 - Port (0x1) Undetermined Sharing (0)
        Flags (0x11) - PORT_IO 16_BIT_DECODE
        0x000008 byte range with alignment 0x000001
        2f8 - 0x2ff
      Preferred Descriptor 2 - Interrupt (0x2) Shared (0x3)
        Flags (0x01) - LATCHED
        0x3 - 0x3

Note that the devnode has no CM Resource List because it is not started and not using resources, although it has requested resources.

2. Note that there are no resources stored in this devnode for a legacy driver.

kd> !devnode 0xff0d1648 6

DevNode 0xff0d1648 for PDO 0xff0d22d0 at level 0x2
  Parent 0xff0d2e28   Sibling 0xff0d1588   Child 0000000000
  InterfaceType 0xffffffff  Bus Number 0xffffffff
  InstancePath is "PCI\VEN_102B&DEV_0519\0&60"
  ServiceName is "mga_mil"
  TargetDeviceNotify List - f 0xff0d16ac  b 0xff0d16ac
  Flags (0x6000500b)  DNF_PROCESSED, DNF_STARTED,
                      DNF_ENUMERATED, DNF_ADDED,
                      DNF_LEGACY_DRIVER, DNF_HAS_BOOT_CONFIG
                      Unknown flags 0x40000000

You can retrieve the device object list for the driver for the following types of devices:

kd> !drvobj mga_mil

Driver object (ff0bbc10) is for:
 \Driver\mga_mil
Driver Extension List: (id , addr)

Device Object list:
ff0bb900

You can then dump the data for this device object:

kd> !devobj ff0bb900

Device object (ff0bb900) is for:
 Video0 \Driver\mga_mil DriverObject ff0bbc10
Current Irp 00000000 RefCount 1 Type 00000023 Flags 0000204c
DevExt ff0bb9b8 DevNode ff0bb808
Device queue is not busy.

Finally, you can dump the devnode referred by the device object. This devnode is not linked in the device tree. It represents a "pseudo-devnode" used to claim resources for the legacy device. Note the DNF_RESOURCE_REPORTED flag that indicates the device is a reported detected device.

kd> !devnode ff0bb808 6

DevNode 0xff0bb808 for PDO 0xff0bb900 at level 0xffffffff
  Parent 0xff0daf48   Sibling 0000000000   Child 0000000000
  InterfaceType 0xffffffff  Bus Number 0xffffffff
  TargetDeviceNotify List - f 0xff0bb86c  b 0xff0bb86c
  Flags (0x00000400)  DNF_RESOURCE_REPORTED
  CmResourceList at 0xe12474e8  Version 0.0  Interface 0x5  Bus #0
    Entry 0 - Port (0x1) Shared (0x3)
      Flags (0x01) - PORT_MEMORY PORT_IO
      Range starts at 0x3c0 for 0x10 bytes
    Entry 1 - Port (0x1) Shared (0x3)
      Flags (0x01) - PORT_MEMORY PORT_IO
      Range starts at 0x3d4 for 0x8 bytes
    Entry 2 - Port (0x1) Shared (0x3)
      Flags (0x01) - PORT_MEMORY PORT_IO
      Range starts at 0x3de for 0x2 bytes
    Entry 3 - Memory (0x3) Device Exclusive (0x1)
      Flags (0000) - READ_WRITE
      Range starts at 0x0000000040000000 for 0x4000 bytes
    Entry 4 - Memory (0x3) Device Exclusive (0x1)
      Flags (0000) - READ_WRITE
      Range starts at 0x0000000040800000 for 0x800000 bytes


Device Node Status Flags

The Device Node Status Flags describe the status of a device.

The most important flags are:

DNF_PROCESSED (0x00000001)
Indicates that the registry instance key of the device node was created.
DNF_STARTED (0x00000002)
Indicates that the device was started; that is, its IRP_MN_START_DEVICE request was processed successfully.
DNF_START_FAILED (0x00000004)
Indicates that the device failed the start request, however, the I/O Manager supplied the device with resources and attempted to start it.
DNF_ENUMERATED (0x00000008)
Indicates that the PDO for this device was exposed by its parent.
DNF_DELETED (0x00000010)
Indicates that the device was removed.
DNF_MADEUP (0x00000020)
Indicates that the PDO was created and is owned by the PnP Manager (as opposed to being created by a bus driver).
DNF_START_REQUEST_PENDING (0x00000040)
Indicates that the device is in the process of being started.
DNF_NO_RESOURCE_REQUIRED (0x00000080)
Indicates that the device does not require resources.
DNF_INSUFFICIENT_RESOURCES (0x00000100)
Indicates that the device was not started because there were no resources available. Use the procedures in described in the following section to identify the resource conflict.
DNF_RESOURCE_ASSIGNED (0x000200)
Indicates that the resources are assigned by the PnP Manager.
DNF_RESOURCE_REPORTED (0x00000400)
Indicates that a legacy driver reported its resources to the PnP Manager, rather than letting the PnP Manager assign the resources.
DNF_ADDED ( 0x00001000)
Indicates that the device has been added to the system. (The PnP Manager called the AddDevice routine for the device's function and filter driver, if any, and whether these routines completed successfully.)
DNF_ADD_FAILED (0x00002000)
Indicates that the Addroutine failed. Reasons for the failure may include: a driver's AddDevice routine returned an error; there is no service listed for the device in the registry; there is more than one service listed; or the controlling driver could not be loaded.
DNF_LEGACY_DRIVER (0x00004000)
Indicates that the device's controlling driver is a non-PnP driver.
DNF_STOPPED( 0x00008000)
Indicates that the device is currently stopped for reconfiguration of its resources.
DNF_WILL_BE_REMOVED (0x00010000)
Corresponds to the user-mode CM_PROB_WILL_BE_REMOVED problem value and the DN_WILL_BE_REMOVED status flag. Set by user mode only, after the user uninstalled a device ("Remove" in Device Manager).
DNF_NEED_TO_ENUM (0x00020000)
Corresponds to the user-mode DN_NEED_TO_ENUM status flag. Set by user mode only.
DNF_NOT_CONFIGURED(0x00040000)
Corresponds to the user-mode CM_PROB_NOT_CONFIGURED problem value. Set for a device that was enumerated, but needs to be installed. The device was not previously installed.
DNF_REINSTALL (0x00080000)
Corresponds to the user-mode CM_PROB_NOT_REINSTALL problem value. Set for a device that was enumerated, but needs to be installed, The device was previously installed.
DNF_DISABLED(0x00200000)
Corresponds to the user-mode CM_PROB_DISABLED problem value.
DNF_RESTART_OK (0x00400000)
Set when user mode initiates a remove; will be followed by a re-enumeration to bring it back on line.
DNF_NEED_RESTART (0x00800000)
Set when user mode informs the kernel that a reboot is required for this device.
DNF_VISITED (0x01000000)
A temporary flag while walking the device tree. Currently used by the device ejection and removal code.
DNF_ASSIGNING_RESOURCES(0x02000000)
Indicates that device resources are being assigned, but the assignment has not been completed.
DNF_BEING_ENUMERATED(0x04000000)
Indicates that the device is being enumerated.
DNF_NEED_ENUMERATION_ONLY(0x08000000)
Indicates that the reported detected devices are considered started.
DNF_LOCKED(0x10000000)
A temporary flag that is used while device nodes are locked for removal.
DNF_HAS_BOOT_CONFIG(0x20000000)
Indicates that the device has resources assigned by the BIOS. This is not truly started (it is considered "pseudo-started").
DNF_BOOT_CONFIG_RESERVED (0x40000000)
Indicates that the BOOT resources of the device are reserved.


Device Manager Problem Codes

The Device Manager marks a device with a yellow exclamation mark (!) when the device has a problem. The problem codes are in the form "CM_PROB_XXX" and are defined in the header file cfg.h. The most important are explained below, together with their mapping to the Device Node Status Flags.

Code 1 (CM_PROB_NOT_CONFIGURED)
Indicates that the device is not installed and was not installed previously. (Corresponds to DNF_NOT_CONFIGURED.)
Code 10 (CM_PROB_FAILED_START)
Indicates that the device did not start for some reason, but the I/O Manager attempted to start it with a set of resources. (Corresponds to DNF_START_FAILED.)
Code 12 (CM_PROB_NORMAL_CONFLICT)
Indicates that there were not sufficient resources to start this device. (Corresponds to DNF_INSUFFICIENT_RESOURCES.)
Code 14 (CM_PROB_NEED_RESTART)
Indicates that user mode reconfigured the device and a reboot is required for the changes to take effect. (Corresponds to DNF_NEED_RESTART.)
Code 18 (CM_PROB_REINSTALL)
Indicates that the device needs to be installed and was installed previously. (Corresponds to DNF_REINSTALL.)
Code 21 (CM_PROB_WILL_BE_REMOVED)
Indicates that the user mode uninstalled this device. (Corresponds to DNF_WILL_BE_REMOVED.)
Code 22 (CM_PROB_DISABLED)
Indicates that the device is disabled. (Corresponds to DNF_DISABLED.)
Code 28 (CM_PROB_FAILED_INSTALL)
Indicates that the installation failed and there is no driver selected for this device, however, the kernel did not report a problem (and there is no DNF_XXX match for this the problem). This problem can be the result of an on-board system device (ISA timer, ISA RTC, RAM Memory, and so forth) that does not yet have an INF file.
Code 31 (CM_FAILED_ADD)
Indicates that the device was not added. Reasons for the failure may include: a driver's AddDevice routine returned an error; there is no service listed for the device in the registry; there is more than one service listed; or the controlling driver could not be loaded. (Corresponds to DNF_ADD_FAILED.)


Checking for Resource Conflicts

This section discusses techniques that can be used to detect resource conflicts.

The first technique involves dumping the arbiter data. The following example examines the arbiter data for the I/O ranges:

kd> !arbiter 1

DEVNODE ff0daf48
  Port Arbiter "RootPort" at 8045b920
    Allocated ranges:
      10 - 1f S         Owner ff0d6b30
      22 - 3f S         Owner ff0d6b30
      44 - 47 S         Owner ff0d6b30
      4c - 6f S         Owner ff0d6b30
      72 - 7f S         Owner ff0d6b30
      90 - 91 S         Owner ff0d6b30
      93 - 9f S         Owner ff0d6b30
      a2 - bf S         Owner ff0d6b30
      d0 - ef S         Owner ff0d6b30
      100 - 2f7 S       Owner ff0d6b30
      300 - cf7 S       Owner ff0d6b30
      d00 - ffff S      Owner ff0d6b30
    Possible allocation:
      < none >

    DEVNODE ff0d2e28 (PCI_HAL\PNP0A03\0)
      Port Arbiter "PCI I/O Port (b=00)" at e122c2c8
        Allocated ranges:
          0 - f         Owner 00000000
          20 - 21       Owner 00000000
          40 - 43       Owner 00000000
          48 - 4b       Owner 00000000
          60 - 60       Owner ff0d4030
          64 - 64       Owner ff0d4030
          70 - 71       Owner 00000000
          80 - 8f       Owner 00000000
          92 - 92       Owner 00000000
          a0 - a1       Owner 00000000
          c0 - cf       Owner 00000000
          f0 - ff       Owner 00000000
          170 - 177     Owner ff0cf030
          1ce - 1cf S   Owner ff040040
          2f8 - 2ff     Owner 00000000
          376 - 376     Owner ff0cf030
          378 - 37f     Owner ff0d4e70
          3b0 - 3bb S   Owner ff040040
          3c0 - 3cf S   Owner ff0bb900
          3c0 - 3df S   Owner ff040040
          3d4 - 3db S   Owner ff0bb900
          3de - 3df S   Owner ff0bb900
          3ec - 3ef     Owner ff0d0b50 (This device conlicts with another device, see below)
          3f2 - 3f5     Owner ff0d4770
          3f7 - 3f7 S   Owner ff0d4770
          3f8 - 3ff     Owner ff0d4af0
          778 - 77b     Owner ff0d4e70
          cf8 - cff     Owner 00000000
          1000 - 10ff           Owner ff0d1030
          1400 - 140f           Owner ff0d1d30
          1410 - 141f           Owner ff0d1890
          10000 - ffffffffffffffff      Owner 00000000
        Possible allocation:
          < none >

Note that there are two arbiters: one located in the root of the device tree, and one in PCI_HAL. Also note that the PCI arbiter claims and pre-allocates ranges for the devices it arbitrates (0xD000-0xFFFF, which is later suballocated by the PCI arbiter for its devices). The "Owner" field indicates the device object that owns the range. A value of 0 for Owner indicates that the range is not on the bus. In the case of a PCI bridge, for example, all the ranges it does not pass will be assigned to NULL.

In the following example, the PCI bridge passes I/O 0xD000-0xDFFFF so that its arbiter will contain the following two ranges:

0-CFFFF                Owner 00000000
E0000-FFFFFFFFFFFFFFFF   Owner 00000000

The FFFFFFFFFFFFFFFF is because all arbitrated resources are treated as 64-bit ranges.

Examples:

kd> !devobj ff0bb900

Device object (ff0bb900) is for:
 Video0 \Driver\mga_mil DriverObject ff0bbc10
Current Irp 00000000 RefCount 1 Type 00000023 Flags 0000204c
DevExt ff0bb9b8 DevNode ff0bb808
Device queue is not busy.
kd> !devnode ff0bb808

DevNode 0xff0bb808 for PDO 0xff0bb900 at level 0xffffffff
  Parent 0xff0daf48   Sibling 0000000000   Child 0000000000
  InterfaceType 0xffffffff  Bus Number 0xffffffff
  TargetDeviceNotify List - f 0xff0bb86c  b 0xff0bb86c
  Flags (0x00000400)  DNF_RESOURCE_REPORTED
kd> !devnode ff0bb808 6

DevNode 0xff0bb808 for PDO 0xff0bb900 at level 0xffffffff
  Parent 0xff0daf48   Sibling 0000000000   Child 0000000000
  InterfaceType 0xffffffff  Bus Number 0xffffffff
  TargetDeviceNotify List - f 0xff0bb86c  b 0xff0bb86c
  Flags (0x00000400)  DNF_RESOURCE_REPORTED
  CmResourceList at 0xe12474e8  Version 0.0  Interface 0x5  Bus #0
    Entry 0 - Port (0x1) Shared (0x3)
      Flags (0x01) - PORT_MEMORY PORT_IO
      Range starts at 0x3c0 for 0x10 bytes
    Entry 1 - Port (0x1) Shared (0x3)
      Flags (0x01) - PORT_MEMORY PORT_IO
      Range starts at 0x3d4 for 0x8 bytes
    Entry 2 - Port (0x1) Shared (0x3)
      Flags (0x01) - PORT_MEMORY PORT_IO
      Range starts at 0x3de for 0x2 bytes
    Entry 3 - Memory (0x3) Device Exclusive (0x1)
      Flags (0000) - READ_WRITE
      Range starts at 0x0000000040000000 for 0x4000 bytes
    Entry 4 - Memory (0x3) Device Exclusive (0x1)
      Flags (0000) - READ_WRITE
      Range starts at 0x0000000040800000 for 0x800000 bytes

As shown in the example, this operation retrieved the legacy video card that owns the range 3c0-3cf. The same device object is listed near the other ranges it owns (3de-3df and 3d4-3dc). Using the same tracking technique, the range of 3f8-3ff is determined to be that used by the serial port.

A similar technique is required to translate the interrupts:

kd> !arbiter 4

DEVNODE ff0daf48
  Interrupt Arbiter "RootIRQ" at 8045bae0
    Allocated ranges:
      31 - 31           Owner ff0d4030
      34 - 34 S         Owner ff0d4af0
      36 - 36           Owner ff0d4770
      3b - 3b S         Owner ff0d1030
      3b - 3b S         Owner ff0d1d30
      3c - 3c           Owner ff0d3c70
      3f - 3f           Owner ff0cf030
    Possible allocation:
      < none >

Note that there is a single arbiter for interrupts: the root arbiter.

For example, translate the interrupt 3F to an IRQ. First dump the device object, then the devnode:

kd> !devobj ff0cf030

Device object (ff0cf030) is for:
 IdeFdoff0d0398Channel1 \Driver\IntelIde DriverObject ff0d0530
Current Irp 00000000 RefCount 0 Type 00000004 Flags 00001040AttachedDev ff0cd030

DevExt ff0cf0e8 DevNode ff0cfe88
Device queue is not busy.
kd> !devnode ff0cfe88 6

DevNode 0xff0cfe88 for PDO 0xff0cf030 at level 0x3
  Parent 0xff0d1348   Sibling 0000000000   Child 0xff0c84a8
  InterfaceType 0xffffffff  Bus Number 0xfffffff0
  InstancePath is "PCIIDE\IDEChannel\1&1"
  ServiceName is "atapi"
  TargetDeviceNotify List - f 0xff0cfeec  b 0xff0cfeec
  Flags (0x6000120b)  DNF_PROCESSED, DNF_STARTED,
                      DNF_ENUMERATED, DNF_RESOURCE_ASSIGNED,
                      DNF_ADDED, DNF_HAS_BOOT_CONFIG
                      Unknown flags 0x40000000
  CmResourceList at 0xe12321c8  Version 0.0  Interface 0x1  Bus #0
    Entry 0 - Port (0x1) Device Exclusive (0x1)
      Flags (0x01) - PORT_MEMORY PORT_IO
      Range starts at 0x170 for 0x8 bytes
    Entry 1 - Port (0x1) Device Exclusive (0x1)
      Flags (0x01) - PORT_MEMORY PORT_IO
      Range starts at 0x376 for 0x1 bytes
    Entry 2 - Interrupt (0x2) Device Exclusive (0x1)
      Flags (0x01) - LATCHED
      Level 0xf, Vector 0xf, Affinity 0xffffffff

  IoResList at 0xe12363c8 : Interface 0x1  Bus 0  Slot 0
  Reserved Values = {0x0002e0d0, 0x00920092, 0xe1235508}
    Alternative 0 (Version 1.1)
      Preferred Descriptor 0 - NonArbitrated/ConfigData (0x80) Shared (0x3)
        Flags (0000) -
        Data:              : 0x1 0x61004d 0x680063
      Preferred Descriptor 1 - Port (0x1) Device Exclusive (0x1)
        Flags (0x01) - PORT_IO
        0x000008 byte range with alignment 0x000001
        170 - 0x177
      Preferred Descriptor 2 - Port (0x1) Device Exclusive (0x1)
        Flags (0x01) - PORT_IO
        0x000001 byte range with alignment 0x000001
        376 - 0x376
      Preferred Descriptor 3 - Interrupt (0x2) Device Exclusive (0x1)
        Flags (0x01) - LATCHED
        0xf - 0xf
    Alternative 1 (Version 1.1)
      Preferred Descriptor 0 - Port (0x1) Device Exclusive (0x1)
        Flags (0x01) - PORT_IO
        0x000008 byte range with alignment 0x000001
        170 - 0x177
      Preferred Descriptor 1 - Port (0x1) Device Exclusive (0x1)
        Flags (0x01) - PORT_IO
        0x000001 byte range with alignment 0x000001
        376 - 0x376
      Preferred Descriptor 2 - Interrupt (0x2) Device Exclusive (0x1)
        Flags (0x01) - LATCHED
        0xf - 0xf

For example, try to determine if there is a resource conflict that caused this device not to start, starting with a devnode:

kd> !devnode 0xff0d4bc8 6

DevNode 0xff0d4bc8 for PDO 0xff0d4cb0 at level 0
  Parent 0xff0daf48   Sibling 0xff0d4a08   Child 0000000000
  InterfaceType 0xffffffff  Bus Number 0xffffffff
  InstancePath is "Root\*PNP0501\1_0_17_2_0_0"
  ServiceName is "Serial"
  TargetDeviceNotify List - f 0xff0d4c2c  b 0xff0d4c2c
  Flags (0x60001129)  DNF_PROCESSED, DNF_ENUMERATED,
                      DNF_MADEUP, DNF_INSUFFICIENT_RESOURCES,
                      DNF_ADDED, DNF_HAS_BOOT_CONFIG
                      Unknown flags 0x40000000

  IoResList at 0xe1251e28 : Interface 0x1  Bus 0  Slot 0
  Reserved Values = {0x0043005c, 0x006e006f, 0x00720074}
    Alternative 0 (Version 1.1)
      Preferred Descriptor 0 - NonArbitrated/ConfigData (0x80) Undetermined Shar
ing (0)
        Flags (0000) -
        Data:              : 0xc000 0x0 0x0
      Preferred Descriptor 1 - Port (0x1) Undetermined Sharing (0)
        Flags (0x05) - PORT_IO 10_BIT_DECODE
        0x000008 byte range with alignment 0x000001
        3e8 - 0x3ef
      Preferred Descriptor 2 - Interrupt (0x2) Shared (0x3)
        Flags (0x01) - LATCHED
        0x5 - 0x5
    Alternative 1 (Version 1.1)
      Preferred Descriptor 0 - NonArbitrated/ConfigData (0x80) Undetermined Shar
ing (0)
        Flags (0000) -
        Data:              : 0xc000 0x0 0x0
      Preferred Descriptor 1 - Port (0x1) Undetermined Sharing (0)
        Flags (0x05) - PORT_IO 10_BIT_DECODE
        0x000008 byte range with alignment 0x000008
        3e8 - 0x3ef
      Preferred Descriptor 2 - Interrupt (0x2) Shared (0x3)
        Flags (0x01) - LATCHED
        0x5 - 0x5

First, make the assumtion that this is an I/O conflict and dump the arbiters (see the preceding example). The result shows that the range 0x3EC-0x3EF is owned by 0xFF0D0B50, which overlaps the serial device's resources request. Next, dump the device object for the owner of this range, and then dump the devnode for the owner:

kd> !devobj ff0d0b50

Device object (ff0d0b50) is for:
 Resource00413e \Driver\isapnp DriverObject ff0d0e10
Current Irp 00000000 RefCount 0 Type 00000004 Flags 00001040
DevExt ff0d0c08 DevNode ff0d0a68
Device queue is not busy.
kd> !devnode ff0d0a68 6

DevNode 0xff0d0a68 for PDO 0xff0d0b50 at level 0xffffffff
  Parent 0xff0daf48   Sibling 0000000000   Child 0000000000
  InterfaceType 0xffffffff  Bus Number 0xffffffff
Duplicate PDO 0xff0d0e10  TargetDeviceNotify List - f 0xff0d0acc  b 0xff0d0acc
  Flags (0x00000421)  DNF_PROCESSED, DNF_MADEUP,
                      DNF_RESOURCE_REPORTED
  CmResourceList at 0xe1233628  Version 0.0  Interface 0x1  Bus #0
    Entry 0 - Port (0x1) Device Exclusive (0x1)
      Flags (0x01) - PORT_MEMORY PORT_IO
      Range starts at 0x3ec for 0x4 bytes

This is a "pseudo-devnode" that corresponds to the range allocated by the ISAPNP driver for its read data port.

To determine the resources which the PnP Manager assigned to a particular device when it attempted to start the device:

  1. Place a breakpoint on the routine that is called when the IRP_MN_START_DEVICE request is received by the driver. You can also place a breakpoint on the driver's dispatch routine (if you know its name). In both cases, the driver and its symbols should be loaded. This may require you to set an initial breakpoint.

    For example, for PCMCIA you can set a breakpoint on pcmcia!pcmciastartpccard. The advantage of using this particular routine is that its second parameter is a CM Resource List which you can dump using !cmreslist (eliminating step 3). See the following PCMCIA example.

  2. When you have determined which device is of interest, dump the device object (if you have not done so already), and then dump the devnode with the CM Resource List. Check which resources were assigned to the device. You may also check whether the resources are a subset of the I/O Resource List. Then type g or single step through the procedure, and determine whether the device was started and which resources were assigned. If a device was offered a set of resources to start, but failed to do so, the driver might not be behaving properly (for example, if it incorrectly declared that it can use a set of resources it cannot actually use).

Example:

ntoskrnl!IopStartDevice:
80420212 55               push    ebp
kd> kb
ChildEBP RetAddr  Args to Child
f64138c0 8048b640 ff0ce870 ff0d7c08 ff0cde88 ntoskrnl!IopStartDevice (!devobj ff0ce870)
f64138f0 8048d8e7 ff0cde88 f6413978 ff0cddc8 ntoskrnl!IopStartAndEnumerateDevice
+0x1a
f6413900 8048de7f ff0cde88 f6413978 ff0cf448 ntoskrnl!IopProcessStartDevicesWork
er+0x43
f6413910 8048d8d5 ff0cf448 8048d8a4 f6413978 ntoskrnl!IopForAllChildDeviceNodes+
0x1f
f6413924 8048de7f ff0cf448 f6413978 ff0d3f48 ntoskrnl!IopProcessStartDevicesWork
er+0x31
f6413934 8048d8d5 ff0d3f48 8048d8a4 f6413978 ntoskrnl!IopForAllChildDeviceNodes+
0x1f
f6413948 8048d893 ff0d3f48 f6413978 e12052e8 ntoskrnl!IopProcessStartDevicesWork
er+0x31
f641395c 804f6f1b ff0d7c08 f6413978 8045c520 ntoskrnl!IopProcessStartDevices+0x1
f
f64139d0 804f5cc1 80088000 f6413aec 8045bba0 ntoskrnl!IopInitializeBootDrivers+0
x2f9
f6413b24 804f4db3 80088000 00000001 00000000 ntoskrnl!IoInitSystem+0x3a6
f6413da8 80447610 80088000 00000000 00000000 ntoskrnl!Phase1Initialization+0x6a3

f6413ddc 8045375a 804f4710 80088000 00000000 ntoskrnl!PspSystemThreadStartup+0x5
4
00000000 00000000 00000000 00000000 00000000 ntoskrnl!KiThreadStartup+0x16
kd> !devobj ff0ce870

Device object (ff0ce870) is for:
 NTPNP_PCI0002 \Driver\PCI DriverObject ff0ceef0
Current Irp 00000000 RefCount 0 Type 00000022 Flags 00001040AttachedDev ff0cb9e0

DevExt ff0ce928 DevNode ff0cde88
Device queue is not busy.
kd> !devnode ff0cde88 6

DevNode 0xff0cde88 for PDO 0xff0ce870 at level 0x2
  Parent 0xff0cf448   Sibling 0xff0cddc8   Child 0000000000
  InterfaceType 0xffffffff  Bus Number 0xffffffff
  InstancePath is "PCI\VEN_8086&DEV_7010\0&69"
  ServiceName is "intelide"
  TargetDeviceNotify List - f 0xff0cdeec  b 0xff0cdeec
  Flags (0x00001209)  DNF_PROCESSED, DNF_ENUMERATED,
                      DNF_RESOURCE_ASSIGNED, DNF_ADDED
                      (note that the device is not yet started)
  CmResourceList at 0xe120fce8  Version 0.0  Interface 0x5  Bus #0
    Entry 0 - Port (0x1) Device Exclusive (0x1)
      Flags (0x01) - PORT_MEMORY PORT_IO
      Range starts at 0xfff0 for 0x10 bytes (these are the resources used: 0xfff0-0xffff)
    Entry 1 - DevicePrivate (0x81) Device Exclusive (0x1)
      Flags (0000) -
      Data - {0x00000001, 0x00000004, 0000000000}

  IoResList at 0xe120df88 : Interface 0x5  Bus 0  Slot 0x2d
    Alternative 0 (Version 1.1)
      Descriptor 0 - Port (0x1) Device Exclusive (0x1)
        Flags (0x01) - PORT_IO
        0x000010 byte range with alignment 0x000010
        0 - 0xffff     (it could have used any 16 bytes that are 16-byte aligned between 0 and 0xffff)
      Descriptor 1 - DevicePrivate (0x81) Device Exclusive (0x1)
        Flags (0000) -
        Data:              : 0x1 0x4 0x0

Example for PCMCIA:

kd> bp pcmcia!pcmciastartpccard
Loading symbols for 0x8039d000       pcmcia.sys ->   pcmcia.sys
kd> kb
Loading symbols for 0x80241000         ndis.sys ->   ndis.sys
ChildEBP RetAddr  Args to Child
f6413814 803a7cbd ff0d0c30 e11d8808 ff0d0c30 pcmcia!PcmciaStartPcCard
f6413838 803a3798 ff0d0c30 ff0d1500 ff0d1588 pcmcia!PcmciaPdoPnpDispatch+0x169
f6413848 80418641 ff0d0c30 ff0d1588 00000000 pcmcia!PcmciaDispatch+0x3a
f641385c 802455cf ff0d1614 ff0d1638 00040000 ntoskrnl!IofCallDriver+0x35
f641387c 802497cf ff0d1588 ff0d0c30 ff0c8210 NDIS!ndisPassIrpDownTheStack+0x3b
f64138ac 80418641 ff0c8210 ff0d161c ff0d1640 NDIS!ndisPnPDispatch+0x1f9
f64138c0 8048de68 ff0c3508 ff0d16a8 00000000 ntoskrnl!IofCallDriver+0x35
f64138d4 8041ff5e ff0c8210 f64138f8 ff0c3508 ntoskrnl!IopAsynchronousCall+0x90
f6413920 8048b4ae ff0d0c30 ff0e0a68 ff0d16a8 ntoskrnl!IopStartDevice+0x76
f6413950 8048d707 ff0d16a8 f64139fc 00000000 ntoskrnl!IopStartAndEnumerateDevice+0x1a
f6413960 8048dc9f ff0d16a8 f64139fc ff0d1e88 ntoskrnl!IopProcessStartDevicesWorker+0x43
f6413970 8048d6f5 ff0d1e88 8048d6c4 f64139fc ntoskrnl!IopForAllChildDeviceNodes+0x1f
f6413984 8048dc9f ff0d1e88 f64139fc ff0d3268 ntoskrnl!IopProcessStartDevicesWorker+0x31
f6413994 8048d6f5 ff0d3268 8048d6c4 f64139fc ntoskrnl!IopForAllChildDeviceNodes+0x1f
f64139a8 8048dc9f ff0d3268 f64139fc ff0d7b28 ntoskrnl!IopProcessStartDevicesWorker+0x31
f64139b8 8048d6f5 ff0d7b28 8048d6c4 f64139fc ntoskrnl!IopForAllChildDeviceNodes+0x1f
f64139cc 8048d6b3 ff0d7b28 f64139fc 80087000 ntoskrnl!IopProcessStartDevicesWorker+0x31
f64139e0 804f6c97 ff0e0a68 f64139fc 8045c140 ntoskrnl!IopProcessStartDevices+0x1f
f6413a30 804f5601 000001e0 80087000 00000000 ntoskrnl!IopInitializeSystemDrivers+0x5b
f6413b7c 804f4820 80087000 00000001 00000000 ntoskrnl!IoInitSystem+0x3fe
kd> !cmreslist e11d8808

CmResourceList at 0xe11d8808  Version 0.0  Interface 0x1  Bus #0
  Entry 0 - Interrupt (0x2) Device Exclusive (0x1)
    Flags (0x01) - LATCHED
    Level 0x9, Vector 0x9, Affinity 0xffffffff
  Entry 1 - Port (0x1) Device Exclusive (0x1)
    Flags (0x01) - PORT_MEMORY PORT_IO
    Range starts at 0xdfe0 for 0x20 bytes (started with IRQ 9, IO dfe0-dfff)
  Entry 2 - DevicePrivate (0x81) Device Exclusive (0x1)
    Flags (0000) -
    Data - {0x00010120, 0000000000, 0000000000}

kd> g


Advanced Debugging Techniques

This section includes:

Debugging a Stalled System

Debugging Timeouts

Debugging a Stack Overflow

Debugging a Failed Driver Unload

Reading Bug Check Callback Data

Debugging Windows Setup and the OS Loader

Debugging Dual-Boot Machines

Debugging CSRSS with NTSD

Debugging WinLogon with NTSD

Debugging Service Applications with WinDbg

Debugging User-Mode Failures with KD


Debugging a Stalled System

There are times that the computer can freeze without actually initiating a bug check. This freeze can take a variety of forms:

  1. The mouse pointer can be moved, but cannot affect any windows on the screen
  2. The entire screen is still and the mouse pointer does not move, but paging continues between the memory and the disk
  3. The screen is still and the disk is silent

If the mouse pointer moves or there is paging to the disk, this is usually due to a problem within CSRSS.

If NTSD is running on CSRSS, press F12 and dump out each thread to see if there is anything strange. (See Debugging CSRSS with NTSD for more details.)

If an examination of CSRSS reveals nothing, then the problem may be with the kernel after all.

If there is no mouse movement or paging, then it is almost certainly a kernel problem.

Analyzing a kernel crash of this sort is a difficult business. Start by breaking into KD (with CTRL+C) or WinDbg (with CTRL+BREAK). You can now use the debugger commands to examine the situation.

Some useful techniques in this case include:

Finding the Failed Process

Debugging Pending IRPs


Finding the Failed Process

The !process extension will show you the currently running process.

The parts of the process dump that are most interesting are:

  • The times (a high value means that process might be the culprit)
  • The handle count (this is the number in parentheses after the ObjectTable in the first line)
  • The thread status (many processes have multiple threads). If the current process is Idle, chances are the machine is either truly idle or hung due to some unusual problem.

Although using the !process 0 7 extension is the best way to find the problem on a hung system, it is sometimes too much information to filter. It would be worthwhile to first do a !process 0 0 and do a !process on the process handle for CSRSS and any other suspicious processes.

When using a !process 0 7, many of the threads might say "kernel stack not resident" because those stacks are paged-out. If those pages are still in the cache in transition, you can get more information by using a .cache decodeptes before !process 0 7:

kd> .cache decodeptes
kd> !process 0 7

If the guilty process can be identified, use !process <process> 7 to show the kernel stacks for each thread in the process. This can indicate what the problem could be in kernel mode and what the suspect process is calling.

Apart from !process, there are several other extensions which help track down the causes for hung machines:

Extension | Effect
!ready | Identifies the threads that are ready to run in order of priority.
!kdext*.locks | Identifies any held resource locks, in case it is a deadlock with retail timeouts.
!vm | Checks the virtual memory usage.
!poolused | Checks to see if any one type of pool allocation is huge (pool tagging required).
!memusage | Checks the physical memory status.
!heap | Checks the validity of the heap.
!irpfind | Searches nonpaged pool for active IRPs.

If none of these point you to anything strange, try setting a breakpoint at ntoskrnl!KiSwapThread to see if you are stuck in one process or if you're still scheduling other processes. If you are not stuck, you could try setting some breakpoints in common functions like NtReadFile to see if things are getting stuck down a specific code path.


Debugging Pending IRPs

There are a number of possible causes of a stalled system. Here is an example of some techniques which can be used to identify the cause.

An IRP that was never completed can cause serious problems.

When the machine hangs, break in using a kernel debugger. Look for pending IRPs (using !irpfind).

Use the !irp extension to obtain details about any pending IRPs:

kd> !irp 81183468
Irp is active with 2 stacks 2 is current (= 0x811834fc)
 No Mdl Thread 00000000:  Irp stack trace.
     cmd  flg cl Device   File     Completion-Context
 [  0, 0]   0  0 8145f470 00000000 00000000-00000000
               \Driver\E100B
                        Args: 00000000 00000000 00000000 00000000
>[ 16, 2]   0 e1 8145f470 00000000 8047f744-814187a8 Success Error Cancel pending
               \Driver\E100B    ntoskrnl!PopCompleteSystemPowerIrp
                        Args: 00000000 00000000 00000002 00000002

This shows that \driver\e100b has not returned the IRP for ntoskrnl!PopCompleteSystemPowerIrp, and it looks stuck.

Get a stack trace using the kb command:

kd> kb
ChildEBP RetAddr  Args to Child
f714ee68 8046355a 00000001 80068c10 00000030 ntoskrnl!RtlpBreakWithStatusInstruction
f714ee68 80067a4f 00000001 80068c10 00000030 ntoskrnl!KeUpdateSystemTime+0x13e
f714eeec 8046380b 01001010 0000003b f714ef00 halacpi!HalBeginSystemInterrupt+0x83
f714eeec 80463c50 01001010 0000003b f714ef00 ntoskrnl!KiChainedDispatch+0x1b
f714ef78 80067cc2 00000000 00000240 8000017c ntoskrnl!KiDispatchInterrupt
f714ef78 80501cb5 00000000 00000240 8000017c halacpi!HalpDispatchInterrupt2ndEnt

Notice the section in bold: this is an interrupt dispatch. If you use the g command and break in again, you will very likely see a different stack trace, but you will still see an interrupt dispatch.

The system is running the ISR for the video card. The system will run the ISR for all of the devices sharing IRQ 0xB. If no process claims the interrupt, the operating system will wait infinitely, requesting the driver ISRs to handle the interrupt. It is also possible that a process might handle the interrupt and stop it, but if the hardware is broken the interrupt may simply be re-asserted.

A second stack trace gives:

kd> kb
ChildEBP RetAddr  Args to Child
f714ee24 8046355a 00000001 00000010 00000030 ntoskrnl!RtlpBreakWithStatusInstruction
f714ee24 bfe854b9 00000001 00000010 00000030 ntoskrnl!KeUpdateSystemTime+0x13e
f714eed8 f7051796 00000000 80463850 8143ec88 atimpab!AtiInterrupt+0x109
f714eee0 80463850 8143ec88 81444038 8046380b VIDEOPRT!pVideoPortInterrupt+0x16
f714eef8 80463818 00000202 0000003b 80450bb8 ntoskrnl!KiChainedDispatch2ndLvl+0x28
f714eef8 80463c50 00000202 0000003b 80450bb8 ntoskrnl!KiChainedDispatch+0x28
f714ef78 80067cc2 00000000 00000240 8000017c ntoskrnl!KiDispatchInterrupt
f714ef78 80501cb5 00000000 00000240 8000017c halacpi!HalpDispatchInterrupt2ndEntry+0x1b
f714f084 8045f744 f714f16c 00020019 f714f148 ntoskrnl!NtCreateKey+0x113
f714f084 8042e487 f714f16c 00020019 f714f148 ntoskrnl!KiSystemService+0xc4
f714f118 804ab556 f714f16c 00020019 f714f148 ntoskrnl!ZwCreateKey+0xb
f714f184 8041f75b f714f1e8 8000017c f714f1d0 ntoskrnl!IopCreateRegistryKeyEx+0x4e
f714f204 804965cd 8145f630 00000000 00000001 ntoskrnl!IopProcessSetInterfaceState+0x93
f714f220 bfee1eb9 8145f630 00000000 8145f5a0 ntoskrnl!IoSetDeviceInterfaceState+0x2b
f714f254 bfedb416 00000004 00000800 0045f570 NDIS!ndisMCommonHaltMiniport+0x1f
f714f268 bfed4ddb bfed0660 811a2708 811a2708 NDIS!ndisPmHaltMiniport+0x9a
f714f288 bfed5146 811a2708 00000004 8145f570 NDIS!ndisSetPower+0x1d1
f714f2a8 8041c60f 81453a30 811a2708 80475b18 NDIS!ndisPowerDispatch+0x84
f714f2bc 8044cc52 80475b18 811a2708 811a279c ntoskrnl!IopfCallDriver+0x35
f714f2d4 8044cb89 811a279c 811a2708 811a27c0 ntoskrnl!PopPresentIrp+0x62

To determine which interrupt is responsible for the system stall, look at the second parameter passed into HalBeginSystemInterrupt (0x3B, in this case). The standard rule is that the interrupt vector expressed (0x3B) is the IRQ line plus 0x30, so this means the interrupt is number 0xB. Use an !arbiter 4 extension to find out which devices are on IRQ 0xB. If there is only one device there, you have the culprit. If there are more then one device sharing the interrupt (99% of the cases), you'll need to isolate the culprit either by manually programming LNK nodes (which is destructive to the system state), or by removing or disabling hardware.

kd> !arbiter 4
DEVNODE 8149a008 (HTREE\ROOT\0)
  Interrupt Arbiter "RootIRQ" at 80472a20
    Allocated ranges:
      0000000000000000 - 0000000000000000   B   8149acd0
      0000000000000001 - 0000000000000001   B   8149acd0
      0000000000000002 - 0000000000000002   B   8149acd0
      0000000000000003 - 0000000000000003   B   8149acd0
      0000000000000004 - 0000000000000004   B   8149acd0
      0000000000000005 - 0000000000000005   B   8149acd0
      0000000000000006 - 0000000000000006   B   8149acd0
      0000000000000007 - 0000000000000007   B   8149acd0
      0000000000000008 - 0000000000000008   B   8149acd0
      0000000000000009 - 0000000000000009   B   8149acd0
      000000000000000a - 000000000000000a   B   8149acd0
      000000000000000b - 000000000000000b   B   8149acd0
      000000000000000c - 000000000000000c   B   8149acd0
      000000000000000d - 000000000000000d   B   8149acd0
      000000000000000e - 000000000000000e   B   8149acd0
      000000000000000f - 000000000000000f   B   8149acd0
      0000000000000010 - 0000000000000010   B   8149acd0
      0000000000000011 - 0000000000000011   B   8149acd0
      0000000000000012 - 0000000000000012   B   8149acd0
      0000000000000013 - 0000000000000013   B   8149acd0
      0000000000000014 - 0000000000000014   B   8149acd0
      0000000000000015 - 0000000000000015   B   8149acd0
      0000000000000016 - 0000000000000016   B   8149acd0
      0000000000000017 - 0000000000000017   B   8149acd0
      0000000000000018 - 0000000000000018   B   8149acd0
      0000000000000019 - 0000000000000019   B   8149acd0
      000000000000001a - 000000000000001a   B   8149acd0
      000000000000001b - 000000000000001b   B   8149acd0
      000000000000001c - 000000000000001c   B   8149acd0
      000000000000001d - 000000000000001d   B   8149acd0
      000000000000001e - 000000000000001e   B   8149acd0
      000000000000001f - 000000000000001f   B   8149acd0
      0000000000000020 - 0000000000000020   B   8149acd0
      0000000000000021 - 0000000000000021   B   8149acd0
      0000000000000022 - 0000000000000022   B   8149acd0
      0000000000000023 - 0000000000000023   B   8149acd0
      0000000000000024 - 0000000000000024   B   8149acd0
      0000000000000025 - 0000000000000025   B   8149acd0
      0000000000000026 - 0000000000000026   B   8149acd0
      0000000000000027 - 0000000000000027   B   8149acd0
      0000000000000028 - 0000000000000028   B   8149acd0
      0000000000000029 - 0000000000000029   B   8149acd0
      000000000000002a - 000000000000002a   B   8149acd0
      000000000000002b - 000000000000002b   B   8149acd0
      000000000000002c - 000000000000002c   B   8149acd0
      000000000000002d - 000000000000002d   B   8149acd0
      000000000000002e - 000000000000002e   B   8149acd0
      000000000000002f - 000000000000002f   B   8149acd0
      0000000000000032 - 0000000000000032   B   8149acd0
      0000000000000039 - 0000000000000039 S     814776d0  (ACPI)
    Possible allocation:
      < none >

    DEVNODE 81476f28 (ACPI_HAL\PNP0C08\0)
      Interrupt Arbiter "ACPI_IRQ" at bfff10e0
        Allocated ranges:
          0000000000000000 - 0000000000000000   B   81495bb0
          0000000000000001 - 0000000000000001       814952b0  (i8042prt)
          0000000000000003 - 0000000000000003 S     81495610  (Serial)
          0000000000000004 - 0000000000000004   B   8149acd0
          0000000000000006 - 0000000000000006       81495730  (fdc)
          0000000000000008 - 0000000000000008       81495a90
          0000000000000009 - 0000000000000009 S     814776d0  (ACPI)
          000000000000000b - 000000000000000b S
            000000000000000b - 000000000000000b S     81453c30  (ds1)
            000000000000000b - 000000000000000b S     81453a30  (E100B)
            000000000000000b - 000000000000000b S     81493c30  (uhcd)
            000000000000000b - 000000000000000b S     8145c390  (atirage3)
          000000000000000c - 000000000000000c       814953d0  (i8042prt)
          000000000000000d - 000000000000000d   B   81495850
          000000000000000e - 000000000000000e       8145bb50  (atapi)
          000000000000000f - 000000000000000f       8145b970  (atapi)
        Possible allocation:
          < none >

In this case, the audio, Universal Serial Bus (USB), network interface card (NIC), and video are all using the same IRQ.

To find out which ISR claims ownership of the interrupt, examine the return value from the ISR. Simply disassemble the ISR using the U command, and set a breakpoint on the last instruction of the ISR (which will be a 'ret' instruction). Note that using the command g <address> is the equivalent of setting a breakpoint on that address:

kd> g bfe33e7b
ds1wdm!AdapterIsr+ad:
bfe33e7b c20800           ret     0x8
kd> r
eax=00000000 ebx=813f4ff0 ecx=00000010 edx=ffdff848 esi=8145d168 edi=813f4fc8
eip=bfe33e7b esp=f714eec4 ebp=f714eee0 iopl=0         nv up ei pl zr na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000246
ds1wdm!AdapterIsr+ad:
bfe33e7b c20800           ret     0x8

Look at the EAX register. If the portion of the register contents in bold (in the following code example) is anything other then zero, this ISR claimed the interrupt. Otherwise the interrupt was not claimed, and the operating system will call the next ISR.

When you encounter this problem, you should also check to see if each piece of hardware associated with the interrupt is actually enabled. For PCI, this is easy — look at the CMD register displayed by the !pci extension output:

kd> !pci 0 0
PCI Bus 0
00:0  8086:7190.03  Cmd[0006:.mb...]  Sts[2210:c....]  Device  Host bridge
01:0  8086:7191.03  Cmd[0107:imb..s]  Sts[0220:.6...]  PciBridge 0->1-1  PCI-PCI bridge
03:0  1073:000c.03  Cmd[0000:......]  Sts[0210:c....]  Device  SubID:1073:000c Audio device
04:0  8086:1229.05  Cmd[0007:imb...]  Sts[0290:c....]  Device  SubID:8086:0008 Ethernet
07:0  8086:7110.02  Cmd[000f:imb...]  Sts[0280:.....]  Device  ISA bridge
07:1  8086:7111.01  Cmd[0005:i.b...]  Sts[0280:.....]  Device  IDE controller
07:2  8086:7112.01  Cmd[0005:i.b...]  Sts[0280:.....]  Device  USB host controller
07:3  8086:7113.02  Cmd[0003:im....]  Sts[0280:.....]  Device  Class:6:80:0

Note that the audio chip's CMD register is zero. This means the audio chip is effectively disabled at this time. This also means that the audio chip will not be capable of responding to accesses by the driver. Unfortunately, Peripheral Component Interconnect (PCI) Special Interest Group (SIG) doesn't give us a universal method for disabling interrupts (or checking their enable status) through the command register.

In this case, the audio chip needs to be manually re-enabled.


Debugging Timeouts

There are two main timeouts which occur on Windows® systems:

Resource timeouts (kernel mode)

Critical section timeouts (user mode)

In many cases, these problems are simply a matter of a thread taking too long to release a resource or exit a section of code.

On a retail system, the timeout value is set high enough that you would not see the break (a true deadlock would simply hang). The timeout values are set in the registry under HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager in seconds.


Resource Timeouts

During a resource timeout, the thread waiting for the resource will break into the kernel debugger with a message like:

Resource @ 800e99c0
 ActiveCount = 0001  Flags = IsOwnedExclusive sharedWaiter
 NumberOfExclusiveWaiters = 0000
  Thread = 809cd2f0, Count = 01
  Thread = 809ebc50, Count = 01
  Thread = 00000000, Count = 00
  Thread = 00000000, Count = 00
  Thread = 00000000, Count = 00
NT!DbgBreakPoint+0x4:
800cee04: 000000ad callkd

The thread which holds the lock is the first thread listed (or multiple threads if it is owned shared). To examine that thread, use a !thread extension on the thread ID (809cd2f0, in the example above). This will give a stack for the thread owning the resource. If it is also waiting on a resource, ExpWaitForResourceExclusive (or ExpWaitForResourceShared) will be on the stack for that thread.

The first parameter to ExpWaitForResourceXxx is the lock which is being waited on. To find out about that resource, use a !locks <resource id> extension which will give you another thread to check.

If you get to a thread that is not waiting for another resource, that thread is probably the source of the problem. For a list of all held locks, use a !locks extension with no parameter at the kd> prompt.

Example

Resource @ fc664ee0                  //here's the resource lock address

 ActiveCount = 0001  Flags = IsOwnedExclusive ExclusiveWaiter
 NumberOfExclusiveWaiters = 0001
  Thread = ffaf5410, Count = 01                //here's the owning thread
  Thread = 00000000, Count = 00
ntoskrnl!_DbgBreakPoint:
80131400 cc               int     3
kd> kb                                        //start with a stack
ChildEBP RetAddr  Args to Child
fcd44980 801154c0 fc664ee0 ffab45d0 00110001 ntoskrnl!_DbgBreakPoint
fcd4499c 80102521 fc664ee0 ffb08ea8 fcd44a4c ntoskrnl!_ExpWaitForResource+0x114        //lock being waited on...

fcd449e8 fc6509fa e12597c8 fef27c08 fee4fca8 ntoskrnl!_ExAcquireResourceExclusiveLite+0xa5
00380020 00000000 00000000 00000000 00000000 nwrdr!_CreateScb+0x2ff
kd>  !locks fc664ee0                       !locks resource address gives lock info
Resource @ nwrdr!_NwScavengerSpinLock (0xfc664ee0)    Exclusively owned
    Contention Count = 45
    NumberOfExclusiveWaiters = 1
     Threads: ffaf5410-01                  //owning thread again
1 total locks, 1 locks currently held
kd>  !thread ffaf5410                     //check the owning thread

THREAD ffaf5410  Cid e7.e8  Teb: 7ffde000 WAIT: (Executive) KernelMode Non-Alertable
    feecf698  SynchronizationEvent
IRP List:
    fef29208: (0006,00b8) Flags: 00000884  Mdl: feed8328
Not impersonating
Owning Process ffaf5690
WaitTime (seconds)      2781250
Context Switch Count    183175
UserTime                  0:00:23.0153
KernelTime                0:01:01.0187
Start Address 0x77f04644
Initial Sp fec6c000 Current Sp fec6b938
Priority 11 BasePriority 7 PriorityDecrement 0 DecrementCount 8

ChildEBP RetAddr  Args to Child
fec6b950 801044fc feecf668 feecf668 00000080 ntoskrnl!KiSwapContext+0x25
fec6b974 fc655976 feecf698 00000000 00000000 ntoskrnl!_KeWaitForSingleObject+0x218
fec6ba5c fc6509fa e1263968 fef29208 feecf668 nwrdr!_ExchangeWithWait+0x38
fec6ba28 fc6533e5 feecf668 e125b3c8 ffafae08 nwrdr!_CreateScb+0x2ff
fec6bac0 fc652f26 feecf668 fec6bae4 fef29208 nwrdr!_CreateRemoteFile+0x2c9
fec6bb6c fc652b14 feecf668 fef29208 fee50b60 nwrdr!_NwCommonCreate+0x3a2

fec6bbac 80107aea fee50b60 fef29208 804052ac nwrdr!_NwFsdCreate+0x56
fec6bbc0 80142792 fef37700 fec6bdbc fee50b28 ntoskrnl!IofCallDriver+0x38
fec6bd10 80145403 fee50b60 00000000 fec6bdbc ntoskrnl!_IopParseDevice+0x6a0
fec6bd7c 80144c0c 00000000 fec6be34 00000040 ntoskrnl!_ObpLookupObjectName+0x479
fec6be5c 80127803 0012dd64 00000000 80127701 ntoskrnl!_ObOpenObjectByName+0xa2
fec6bef4 801385c3 0012dd64 0012dd3c 00000000 ntoskrnl!_NtQueryAttributesFile+0xc1
fec6bef4 77f716ab 0012dd64 0012dd3c 00000000 ntoskrnl!_KiSystemService+0x83

0012dd20 00000000 00000000 00000000 00000000 ntdll!_ZwQueryAttributesFile+0xb


Critical Section Timeouts

Critical section timeouts can be identified by the stack trace that has RtlpWaitForCriticalSection near the top of the stack. Another variety of critical section timeout is a possible deadlock application error. To debug critical section timeouts properly, CDB or WinDbg is necessary.

Similar to resource timeouts, !locks extension will give a list of locks currently held and the threads which own them. Unlike resource timeouts, the thread IDs given are not immediately useful. These are system IDs which do not map directly to the thread numbers used by CDB.

To map the system thread IDs to CDB thread numbers, use the ~ (tilde) command. This will list all threads currently being debugged and give their thread number, ID, Thread Environment Block (TEB), and state. Just as with ExpWaitForResource Xxx, the lock identifier is the first parameter to RtlpWaitForCriticalSection. Continue tracing the chain of waits until either a loop is found or the final thread is not waiting for a critical section timeout.

Example of Debugging a Critical Timeout

0:024>  kb        start with a stack

ChildEBP RetAddr  Args to Child
0569fca4 77f79c78 77f71000 002a6b88 7fffffff ntdll!_DbgBreakPoint
0569fd04 77f71048 5ffa9f9c 5fef0b4b 5ffa9f9c ntdll!_RtlpWaitForCriticalSection+0x89
0569fd0c 5fef0b4b 5ffa9f9c 002a6b88 002a0019 ntdll!_RtlEnterCriticalSection+0x48
0569fd70 5fedf83f 002a6b88 0569fdc0 0000003e winsrv!_StreamScrollRegion+0x1f0
0569fd8c 5fedfa5b 002a6b88 00190000 00000000 winsrv!_AdjustCursorPosition+0x8e
0569fdc0 5fedf678 0569ff18 0031c200 0335ee88 winsrv!_DoWriteConsole+0x104

0569fefc 5fe6311b 0569ff18 0569ffd0 00000005 winsrv!_SrvWriteConsole+0x96
0569fff4 00000000 00000000 00000024 00000024 csrsrv!_CsrApiRequestThread+0x4ff
0:024>  !locks         //!locks to find the critical section
CritSec winsrv!_ScrollBufferLock at 5ffa9f9c        5ffa9f9c is the first one
LockCount          5
RecursionCount     1
OwningThread       88          //here's the owning thread ID
EntryCount         11c
ContentionCount    135
*** Locked

CritSec winsrv!_gcsUserSrv+0 at 5ffa91b4        //second crit sect found below

LockCount          8
RecursionCount     1
OwningThread       6d         //second owning thread
EntryCount         1d6c
ContentionCount    1d47
*** Locked
0:024>  ~            //tilde to list CDB threads to find thread IDs
  0  id: 16.15   Teb 7ffdd000 Unfrozen
  1  id: 16.13   Teb 7ffdb000 Unfrozen
  2  id: 16.30   Teb 7ffda000 Unfrozen
  3  id: 16.2f   Teb 7ffd9000 Unfrozen
  4  id: 16.2e   Teb 7ffd8000 Unfrozen
  5  id: 16.6c   Teb 7ff6c000 Unfrozen
  6  id: 16.6d   Teb 7ff68000 Unfrozen        //second owning thread ID -> CDB thread 6

  7  id: 16.2d   Teb 7ffd7000 Unfrozen
  8  id: 16.33   Teb 7ffd6000 Unfrozen
  9  id: 16.42   Teb 7ff6f000 Unfrozen
 10  id: 16.6f   Teb 7ff6e000 Unfrozen
 11  id: 16.6e   Teb 7ffd5000 Unfrozen
 12  id: 16.52   Teb 7ff6b000 Unfrozen
 13  id: 16.61   Teb 7ff6a000 Unfrozen
 14  id: 16.7e   Teb 7ff69000 Unfrozen
 15  id: 16.43   Teb 7ff67000 Unfrozen
 16  id: 16.89   Teb 7ff50000 Unfrozen
 17  id: 16.95   Teb 7ff65000 Unfrozen
 18  id: 16.90   Teb 7ff64000 Unfrozen

 19  id: 16.71   Teb 7ff63000 Unfrozen
 20  id: 16.bb   Teb 7ff62000 Unfrozen
 21  id: 16.88   Teb 7ff61000 Unfrozen        //first owning thread ID -> CDB thread 21
 22  id: 16.cd   Teb 7ff5e000 Unfrozen
 23  id: 16.c1   Teb 7ff5f000 Unfrozen
 24  id: 16.bd   Teb 7ff5d000 Unfrozen
0:024>  ~21s        switch to owning thread
ntdll!_ZwWaitForSingleObject+0xb:
77f71bfb c20c00           ret     0xc
0:021>  kb        //get a stack; it's also waiting on a crit sect

ChildEBP RetAddr  Args to Child
0556fc44 77f79c20 00000110 00000000 77fa4700 ntdll!_ZwWaitForSingleObject+0xb
0556fcb0 77f71048 5ffa91b4 5feb4f7e 5ffa91b4 ntdll!_RtlpWaitForCriticalSection+0x31
0556fcb8 5feb4f7e 5ffa91b4 0556fd70 77f71000 ntdll!_RtlEnterCriticalSection+0x48
0556fcf4 5fef0b76 01302005 00000000 fffffff4 winsrv!__ScrollDC+0x14
0556fd70 5fedf83f 002bd880 0556fdc0 00000025 winsrv!_StreamScrollRegion+0x21b
0556fd8c 5fedfa5b 002bd880 00190000 00000000 winsrv!_AdjustCursorPosition+0x8e

0556fdc0 5fedf678 0556ff18 002bdf70 002a4d58 winsrv!_DoWriteConsole+0x104
0556fefc 5fe6311b 0556ff18 0556ffd0 00000005 winsrv!_SrvWriteConsole+0x96
0556fff4 00000000 00000000 00000024 00000024 csrsrv!_CsrApiRequestThread+0x4ff
0:021>  ~6s                   //scroll up to find crit sect and thread number
winsrv!_PtiFromThreadId+0xd:
5fe8429a 394858           cmp     [eax+0x58],ecx    ds:0023:7f504da8=000000f8
0:006>  kb        get the final stack
ChildEBP RetAddr  Args to Child

01ecfeb4 5fecd0d7 00000086 00000000 7f5738e0 winsrv!_PtiFromThreadId+0xd
01ecfed0 5feccf62 00000086 01ecfff4 00000113 winsrv!__GetThreadDesktop+0x12
01ecfefc 5fe6311b 01ecff18 01ecffd0 00000005 winsrv!___GetThreadDesktop+0x8b
01ecfff4 00000000 00000000 00000024 00000024 csrsrv!_CsrApiRequestThread+0x4ff


Debugging a Stack Overflow

A stack overflow is an error that user-mode threads can encounter. There are three possible causes for this error:

  • A thread uses the entire stack reserved for it. This is often caused by infinite recursion.
  • A thread cannot extend the stack because the page file is maxed out, and therefore no additional pages can be committed to extend the stack.
  • A thread cannot extend the stack because the system is within the brief period used to extend the page file.

Here is an example of how to debug this error. In this example, NTSD is running on the same computer as the target application, and is redirecting its output to KD on the host computer. See Controlling the User-Mode Debugger from the Kernel Debugger for details.

The first thing to do is see what event caused the debugger to break in:

0:002> .lastevent
Last event: Exception C00000FD, second chance

You can look up exception code 0xC00000FD in ntstatus.h (which can be found in the Platform SDK and the Windows DDK). This exception code is STATUS_STACK_OVERFLOW.

To double-check that the stack overflowed, you can use the K (Display Stack Backtrace) command:

0:002> k
ChildEBP RetAddr
009fdd0c 71a32520 COMCTL32!_chkstk+0x25
009fde78 77cf8290 COMCTL32!ListView_WndProc+0x4c4
009fde98 77cfd634 USER32!_InternalCallWinProc+0x18
009fdf00 77cd55e9 USER32!UserCallWinProcCheckWow+0x17f
009fdf3c 77cd63b2 USER32!SendMessageWorker+0x4a3
009fdf5c 71a45b30 USER32!SendMessageW+0x44
009fdfec 71a45bb0 COMCTL32!CCSendNotify+0xc0e
009fdffc 71a1d688 COMCTL32!CICustomDrawNotify+0x2a
009fe074 71a1db30 COMCTL32!Header_Draw+0x63
009fe0d0 71a1f196 COMCTL32!Header_OnPaint+0x3f
009fe128 77cf8290 COMCTL32!Header_WndProc+0x4e2
009fe148 77cfd634 USER32!_InternalCallWinProc+0x18
009fe1b0 77cd4490 USER32!UserCallWinProcCheckWow+0x17f
009fe1d8 77cd46c8 USER32!DispatchClientMessage+0x31
009fe200 77f7bb3f USER32!__fnDWORD+0x22
009fe220 77cd445e ntdll!_KiUserCallbackDispatcher+0x13
009fe27c 77cfd634 USER32!DispatchMessageWorker+0x3bc
009fe2e4 009fe4a8 USER32!UserCallWinProcCheckWow+0x17f
00000000 00000000 0x9fe4a8

The target thread has broken into COMCTL32!_chkstk, which indicates a stack problem.

Now you should investigate the target process' stack usage. The process has multiple threads, but we're only interested in the one that caused the overflow, so you should first identify this thread:

0:002> ~*k

   0  id: 570.574   Suspend: 1 Teb 7ffde000 Unfrozen
   .....

   1  id: 570.590   Suspend: 1 Teb 7ffdd000 Unfrozen
   .....

.  2  id: 570.598   Suspend: 1 Teb 7ffdc000 Unfrozen
ChildEBP RetAddr
009fdd0c 71a32520 COMCTL32!_chkstk+0x25
.....

   3  id: 570.760   Suspend: 1 Teb 7ffdb000 Unfrozen

So you need to investigate thread 2. The period at the left of this line indicates that this is the current thread.

The stack information is contained in the TEB (Thread Environment Block) at 0x7FFDC000. The easiest way to list it is using !teb. However, this requires good symbols. For maximum generality, assume you have no symbols:

0:002> dd 7ffdc000 L4
7ffdc000   009fdef0 00a00000 009fc000 00000000

To interpret this, you need to look up the definition of the TEB data structure. If you had good symbols, you could use dt TEB to do this. But in this case, you will need to look at the ntpsapi.h file in the Platform SDK. For Windows XP and Windows .NET Server 2003, this file contains the following information:

typedef struct _TEB {
    NT_TIB NtTib;
    PVOID  EnvironmentPointer;
    CLIENT_ID ClientId;
    PVOID ActiveRpcHandle;
    PVOID ThreadLocalStoragePointer;
    PPEB ProcessEnvironmentBlock;
    ULONG LastErrorValue;
    .....
    PVOID DeallocationStack;
    .....
} TEB;

typedef struct _NT_TIB {
    struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
    PVOID StackBase;
    PVOID StackLimit;
    .....
} NT_TIB;

This tells us that the second and third DWORDs in the TEB structure point to the bottom and top of the stack, respectively. In this case, these addresses are 0x00A00000 and 0x009FC000. (The stack grows downward in memory.) You can calculate the stack size by doing arithmetic with the ? (Evaluate Expression) command:

0:002> ? a00000-9fc000
Evaluate expression: 16384 = 00004000

This shows that the stack size is 16 K. What is the maximum stack size? It is stored in the field DeallocationStack. After some calculation, you can determine that this field's offset is 0xE0C.

0:002> dd 7ffdc000+e0c L1
7ffdce0c   009c0000

0:002> ? a00000-9c0000
Evaluate expression: 262144 = 00040000

This shows that the maximum stack size is 256 K, which means you have plenty of stack space left.

Furthermore, this process looks clean — it isn't in an infinite recursion or exceeding its stack space by using excessively large stack-based data structures.

Now break into KD and look at the overall system memory usage with the !vm extension command:

0:002> .breakin
Break instruction exception - code 80000003 (first chance)
ntoskrnl!_DbgBreakPointWithStatus+4:
80148f9c cc               int     3

kd> !vm

*** Virtual Memory Usage ***
        Physical Memory:     16268   (   65072 Kb)
        Page File: \??\C:\pagefile.sys
           Current:    147456Kb Free Space:     65988Kb
           Minimum:     98304Kb Maximum:       196608Kb
        Available Pages:      2299   (    9196 Kb)
        ResAvail Pages:       4579   (   18316 Kb)
        Locked IO Pages:        93   (     372 Kb)
        Free System PTEs:    42754   (  171016 Kb)
        Free NP PTEs:         5402   (   21608 Kb)
        Free Special NP:       348   (    1392 Kb)
        Modified Pages:        757   (    3028 Kb)
        NonPagedPool Usage:    811   (    3244 Kb)
        NonPagedPool Max:     6252   (   25008 Kb)
        PagedPool 0 Usage:    1337   (    5348 Kb)
        PagedPool 1 Usage:     893   (    3572 Kb)
        PagedPool 2 Usage:     362   (    1448 Kb)
        PagedPool Usage:      2592   (   10368 Kb)
        PagedPool Maximum:   13312   (   53248 Kb)
        Shared Commit:        3928   (   15712 Kb)
        Special Pool:         1040   (    4160 Kb)
        Shared Process:       3641   (   14564 Kb)
        PagedPool Commit:     2592   (   10368 Kb)
        Driver Commit:         887   (    3548 Kb)
        Committed pages:     45882   (  183528 Kb)
        Commit limit:        50570   (  202280 Kb)

        Total Private:       33309   (  133236 Kb)
         .....

First, look at nonpaged and paged pool usage. Both are well within limits, so these aren't the cause of the problem here.

Next, look at the number of committed pages: 183528 out of 202280. This is very close to the limit. Although this display does not show this number to be at the limit, you should keep in mind that while you are performing user-mode debugging, things are still happening in the system. Each time an NTSD command is executed, other processes are also allocating and freeig memory. That means you don't know exactly what the memory state was like at the time the stack overflow occurred. Given how close the committed page number is to the limit, it is reasonable to conclude that the page file was used up at some point, and this caused the stack overflow.

This is not an uncommon occurrence, and the target application cannot really be faulted for this. If it happens frequently, you might think about raising the initial stack commitment for the failing application.

Analyzing a Single Function Call

It can also be useful to find out exactly how much stack space a certain function call is allocating.

To do this, disassemble the first few instructions and look for the instruction sub esp,number. This moves the stack pointer, effectively reserving number bytes for local data.

Here is an example:

0:002> k
ChildEBP RetAddr
009fdd0c 71a32520 COMCTL32!_chkstk+0x25
009fde78 77cf8290 COMCTL32!ListView_WndProc+0x4c4
009fde98 77cfd634 USER32!_InternalCallWinProc+0x18
009fdf00 77cd55e9 USER32!UserCallWinProcCheckWow+0x17f
009fdf3c 77cd63b2 USER32!SendMessageWorker+0x4a3
009fdf5c 71a45b30 USER32!SendMessageW+0x44
009fdfec 71a45bb0 COMCTL32!CCSendNotify+0xc0e
009fdffc 71a1d688 COMCTL32!CICustomDrawNotify+0x2a
009fe074 71a1db30 COMCTL32!Header_Draw+0x63
009fe0d0 71a1f196 COMCTL32!Header_OnPaint+0x3f
009fe128 77cf8290 COMCTL32!Header_WndProc+0x4e2
009fe148 77cfd634 USER32!_InternalCallWinProc+0x18

0:002> u COMCTL32!Header_Draw
COMCTL32!Header_Draw:
71a1d625 55               push    ebp
71a1d626 8bec             mov     ebp,esp
71a1d628 83ec58           sub     esp,0x58
71a1d62b 53               push    ebx
71a1d62c 8b5d08           mov     ebx,[ebp+0x8]
71a1d62f 56               push    esi
71a1d630 57               push    edi
71a1d631 33f6             xor     esi,esi

This shows that Header_Draw allocated 0x58 bytes of stack space.


Debugging a Failed Driver Unload

A driver will not unload if there is a leaked reference to DeviceObject or DriverObject. This is a common cause of failed driver unloads.

Apart from IoCreateDevice, there are several functions that take reference to DriverObject and DeviceObject. If you don't follow the guidelines of using the functions, you will end up leaking the reference.

Here is an example of how to debug this problem. Although DeviceObject is used in this example, this technique works for all objects.

Fixing a driver that fails to unload

  1. Put a breakpoint right after the driver calls IoCreateDevice. Get the DeviceObject address.
  2. Find the object header by using the !object extension on this object address:
    kd> !object 81a578c0
Object: 81a578c0  Type: (81bd0e70) Device
    ObjectHeader: 81a578a8
    HandleCount: 0  PointerCount: 3
    Directory Object: e1001208  Name: Serial0

    The first variable in the ObjectHeader is the pointer count or reference count.

  3. Put a write breakpoint on the pointer count, using the ObjectHeader's address:
    kd> ba w4 81a578a8 "k;g"
  4. Hit G (Go). The debugger will produce a log.
  5. Look for the mismatched reference/dereference pair — specifically, a missing dereference. (Note that ObReferenceObject is implemented as a macro inside the kernel.)


Reading Bug Check Callback Data

Many drivers supply bug check callback routines. When Windows issues a bug check, it calls these routines before shutting down the system. One thing these routines can do is to indicate certain important parts of memory for debugging purposes.

In Windows NT 4.0, Windows 2000, and Windows XP prior to SP1, the bug check callback function is named BugCheckCallback. It is primarily used to write data to a region in memory — this data is called callback data.

In Windows XP SP1, Windows .NET Server 2003, and later versions of Windows, there are multiple callback functions. BugCheckCallback is the same as its counterpart in earlier versions of Windows, except that it is called after the dump file is written. Another callback function, BugCheckSecondaryDumpDataCallback, is called before the dump file is written — the data written by this routine is called secondary callback data.

How much of this information is available to the debugger depends on several factors:

  • If you are performing live debugging of a crashed system, callback data will be available if it has already been written by BugCheckCallback. Secondary callback data will not be available, since it is not stored in any fixed memory location.
  • If you are debugging a Complete Memory Dump or Kernel Memory Dump in Windows NT 4.0, Windows 2000, or Windows XP prior to SP1, all callback data will be available.
  • If you are debugging a Complete Memory Dump or Kernel Memory Dump in Windows XP SP1, Windows .NET Server 2003, or a later version, callback data will not be available. The dump file will contain an image of the buffer that holds this data, but this image will have been made before the BugCheckCallback routine wrote the callback data to the buffer. On the other hand, secondary callback data will be present.
  • If you are debugging a Small Memory Dump, callback data will not be available. Secondary callback data will be available in Windows XP SP1, Windows .NET Server 2003, or a later version.

See Varieties of Kernel-Mode Dump Files for more details on these different dump file sizes.

Displaying Callback Data

To display bug check callback data, you can use the !bugdump extension.

Without any parameters, !bugdump will display data for all callbacks.

To view data for one specific callback routine, use !bugdump Component, where Component is the same parameter that was passed to KeRegisterBugCheckCallback when that routine was registered.

Displaying Secondary Callback Data

There are two methods of displaying secondary callback data in Windows XP SP1, Windows .NET Server 2003, and later versions of Windows. You can use the .enumtag command or you can write your own debugger extension.

Each block of secondary callback data is identified by a GUID tag. This tag is specified by the Guid field of the (KBUGCHECK_SECONDARY_DUMP_DATA)ReasonSpecificData parameter passed to BugCheckSecondaryDumpDataCallback.

The .enumtag (Enumerate Secondary Callback Data) command is not a very precise instrument. It displays every secondary data block, showing the tag and then showing the data in hexadecimal and ASCII format. It is generally useful only to determine what tags are actually being used for secondary data blocks.

To use this data in a more practical way, it is recommended that you write your own debugger extension. This extension must call methods in the dbgeng.h header file. For details, see Writing New Debugger Extensions.

If you know the GUID tag of the secondary data block, your extension should use the method IDebugDataSpaces3::ReadTagged to access the data. Its prototype is as follows:

STDMETHOD(ReadTagged)(
    THIS_
    IN LPGUID Tag,
    IN ULONG Offset,
    OUT OPTIONAL PVOID Buffer,
    IN ULONG BufferSize,
    OUT OPTIONAL PULONG TotalSize
    ) PURE;

Here is an example of how to use this method:

UCHAR RawData[MY_DATA_SIZE];
GUID MyGuid = .... ;

Success = DataSpaces->ReadTagged(  &MyGuid,  0,  RawData,
                                   sizeof(RawData),  NULL);

If you supply a BufferSize that is too small, ReadTagged will succeed but will write only the requested number of bytes to Buffer. If you specify a BufferSize that is too large, ReadTagged will succeed but will write only the actual block size to Buffer. If you supply a pointer for TotalSize, ReadTagged will use it to return the size of the actual block. If the block cannot be accessed, ReadTagged will return a failure status code.

If two blocks have identical GUID tags, the first matching block will be returned, and the second block will be inaccessible.

If you are not sure of the GUID tag of your block, you can use the IDebugDataSpaces3::StartEnumTagged, IDebugDataSpaces3::GetNextTagged, and IDebugDataSpaces3::EndEnumTagged methods to enumerate the tagged blocks. Their prototypes are as follows:

STDMETHOD(StartEnumTagged)(
    THIS_
    OUT PULONG64 Handle
    ) PURE;

STDMETHOD(GetNextTagged)(
    THIS_
    IN ULONG64 Handle,
    OUT LPGUID Tag,
    OUT PULONG Size
    ) PURE;

STDMETHOD(EndEnumTagged)(
    THIS_
    IN ULONG64 Handle
    ) PURE;

Debugging Callback Routines

It is also possible to debug the callback routine itself. Breakpoints within callback routines work just like any other breakpoint.

If the callback routine causes a second bug check, this new bug check will be processed first. However, Windows will not repeat certain parts of the Stop process — for example, it will not write a second crash dump file. The Stop code displayed on the blue screen will be the second bug check code. If a kernel debugger is attached, messages about both bug checks will usually appear.


Debugging Windows Setup and the OS Loader

If your computer hangs in text-mode at the "Starting Windows" screen and has not connected into the debugger, it may be possible to modify your setup to allow the debugger to connect during startup.

Before debugging can begin, you must start your target computer in Safe Mode and make the following preparations:

  • Install the checked version of $LDR$ on the target computer. If you install the full checked build of Windows, this file will be included. If you wish to install just this file, you need to look for it under the name setupldr.bin. Copy this file to the root of the first bootable partition on the target computer and rename it $LDR$ (with no filename extension). For instructions on how to install a full checked build or individual checked files, see the Windows DDK.
  • Make sure the symbols for the checked version of $LDR$ are included in the debugger's symbol path.
  • Set the debugger baudrate to 19200.
  • Modify the file txtsetup.sif on the target computer by adding the /debugstop, /debugport, and /baudrate switches to the OsLoadOptions line. Here is an example of a modified txtsetup.sif file:
    OsLoadOptions = "/fastdetect /noguiboot /debugstop /debugport=com2 /baudrate=19200"
; OsLoadOptionsVar = "/fastdetect"
; SetupCmdLinePrepend = "CDB"

    The exact contents of your file may differ from this. The baudrate should match that used by the debugger (19200 is recommended). The COM port should be the port on the target computer to which the debugging cable is attached.

Once these steps have been completed, use the following procedure to connect the debugger:

Debugging Windows Setup and the OS Loader

  1. Start up the debugger with the -d command-line option, or use CTRL+K to cause the debugger to break in when the first kernel module is loaded.
  2. When the debugger breaks in, you will see a message that the symbol checksum cannot be verified. Ignore this message! If you want to verify that your symbols are correct, do a stack trace and make sure the first line of the stack trace says osloader!DbgBreakPoint.


Debugging Dual-Boot Machines

How should you respond when the alternate operating system doesn't start on a dual-boot machine?

On an x86 computer, check that the boot.ini points to the correct path for the other operating system. See Editing the boot.ini File for Debugging for details. Also check that boosect.ini exists. This file contains the boot record for the other operating system exists. To unhide this file, use the attrib -r -s -h boosect.ini command.

On an IA-64 computer, check that the NVRAM settings point to the correct path for the other operating system. See Editing the NVRAM Settings for Debugging for details.


Debugging CSRSS with NTSD

CSRSS is the executable that controls the underlying layer for the Windows® environment. There are a number of problems which make it necessary to debug CSRSS itself.

Debugging CSRSS is also useful when the Windows subsystem terminates unexpected with a Bug Check 0xC000021A. (STATUS_SYSTEM_PROCESS_TERMINATED). In this case, debugging CSRSS will catch the failure before it gets to the "unexpected" point.

Although CSRSS is an integral part of the Windows operating system, it is actually a user-mode process.

Controlling NTSD from the Kernel Debugger

Normally, user-mode processes can be debugged equally well by CDB or NTSD. However, to debug CSRSS it is necessary to use NTSD and controlling it from the kernel debugger.

The reason for this is that when its output is redirected, NTSD will run without generating any console window on the target computer. CDB would require a console window, which would require the CSRSS process to be active.

Enabling CSRSS Debugging

CSRSS debugging must be enabled before you can proceed. If the target computer is running a checked build, CSRSS debugging is always enabled. If the target computer is running a free build, you will have to manually clear the CSRSS-debugging-disable bit in the registry of the target computer.

Use gflags or regedt32 to edit the following registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager

Edit the GlobalFlag value entry (of type REG_DWORD) and set the bit 0x00020000.

The registry change requires a reboot to take effect.

Starting NTSD

Since you will be controlling the user-mode debugger from the kernel debugger, you will need to set up a kernel debugging connection. See Kernel-Mode Setup for details.

After the registry has been properly configured, it is a simple matter of starting NTSD as follows:

ntsd --

This command is simply shorthand for the following:

ntsd -d -g -G -o -pd -p -1

(Note that the process ID of CSRSS is always -1. The -pd parameter specifies that the debugger should detach from CSRSS after debugging is finished; this only works on Windows XP and Windows .NET Server 2003.)

See Controlling the User-Mode Debugger from the Kernel Debugger for an explanation of how to proceed.

You will have to set your symbol path to a location on your host computer or to some other location on your network. When CSRSS is being debugged, symbol authentication on the target computer will not work properly.

Note that you may see an "in page io error" message. This is another manifestation of a hardware failure.


Debugging WinLogon with NTSD

WinLogon is the executable which handles interactive user logons and logoffs, and handles all instances of CTRL+ALT+DELETE.

Although WinLogon is an integral part of the Windows operating system, it is actually a user-mode process.

Controlling NTSD from the Kernel Debugger

Normally, user-mode processes can be debugged equally well by CDB or NTSD. However, to debug WinLogon it is necessary to use NTSD and controlling it from the kernel debugger.

The reason for this is that when its output is redirected, NTSD will run without generating any console window on the target computer. CDB would require a console window, which would require the WinLogon process to be active.

Enabling WinLogon Debugging

Since you will be redirecting the user-mode debugger output to the kernel debugger, you will need to set up a kernel debugging connection. See Kernel-Mode Setup for details.

To attach a debugger to WinLogon, you must go through the registry so that the process is debugged from the time it starts up. To set up WinLogon debugging, set HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\WinLogon.EXE\Debugger to:

ntsd -d -x -g

The -d option passes control to the kernel debugger. The -x option causes the debugger to capture access violations as second-chance exceptions. The -g option causes the WinLogon process to run after the attachment. Don't add the -g if you want to start debugging before winlogon.exe begins — for example, if you want to set an initial breakpoint.

In addition, you should set the GLOBAL_FLAG value under the winlogon.exe key to REG_SZ "0x000400F0". This sets heap checking and FLG_ENABLE_KDEBUG_SYMBOL_LOAD.

The registry change requires a reboot to take effect.

Performing the Debugging

After the next reboot, the debugger will break into WinLogon automatically.

See Controlling the User-Mode Debugger from the Kernel Debugger for an explanation of how to proceed.

You will have to set your symbol path to a location on your host computer or to some other location on your network. When CSRSS is being debugged, symbol authentication on the target computer will not work properly.


Debugging Service Applications with WinDbg

Windows supports an application type known as a service application. A service application conforms to the interface rules of the Service Control Manager (SCM). It can be started automatically at system boot, by a user through the Services control panel utility, or by an application that uses the service functions included in the Win32® API.

There are two methods for debugging a service. The first method involves attaching the debugger to the service while it is running. The second method involves using postmortem debugging feature of Windows.

Attaching to a Service

Use the following steps to debug a service by attaching to the service.

  1. Install and start the service.
  2. Start the debugger.
  3. Click Attach to a Process from the File menu, or press F6. The Attach to Process dialog box appears. Double-click the process you want to debug, or click the process and click OK.
  4. Set any breakpoints you will need.
  5. Press F5 to start debugging after the thread that performs the attach terminates.

Using Postmortem Debugging

Use the following steps to debug a service using the postmortem debugger.

  1. Call the DebugBreak function in your service from the point at which you would like to break into the debugger. (For more information, see DebugBreak in the Platform SDK documentation.)
  2. Install WinDbg as postmotem debugger. (See Enabling Postmortem Debugging for details.)
  3. Install and start the service. The system will display a dialog box giving you the option to debug the service.
  4. Click Cancel to debug the service.
  5. Press F5 to start debugging the service.


Debugging User-Mode Failures with KD

To properly debug user-mode failures, you need CDB or WinDbg. However, sometimes a user-mode exception will break into KD because no user-mode debugger is present. There are also times when it is helpful to monitor what specific user-mode processes are doing while debugging a kernel-mode problem.

By default, the kernel debugger attempts to load the first user-mode symbol which matches the address specified (for a k, u, or ln command).

Unfortunately, user-mode symbols are often not specified in the symbol path or the first symbol isn't the correct one. If the symbols are not there, either copy them into the symbol path or use a .sympath (Set Symbol Path) command to point to the full symbol tree, and then use the .reload (Reload Module) command. If the wrong symbol is loaded, you can explicitly load a symbol by doing a .reload <binary.ext>.

Most of the Windows DLLs are rebased so that they load at different addresses, but there are exceptions. Video adapters are the most common case. There are dozens of video adapters which all load at the same base address, so KD will almost always find ati.dll (the first video symbol, alphabetically). For video, there is also a .sys file loaded which can be identified by using a !drivers extension. With that information, you can issue a .reload to get the correct video DLLs. There are also times when the debugger gets confused and reloading specific symbols will help give the correct stack. Unassemble the functions to see if the symbols look correct.

Similar to the video DLLs, almost all executables load at the same address, so KD will report access. If you see a stack trace in access, do a !process and then a .reload of the executable name given. If the executable does not have symbols in the symbol path, copy them there and do the .reload again.

Sometimes KD or WinDbg has trouble loading the correct user-mode symbols even when the full symbol tree is in the symbol path. In this case, ntdll.dll and kernel32.dll are two of the most common symbols which would be required. In the case of debugging CSRSS from KD, winsrv.dll and csrsrv.dll are also common DLLs to load.


Security Considerations

This section includes:

Security Vulnerabilities

Secure Mode


Security Vulnerabilities

This section includes:

Security During Kernel-Mode Debugging

Security During User-Mode Debugging

Security During Postmortem Debugging

Security During Remote Debugging


Security During Kernel-Mode Debugging

Security during kernel-mode debugging is never about protecting the target computer. The target is completely vulnerable to the debugger — this is the very nature of debugging.

If a debugging connection was enabled during boot (see Configuring Software for Kernel-Mode Debugging), it will remain vulnerable through the debugging port until its next boot.

However, you should be concerned about security on the host computer. In an ideal situation, the debugger runs as an application on your host computer, but does not interact with other applications on this computer. There are three possible ways in which security problems could arise:

  • If you use corrupt or malicious extension DLLs, they could cause your debugger to take unexpected actions, possibly affecting the host computer.
  • It might be possible that corrupt or malicious symbol files could have a similar effect.
  • If you are running a remote debugging session, an unexpected client might attempt to link to your server. Or perhaps the client you are expecting might attempt to perform actions that you don't anticipate.

If you wish to prevent a remote user from performing actions on your host computer, use Secure Mode.

For suggestions on how to guard against unexpected remote connections, see Security During Remote Debugging.

If you are not performing remote debugging, you should still beware of bad symbol files and extension DLLs. Don't load symbols or extensions that you distrust!

Local Kernel Debugging

Only users who have debug privileges can start a local kernel debugging session. If you are the administrator of a machine that has multiple user accounts, you should be aware that any user with these privileges can starta a local kernel debugging session, effectively giving them control of all processes on the computer — and therefore giving them access to all peripherals as well.


Security During User-Mode Debugging

When a user-mode debugger is active, it can effectively control any of the processes on the computer.

There are three possible ways in which security problems could arise during user-mode debugging:

  • If you use corrupt or malicious extension DLLs, they could cause your debugger to take unexpected actions, possibly affecting applications other than your target.
  • It might be possible that corrupt or malicious symbol files could have a similar effect.
  • If you are running a remote debugging session, an unexpected client might attempt to link to your server. Or perhaps the client you are expecting might attempt to perform actions that you don't anticipate.

For suggestions on how to guard against unexpected remote connections, see Security During Remote Debugging. Once a remote client has joined a user-mode debugging session, there is no way to restrict its access to processes on your computer.

If you are not performing remote debugging, you should still beware of bad symbol files and extension DLLs. Don't load symbols or extensions that you distrust!


Security During Postmortem Debugging

Only an administrator can enable postmortem debugging.

However, postmortem debugging is enabled for the entire system, not just for one user. So once it has been enabled, any application crash will activate the debugger that has been chosen — even if the current user does not have administrative privileges.

Also, a postmortem debugger inherits the same privileges as the application that crashed. So if a Windows service such as CSRSS and LSASS crashes, the debugger will have very high-level privileges.

You should take this into account when choosing to enable postmortem debugging.


Security During Remote Debugging

There are two ways to increase security during remote debugging: by restricting who can connect to your session, and by restricting the powers of someone who does connect.

Controlling Access to the Debugging Session

If you are performing remote debugging through the debugger or remote debugging through a process server, any computer on your local network can attempt to attach to your debugging session.

If you are using the TCP, 1394, COM, or named pipe protocols, you can require the Debugging Client to supply a password. However, this password is not encrypted during transmission, and therefore these protocols are not secure.

If you wish your Debugging Server to be secure, you must use secure sockets layer (SSL) or secure pipe (SPIPE) protocol.

If you are performing remote debugging through remote.exe, you can use the /u parameter to prohibit connections from unauthorized users.

Restricting the Powers of the Client

If you are setting up a kernel-mode debugging session, you can restrict the debugger's ability to interfere with the host machine by using Secure Mode.

In user mode, Secure Mode is not available. You can stop a nosy client from issuing MS-DOS commands by issuing the .noshell (Prohibit Shell Commands) command, but there are many other ways for a client to interfere with your computer.

Note that both Secure Mode and .noshell will prevent both the Debugging Client and the Debugging Server from taking certain actions. There is no way to place a restriction on the client but not the server.

Forgotten Process Servers

When you start a process server on a remote machine, the process server runs silently.

If you perform remote debugging through this process server and then end the session, the process server continues to run.

A forgotten process server is a potential target for an attack. You should always shut down an unneeded process server. Use the Kill.exe utility or Task Manager to terminate the process server.


Secure Mode

When you are performing kernel-mode debugging, you can run the debugger in Secure Mode. This prevents the debugger from affecting the host computer, yet does not significantly decrease its freedom to debug the target computer.

Secure Mode is recommended if you are going to allow remote clients to join your debugging session.

This section includes:

Features of Secure Mode

Activating Secure Mode


Features of Secure Mode

When Secure Mode is active, all commands that could be used to affect the host computer are deactivated. In addition,

Secure Mode has the following specific affects:

  • The .attach (Attach to Process), .create (Create Process), .detach (Detach from Process), .abandon (Abandon Process), .kill (Kill Process), .tlist (List Process IDs), and .opendump (Open Dump File) commands are not available.
  • The File | Attach to a Process, File | Open Executable, Debug | Stop Debugging, and File | Open Crash Dump WinDbg menu commands are not availabe.
  • The .shell (MS-DOS Shell) command is not available.
  • Extension DLLs must be loaded from a local disk; they cannot be loaded from UNC paths.
  • Only the two standard types of extension DLLs (wdbgexts.h and dbgeng.h) are permitted. Other types of DLLs cannot be loaded as extensions.
  • If you are using a symbol server, there are several restrictions. Only SymSrv (symsrv.dll) is permitted; other symbol server DLLs will not be accepted. You may not use a downstream store for your symbols. HTTP and HTTPS connections are not permitted.

Once it has been activated, Secure Mode cannot be turned off.


Activating Secure Mode

Secure Mode is only available for kernel-mode debugging. It must be activated before the debugging session has begun — either on the debugger's command line, or when the debugger is completely dormant and is not yet being used as a server.

To activate Secure Mode, use one of the following methods:

  • The -secure command-line option
  • The .secure (Activate Secure Mode) command
  • The .symopt+0x40000 command

If you have an existing kernel debugging session and need to discover whether you are already in Secure Mode, use the .secure command. This will tell you the current status of Secure Mode — it will not activate Secure Mode, since this cannot be done once the session has started.

Once Secure Mode has been activated, it cannot be turned off. Even ending the debugging session will not turn it off. Secure Mode persists as long as the debugger itself is running.


Reference

This reference section includes:

Command-Line Options

Environment Variables

Debugger Commands

Debugger Extension Commands

Debugger-Related APIs

Debugger Error and Warning Messages

WinDbg Graphical Interface Features


Command-Line Options

This reference section includes:

CDB Command-Line Options

KD Command-Line Options

WinDbg Command-Line Options

KDbgCtrl Command-Line Options

Dr. Watson Command-Line Options

Autodump+ Command-Line Options

DbgRpc Command-Line Options

SymChk Command-Line Options

SymStore Command-Line Options


CDB Command-Line Options

First-time users of CDB or NTSD should begin with the Debugger Operation section.

The CDB command line uses the following syntax:

cdb  [ -server ServerOptions | -remote ClientOptions ]
   [ -premote SmartClientOptions ] [-log{o|a} LogFile]
   [-2] [-d] [-g] [-G] [-hd] [-lines] [-myob] [-bonc]
   [-n] [-o] [-s] [-v] [-w] [-cf "filename"] [-c "command"]
   [-robp] [-r BreakErrorLevel]  [-t PrintErrorLevel]
   [ -x{e|d|n|i} Exception ] [-x] [-clines lines]
   [-i ImagePath]  [-y SymbolPath] [-srcpath SourcePath]
   [-aExtension] [-failinc] [-noio] [-noshell]
   [-sdce] [-ses] [-sicv] [-sins] [-snc] [-snul]
   [-sup] [-sflags 0xNumber] [-ee {masm|c++}]
   [-e Event] [-pb] [-pd] [-pe] [-pr] [-pt Seconds] [-pv]
   [ -- | -p pid  | -pn name | -z DumpFile | executable ]

cdb -QR Server

cdb -wake pid

cdb -?

The NTSD command-line syntax is identical to that of CDB:

ntsd  [ -server ServerOptions | -remote ClientOptions ]
   [ -premote SmartClientOptions ] [-log{o|a} LogFile]
   [-2] [-d] [-g] [-G] [-hd] [-lines] [-myob] [-bonc]
   [-n] [-o] [-s] [-v] [-w] [-cf "filename"] [-c "command"]
   [-robp] [-r BreakErrorLevel]  [-t PrintErrorLevel]
   [ -x{e|d|n|i} Exception ] [-x] [-clines lines]
   [-i ImagePath]  [-y SymbolPath] [-srcpath SourcePath]
   [-aExtension] [-failinc] [-noio] [-noshell]
   [-sdce] [-ses] [-sicv] [-sins] [-snc] [-snul]
   [-sup] [-sflags 0xNumber] [-ee {masm|c++}]
   [-e Event] [-pb] [-pd] [-pe] [-pr] [-pt Seconds] [-pv]
   [ -- | -p pid  | -pn name | -z DumpFile | executable ]

ntsd -QR Server

ntsd -wake pid

ntsd -?

The only difference between NTSD and CDB is that NTSD spawns a new console window while CDB inherits the window from which it was invoked. Since the start command can also be used to spawn a new console window, the following two constructions will give the same results:

start cdb [parameters]
ntsd [parameters]

Descriptions of the CDB and NTSD command-line options follow. Only the -remote, -server, -g and -G options are case-sensitive. The initial hyphen can be replaced with a forward-slash (/). Options that do not take any additional parameters can be concatenated — so cdb -o -d -G -g winmine can be written as cdb -odGg winmine.

If the -remote or -server option is used, it must appear before any other options on the command line. If an executable is specified, it must appear last on the command line; any text after the executable name is passed to the executable program as its own command-line parameters.

Parameters

-server ServerOptions
Creates a Debugging Server that can be accessed by other debuggers. For an explanation of the possible ServerOptions, see Activating the Debugging Server.
-remote ClientOptions
Creates a Debugging Client, and connects to a Debugging Server that is already running. For an explanation of the possible ClientOptions, see Activating the Debugging Client.
-premote SmartClientOptions
Creates a Smart Client, and connects to a process server that is already running. For an explanation of the possible SmartClientOptions values, see Activating the Smart Client.
-2
If the target application is a console application, this option causes it to live in a new console window. (The default is for a target console application to share the window with CDB or NTSD.)
--
This is the same as -d -g -G -o -pd -p -1. See Debugging CSRSS with NTSD for an explanation.
-a Extension
Sets the default extension DLL. The default is userexts. There must be no space after the "a", and the .dll extension must not be included. For details, and other methods of setting this default, see Loading Debugger Extension DLLs.
-bonc
If this option is specified, the debugger will break into the target as soon as the session begins. This is especially useful when connecting to a Debugging Server that might not be currently broken into the target.
-c "command"
Specifies the initial debugger command to run at start-up. This command must be surrounded with quotation marks. Multiple commands can be separated with semicolons. (If you have a long command list, it may be easier to put them in a script and then use the -c option with the $< (Run Script File) command.)

If you are starting a Debugging Client, this command must be intended for the Debugging Server. Client-specific commands such as .lsrcpath are not allowed.

-cf "filename"
Specifies the path and name of a file containing debugger commands. These commands are executed as soon as the debugger is started. If filename contains spaces it must be enclosed in quotation marks. If the path is omitted, the current directory is assumed. If the -cf option is not used, the default is the file ntsd.ini in the current directory. If the file does not exist, no error occurs.
-clines lines
Sets the approximate number of commands in the command history which can be accessed during remote debugging. For details, and for other ways to change this number, see Using Debugger Commands.
-d
Passes control of this debugger to the kernel debugger. If you are debugging CSRSS, this control redirection always is active, even if -d is not specified. (This option cannot be used during remote debugging — use -ddefer instead.) See Controlling the User-Mode Debugger from the Kernel Debugger for details.
-ddefer
Passes control of this debugger to the kernel debugger, unless a Debugging Client is connected. (This is a variation of -d that can be used from a Debugging Server.) See Controlling the User-Mode Debugger from the Kernel Debugger for details.
-e Event
Signals the debugger that the specified event has occurred. This option is only used when starting the debugger programmatically.
-ee {masm|c++}
Sets the default expression evaluator. If masm is specified, MASM expression syntax will be used. If c++ is specified, C++ expression syntax will be used. If the -ee option is omitted, MASM expression syntax is used as the default. See Evaluating Expressions for details.
-failinc
Causes the debugger to ignore any questionable symbols. When debugging a user-mode or kernel-mode minidump file, this option will also prevent the debugger from loading any modules whose images can't be mapped. For details and for other methods of controlling this, see SYMOPT_EXACT_SYMBOLS.
-g
Ignores initial breakpoint in target application. Normally, CDB stops after the main image and all statically-linked images are loaded, but before the DLL initialization routines have been run.
-G
Ignores final breakpoint at process termination. Normally, CDB stops during the image run-down process. This option will cause CDB to exit immediately when the child terminates.
-hd
(Windows XP and Windows .NET Server 2003 only) Specifies that the debug heap should not be used. See Behavior of Spawned Processes for details.
-i ImagePath
Specifies the location of the executables that generated the fault. If the path contains spaces, it should be enclosed in quotation marks. For details, and for other ways to change this path, see Setting Paths and Loading Files.
-lines
Enables source line debugging. If this option is omitted, the .lines (Toggle Source Line Support) command will have to be used before source debugging will be allowed. For other methods of controlling this, see SYMOPT_LOAD_LINES.
-log{o|a} LogFile
Begins logging information to a log file. If the specified file already exists, it will be overwritten if -logo is used, or output will be appended to the file if -loga is used. For more details, see Keeping a Log File.
-myob
If there is a version mismatch with dbghelp.dll, the debugger will continue to run. (Without the -myob switch, this is considered a fatal error.)
-n
Noisy symbol load: Enables verbose output from symbol handler. For details and for other methods of controlling this, see SYMOPT_DEBUG.
-noio
(Debugging Server only) Causes the Debugging Server to only perform its input and output remotely. For more details, see Activating the Debugging Server.
-noshell
Prohibits all .shell commands. This prohibition will last as long as the debugger is running, even if a new debugging session is begun. For details, and for other ways to disable .shell commands, see Using Shell Commands.
-o
Debugs all processes launched by the target application (child processes). By default, processes created by the one you are debugging will run as they normally do. For other methods of controlling this, see Spawning a New Process (User Mode).
-p PID
Specifies the decimal process ID to be debugged. This is used to debug a process that is already running. For details, see Attaching to a Running Process (User Mode).
-pb
(Windows XP and Windows .NET Server 2003 only) Prevents the debugger from requesting an initial break-in when attaching to a target process. This can be useful if the application is already suspended, or if you wish to avoid creating a break-in thread in the target. See Attaching to a Running Process (User Mode).
-pd
(Windows XP and Windows .NET Server 2003 only) Causes the target application not to be terminated at the end of the debugging session. See Ending the Debugging Session for details.
-pe
(Windows XP and Windows .NET Server 2003 only) Indicates that the target application is already being debugged. See Re-attaching to the Target Application for details.
-pn name
Specifies the name of the process to be debugged. (This name must be unique.) This is used to debug a process that is already running. For details, see Attaching to a Running Process (User Mode).
-pr
(Windows XP and Windows .NET Server 2003 only) Causes the debugger to start the target process running when it attaches to it. This can be useful if the application is already suspended and you wish it to resume execution. See Attaching to a Running Process (User Mode).
-pt Seconds
Specifies the break time-out, in seconds. The default is 30. See Controlling the Target for details.
-pv
Specifies that the debugger should attach to the target process noninvasively. For details, see Noninvasive Debugging (User Mode).
-QR Server
Lists all Debugging Servers running on the specified network server. The double backslash (\\) preceding Server is optional. See Searching for Debugging Servers for details.

The -QR parameter cannot be used with any other parameters. This command will not actually start CDB.

-r BreakErrorLevel
Specifies the error level that will cause the target to break into the debugger. This is a decimal number equal to 0, 1, 2, or 3. Possible values are as follows:
Value | Constant | Meaning
0 | NONE | Do not break on any errors.
1 | ERROR | Break on ERROR level debugging events.
2 | MINORERROR | Break on MINORERROR and ERROR level debugging events.
3 | WARNING | Break on WARNING, MINORERROR, and ERROR level debugging events.

This error level only has meaning in checked builds of Microsoft® Windows® 2000 and above. The default value is 1.

-robp
This allows CDB to set a breakpoint on a read-only memory page. (The default is for such an operation to fail.)
-s
Disables lazy symbol loading. This will slow down process startup. For details and for other methods of controlling this, see SYMOPT_DEFERRED_LOADS.
-sdce
Causes the debugger to display File access error dialog boxes during symbol load. For details and for other methods of controlling this, see SYMOPT_FAIL_CRITICAL_ERRORS.
-ses
Causes the debugger to perform a strict evaluation of all symbol files and ignore any questionable symbols. For details and for other methods of controlling this, see SYMOPT_EXACT_SYMBOLS.
-sflags 0x Number
Sets all the symbol handler options at once. Number should be a hexadecimal number prefixed with 0x — a decimal without the 0x is permitted, but the symbol options are binary flags and therefore hexadecimal is recommended. This option should be used with care, since it will override all the symbol handler defaults. For details, see Setting Symbol Options.
-sicv
Causes the symbol handler to ignore the CV record. For details and for other methods of controlling this, see SYMOPT_IGNORE_CVREC.
-sins
Causes the debugger to ignore the symbol path and executable image path environment variables. For details, see SYMOPT_IGNORE_NT_SYMPATH.
-snc
Causes the debugger to turn off C++ translation. For details and for other methods of controlling this, see SYMOPT_NO_CPP.
-snul
Disables automatic symbol loading for unqualified names. For details and for other methods of controlling this, see SYMOPT_NO_UNQUALIFIED_LOADS.
-srcpath SourcePath
Specifies the source file search path. Separate multiple paths with a semicolon (;). If the path contains spaces, it should be enclosed in quotation marks. For details, and for other ways to change this path, see Setting Paths and Loading Files.
-sup
Causes the symbol handler to search the public symbol table during every symbol search. For details and for other methods of controlling this, see SYMOPT_AUTO_PUBLICS.
-t PrintErrorLevel
Specifies the error level that will cause the debugger to display an error message. This is a decimal number equal to 0, 1, 2, or 3. Possible values are as follows:
Value | Constant | Meaning
0 | NONE | Do not display any errors.
1 | ERROR | Display ERROR level debugging events.
2 | MINORERROR | Display MINORERROR and ERROR level debugging events.
3 | WARNING | Display WARNING, MINORERROR, and ERROR level debugging events.

This error level only has meaning in checked builds of Microsoft® Windows® 2000 and above. The default value is 1.

-v
Enables verbose output from the debugger.
-w
Specifies to debug 16-bit applications in a separate VDM.
-wake pid
Causes sleep mode to end for the user-mode debugger whose process ID is specified by pid. This command must be issued on the target machine during sleep mode. See Controlling the User-Mode Debugger from the Kernel Debugger for details.

The -wake parameter should not be used with any other parameters. This command will not actually start CDB.

-x{e|d|n|i} Exception
Controls the debugger's behavior when the specified event occurs. The Exception can be either an exception number or an event code. You can specify this option multiple times to control different events. See Controlling Exceptions and Events for details and for other methods of controlling these settings.
-x
Disables first-chance break on access violation exceptions. The second occurrence of an access violation will break into the debugger. This is the same as -xd av.
-y SymbolPath
Specifies the symbol search path. Separate multiple paths with a semicolon (;). If the path contains spaces, it should be enclosed in quotation marks. For details, and for other ways to change this path, see Setting Paths and Loading Files.
-z DumpFile
Specifies the name of a crash dump file to debug. If the path and file name contain spaces, this must be surrounded by quotation marks. It is possible to open several dump files at once by including multiple -z options, each followed by a different DumpFile value. For details, see Analyzing a User-Mode Dump File with CDB.
executable
Specifies the command line of an executable process. This is used to launch a new process and debug it. This has to be the final item on the command line. All text after the executable name is passed to the executable as its argument string. For details, see Spawning a New Process (User Mode).
-?
Displays command-line help text.

When you are starting the debugger from the MS-DOS® Command Prompt, specify arguments for the target application after the application's file name. For instance:

cdb myexe arg1 arg2


KD Command-Line Options

First-time users of KD should begin with the Debugger Operation section.

The KD command line uses the following syntax.

kd [ -server ServerOptions | -remote ClientOptions ]
   [-b | -x] [-d] [-bonc] [-m] [-myob] [-lines] [-n] [-r] [-s]
   [-v] [-clines lines] [-failinc] [-noio] [-noshell]
   [-secure] [-sdce] [-ses] [-sicv] [-sins] [-snc] [-snul]
   [-sup] [-sflags 0xNumber] [-log{o|a} LogFile] [-aExtension]
   [-i ImagePath] [-y SymbolPath]  [-srcpath SourcePath]
   [-k ConnectType | -kl | -kx ExdiOptions] [-ee {masm|c++}]
   [-z DumpFile] [-cf "filename"] [-c "command"]

kd -QR Server

kd -wake pid

kd -?

Descriptions of the KD command-line options follow. Only the -remote and -server options are case-sensitive. The initial hyphen can be replaced with a forward-slash (/). Options which do not take any additional parameters can be concatenated — so kd -r -n -v can be written as kd -rnv.

If the -remote or -server option is used, it must appear before any other options on the command line.

Parameters

-server ServerOptions
Creates a Debugging Server that can be accessed by other debuggers. For an explanation of the possible ServerOptions, see Activating the Debugging Server.
-remote ClientOptions
Creates a Debugging Client, and connects to a Debugging Server that is already running. For an explanation of the possible ClientOptions, see Activating the Debugging Client.
-a Extension
Sets the default extension DLL. The default is kdextx86.dll or kdexts.dll. There must be no space after the "a", and the .dll file name extension must not be included. For details, and other methods of setting this default, see Loading Debugger Extension DLLs.
-b
This option has two effects:

1. The debugger will break into the target computer immediately upon connection.

2. After a reboot, the debugger will break into the target computer once the kernel is initialized. See Crashing and Rebooting the Target Computer for details and for other methods of changing this status.

-bonc
If this option is specified, the debugger will break into the target as soon as the session begins. This is especially useful when connecting to a Debugging Server that might not be currently broken into the target.
-c "command"
Specifies the initial debugger command to run at start-up. This command must be surrounded with quotation marks. Multiple commands can be separated with semicolons. (If you have a long command list, it may be easier to put them in a script and then use the -c option with the $< (Run Script File) command.)

If you are starting a Debugging Client, this command must be intended for the Debugging Server. Client-specific commands, such as .lsrcpath, are not allowed.

-cf "filename"
Specifies the path and name of a file containing debugger commands. These commands are executed as soon as the debugger is started. If filename contains spaces it must be enclosed in quotation marks. If the path is omitted, the current directory is assumed. If the -cf option is not used, the default is the file ntsd.ini in the current directory. If the file does not exist, no error occurs.
-clines lines
Sets the approximate number of commands in the command history which can be accessed during remote debugging. For details, and for other ways to change this number, see Using Debugger Commands.
-d
After a reboot, the debugger will break into the target computer as soon as a kernel module is loaded. (This break is earlier than the break from the -b option.) See Crashing and Rebooting the Target Computer for details and for other methods of changing this status.
-ee {masm|c++}
Sets the default expression evaluator. If masm is specified, MASM expression syntax will be used. If c++ is specified, C++ expression syntax will be used. If the -ee option is omitted, MASM expression syntax is used as the default. See Evaluating Expressions for details.
-failinc
Causes the debugger to ignore any questionable symbols. When debugging a user-mode or kernel-mode minidump file, this option will also prevent the debugger from loading any modules whose images can't be mapped. For details and for other methods of controlling this, see SYMOPT_EXACT_SYMBOLS.
-i ImagePath
Specifies the location of the executables that generated the fault. If the path contains spaces, it should be enclosed in quotation marks. For details, and for other ways to change this path, see Setting Paths and Loading Files.
-k ConnectType
Tells the debugger how to connect to the target. For details, see Choosing Kernel Debugging Settings.
-kl
(Windows XP and Windows .NET Server 2003 only) Starts a kernel debugging session on the same machine as the debugger. For more details, see Attaching to a Target Computer (Kernel Mode).
-kx ExdiOptions
Starts a kernel debugging session using an EXDI driver. EXDI drivers are not described in this documentation. If you have an EXDI interface to your hardware probe or hardware simulator, please contact Microsoft for debugging information.
-lines
Enables source line debugging. If this option is omitted, the .lines (Toggle Source Line Support) command will have to be used before source debugging will be allowed. For other methods of controlling this, see SYMOPT_LOAD_LINES.
-log{o|a} LogFile
Begins logging information to a log file. If LogFile already exists, it will be overwritten if -logo is used, or output will be appended to the file if -loga is used. For more details, see Keeping a Log File.
-m
Indicates that the serial port is connected to a modem. Instructs the debugger to watch for the carrier-detect signal.
-myob
If there is a version mismatch with dbghelp.dll, the debugger will continue to run. (Without the -myob switch, this is considered a fatal error.)

A secondary effect of this option is that the warning that normally appears when breaking into the target computer is suppressed.

-n
Noisy symbol load: Enables verbose output from symbol handler. For details and for other methods of controlling this, see SYMOPT_DEBUG.
-noio
(Debugging Server only) Causes the Debugging Server to only perform its input and output remotely. For more details, see Activating the Debugging Server.
-noshell
Prohibits all .shell commands. This prohibition will last as long as the debugger is running, even if a new debugging session is begun. For details, and for other ways to disable shell commands, see Using Shell Commands.
-QR Server
Lists all Debugging Servers running on the specified network server. The double backslash (\\) preceding Server is optional. See Searching for Debugging Servers for details.

The -QR parameter must not be used with any other parameters. This command will not actually start CDB.

-r
Displays registers.
-s
Disables lazy symbol loading. This will slow down process startup. For details and for other methods of controlling this, see SYMOPT_DEFERRED_LOADS.
-sdce
Causes the debugger to display File access error dialog boxes during symbol load. For details and for other methods of controlling this, see SYMOPT_FAIL_CRITICAL_ERRORS.
-secure
Activates Secure Mode.
-ses
Causes the debugger to perform a strict evaluation of all symbol files and ignore any questionable symbols. For details and for other methods of controlling this, see SYMOPT_EXACT_SYMBOLS.
-sflags 0x Number
Sets all the symbol handler options at once. Number should be a hexadecimal number prefixed with 0x — a decimal without the 0x is permitted, but the symbol options are binary flags and therefore hexadecimal is recommended. This option should be used with care, since it will override all the symbol handler defaults. For details, see Setting Symbol Options.
-sicv
Causes the symbol handler to ignore the CV record. For details and for other methods of controlling this, see SYMOPT_IGNORE_CVREC.
-sins
Causes the debugger to ignore the symbol path and executable image path environment variables. For details, see SYMOPT_IGNORE_NT_SYMPATH.
-snc
Causes the debugger to turn off C++ translation. For details and for other methods of controlling this, see SYMOPT_NO_CPP.
-snul
Disables automatic symbol loading for unqualified names. For details and for other methods of controlling this, see SYMOPT_NO_UNQUALIFIED_LOADS.
-srcpath SourcePath
Specifies the source file search path. Separate multiple paths with a semicolon (;). If the path contains spaces, it should be enclosed in quotation marks. For details, and for other ways to change this path, see Setting Paths and Loading Files.
-sup
Causes the symbol handler to search the public symbol table during every symbol search. For details and for other methods of controlling this, see SYMOPT_AUTO_PUBLICS.
-v
Generates verbose messages for loads, deferred loads, and unloads.
-wake pid
Causes sleep mode to end for the user-mode debugger whose process ID is specified by pid. This command must be issued on the target machine during sleep mode. See Controlling the User-Mode Debugger from the Kernel Debugger for details.

The -wake parameter must not be used with any other parameters. This command will not actually start KD.

-x
Causes the debugger to break in when an exception first occurs, rather than letting the application or module that caused the exception deal with it. (Same as -b, except with an initial eb nt!NtGlobalFlag 9;g command.)
-y SymbolPath
Specifies the symbol search path. Separate multiple paths with a semicolon (;). If the path contains spaces, it should be enclosed in quotation marks. For details, and for other ways to change this path, see Setting Paths and Loading Files.
-z DumpFile
Specifies the name of a crash dump file to debug. If the path and file name contain spaces, this must be surrounded by quotation marks. It is possible to open several dump files at once by including multiple -z options, each followed by a different DumpFile value. For details, see Analyzing a Kernel-Mode Dump File with KD.
-?
Displays command-line help text.

KD will automatically detect the platform on which the target is running. You do not need to specify the target on the KD command line. The older syntax (using the name I386KD or IA64KD) is obsolete.


WinDbg Command-Line Options

First-time users of WinDbg should begin with the Debugger Operation section.

The WinDbg command line uses the following syntax:

windbg [ -server ServerOptions | -remote ClientOptions ]
   [ -premote SmartClientOptions ] [-?] [-ee {masm|c++}]
   [-clines lines] [-b] [-d] [-aExtension] [-e Event]
   [-failinc] [-g] [-G] [-hd] [-j] [-n] [-noshell] [-o]
   [-Q | -QY] [-QS | -QSY] [-robp] [-secure] [-ses] [-sdce]
   [-sicv] [-sins] [-snc] [-snul] [-sup] [-sflags 0xNumber]
   [-T Title] [-v] [-log{o|a} LogFile]
   [-i ImagePath] [-y SymbolPath] [-srcpath SourcePath]
   [-k [ConnectType] | -kl | -kx ExdiOptions] [-c "command"]
   [-pb] [-pd] [-pe] [-pr] [-pt Seconds] [-pv]
   [-W Workspace] [-WF Filename] [-WX]
   [ -p pid | -pn name | -z DumpFile | executable ]

windbg -I

Descriptions of the WinDbg command-line options follow. All command-line options are case-sensitive except for -j. The initial hyphen can be replaced with a forward-slash (/).

If the -remote or -server option is used, it must appear before any other options on the command line. If an executable is specified, it must appear last on the command line; any text after the executable name is passed to the executable program as its own command-line parameters.

Parameters

-server ServerOptions
Creates a Debugging Server that can be accessed by other debuggers. For an explanation of the possible ServerOptions, see Activating the Debugging Server.
-remote ClientOptions
Creates a Debugging Client, and connects to a Debugging Server that is already running. For an explanation of the possible ClientOptions, see Activating the Debugging Client.
-premote SmartClientOptions
Creates a Smart Client, and connects to a process server that is already running. For an explanation of the possible SmartClientOptions values, see Activating the Smart Client.
-a Extension
Sets the default extension DLL. The default is kdextx86.dll or kdexts.dll. There must be no space after the "a", and the .dll file name extension must not be included. For details, and other methods of setting this default, see Loading Debugger Extension DLLs.
-b
(Kernel mode only) This option has two effects:

1. The debugger will break into the target computer immediately upon connection.

2. After a reboot, the debugger will break into the target computer once the kernel is initialized. See Crashing and Rebooting the Target Computer for details and for other methods of changing this status.

-c "command"
Specifies the initial debugger command to run at start-up. This command must be enclosed in quotation marks. Multiple commands can be separated with semicolons. (If you have a long command list, it may be easier to put them in a script and then use the -c option with the $< (Run Script File) command.)

If you are starting a Debugging Client, this command must be intended for the Debugging Server. Client-specific commands, such as .lsrcpath, are not allowed.

-clines lines
Sets the approximate number of commands in the command history which can be accessed during remote debugging. For details, and for other ways to change this number, see Using Debugger Commands.
-d
(Kernel mode only) After a reboot, the debugger will break into the target computer as soon as a kernel module is loaded. (This break is earlier than the break from the -b option.) See Crashing and Rebooting the Target Computer for details and for other methods of changing this status.
-e Event
Signals the debugger that the specified event has occurred. This option is only used when starting the debugger programmatically.
-ee {masm|c++}
Sets the default expression evaluator. If masm is specified, MASM expression syntax will be used. If c++ is specified, C++ expression syntax will be used. If the -ee option is omitted, MASM expression syntax is used as the default. See Evaluating Expressions for details.
-failinc
Causes the debugger to ignore any questionable symbols. When debugging a user-mode or kernel-mode minidump file, this option will also prevent the debugger from loading any modules whose images can't be mapped. For details and for other methods of controlling this, see SYMOPT_EXACT_SYMBOLS.
-g
(User mode only) Ignores initial breakpoint in the target application. Normally, WinDbg stops after the main image and all statically-linked images are loaded, but before the DLL initialization routines have been run.
-G
(User mode only) Ignores final breakpoint at process termination. Typically, the debugging session ends during the image run-down process. This option will cause the debugging session to end immediately when the child terminates.
-hd
(Windows XP and Windows .NET Server 2003 only, user mode only) Specifies that the debug heap should not be used. See Behavior of Spawned Processes for details.
-I
Installl WinDbg as the postmortem debugger. For details, see Enabling Postmortem Debugging.

The -I parameter must not be used with any other parameters. This command will not actually start WinDbg.

-i ImagePath
Specifies the location of the executables that generated the fault. If the path contains spaces, it should be enclosed in quotation marks. For details, and for other ways to change this path, see Setting Paths and Loading Files.
-j
Allow journaling.
-k [ConnectType]
(Kernel mode only) Starts a kernel debugging session. For details, see Choosing Kernel Debugging Settings. If -k is used without any ConnectType options following it, it must be the final entry on the command line.
-kl
(Windows XP and Windows .NET Server 2003 only, kernel mode only) Starts a kernel debugging session on the same machine as the debugger. For more details, see Attaching to a Target Computer (Kernel Mode).
-kx ExdiOptions
(Kernel mode only) Starts a kernel debugging session using an EXDI driver. EXDI drivers are not described in this documentation. If you have an EXDI interface to your hardware probe or hardware simulator, please contact Microsoft for debugging information.
-log{o|a} LogFile
Begins logging information to a log file. If the specified log file already exists, it will be overwritten if -logo is used. If loga is used, the output will be appended to the file. For more details, see Keeping a Log File.
-n
Noisy symbol load: Enables verbose output from symbol handler. For details and for other methods of controlling this, see SYMOPT_DEBUG.
-noio
(Debugging Server only) Causes the Debugging Server to perform all input and output remotely. For more details, see Activating the Debugging Server.
-noshell
Prohibits all .shell commands. This prohibition will last as long as the debugger is running, even if a new debugging session is begun. For details, and for other ways to disable shell commands, see Using Shell Commands.
-o
(User mode only) Debugs all processes launched by the target application (child processes). By default, processes created by the one you are debugging will run as they normally do. For other methods of controlling this, see Spawning a New Process (User Mode).
-p PID
Specifies the decimal process ID to be debugged. This is used to debug a process that is already running. For details, see Attaching to a Running Process (User Mode).
-pb
(Windows XP and Windows .NET Server 2003 only, user mode only) Prevents the debugger from requesting an initial break-in when attaching to a target process. This can be useful if the application is already suspended, or if you wish to avoid creating a break-in thread in the target. See Attaching to a Running Process (User Mode).
-pd
(Windows XP and Windows .NET Server 2003 only, user mode only) Causes the target application not to be terminated at the end of the debugging session. See Ending the Debugging Session for details.
-pe
(Windows XP and Windows .NET Server 2003 only, user mode only) Indicates that the target application is already being debugged. See Re-attaching to the Target Application for details.
-pn name
Specifies the name of the process to be debugged. (This name must be unique.) This is used to debug a process that is already running. For details, see Attaching to a Running Process (User Mode).
-pr
(Windows XP and Windows .NET Server 2003 only, user mode only) Causes the debugger to start the target process running when it attaches to it. This can be useful if the application is already suspended and you wish it to resume execution. See Attaching to a Running Process (User Mode).
-pt Seconds
Specifies the break timeout, in seconds. The default is 30. See Controlling the Target for details.
-pv
(User mode only) Specifies that the debugger should attach to the target process noninvasively. For details, see Noninvasive Debugging (User Mode).
-Q
Suppresses the Save Workspace? popup windows. Workspaces are not automatically saved. See Using Workspaces for details.
-QS
Suppresses the Reload Source? popup windows. Source files are not automatically reloaded.
-QSY
Suppresses the Reload Source? popup windows and automatically reloads source files.
-QY
Suppresses the Save Workspace? popup windows and automatically saves workspaces. See Using Workspaces for details.
-robp
This allows CDB to set a breakpoint on a read-only memory page. (The default is for such an operation to fail.)
-sdce
Causes the debugger to display File access error messages during symbol load. For details and for other methods of controlling this, see SYMOPT_FAIL_CRITICAL_ERRORS.
-secure
Activates Secure Mode.
-ses
Causes the debugger to perform a strict evaluation of all symbol files and ignore any questionable symbols. For details and for other methods of controlling this, see SYMOPT_EXACT_SYMBOLS.
-sflags 0x Number
Sets all the symbol handler options at once. Number should be a hexadecimal number prefixed with 0x — a decimal without the 0x is permitted, but the symbol options are binary flags and therefore hexadecimal is recommended. This option should be used with care, since it will override all the symbol handler defaults. For details, see Setting Symbol Options.
-sicv
Causes the symbol handler to ignore the CV record. For details and for other methods of controlling this, see SYMOPT_IGNORE_CVREC.
-sins
Causes the debugger to ignore the symbol path and executable image path environment variables. For details, see SYMOPT_IGNORE_NT_SYMPATH.
-snc
Causes the debugger to turn off C++ translation. For details and for other methods of controlling this, see SYMOPT_NO_CPP.
-snul
Disables automatic symbol loading for unqualified names. For details and for other methods of controlling this, see SYMOPT_NO_UNQUALIFIED_LOADS.
-srcpath SourcePath
Specifies the source file search path. Separate multiple paths with a semicolon (;). If the path contains spaces, it should be enclosed in quotation marks. For details, and for other ways to change this path, see Setting Paths and Loading Files.
-sup
Causes the symbol handler to search the public symbol table during every symbol search. For details and for other methods of controlling this, see SYMOPT_AUTO_PUBLICS.
-T Title
Sets WinDbg window title.
-v
Enables verbose output from debugger.
-W Workspace
Loads the given named workspace. If the workspace name contains spaces, enclose it in quotation marks. For details, see Using Workspaces.
-WF Filename
Loads the workspace from the given file. Filename should include the file and the extension (usually .wew). If the workspace name contains spaces, enclose it in quotation marks. For details, see Using Workspaces.
-WX
Disables automatic workspace loading. For details, see Using Workspaces.
-y SymbolPath
Specifies the symbol search path. Separate multiple paths with a semicolon (;). If the path contains spaces, it should be enclosed in quotation marks. For details, and for other ways to change this path, see Setting Paths and Loading Files.
-z DumpFile
Specifies the name of a crash dump file to debug. If the path and file name contain spaces, this must be surrounded by quotation marks. It is possible to open several dump files at once by including multiple -z options, each followed by a different DumpFile value. For details, see Analyzing a User-Mode Dump File with WinDbg or Analyzing a Kernel-Mode Dump File with WinDbg.
executable
Specifies the command line of an executable process. This is used to launch a new process and debug it. This has to be the final item on the command line. All text after the executable name is passed to the executable as its argument string. For details, see Spawning a New Process (User Mode).
-?
Pops up this HTML Help window.

When you are running the debugger from the command line, specify arguments for the target application after application's file name. For instance:

windbg myexe arg1 arg2


KDbgCtrl Command-Line Options

The KDbgCtrl command line uses the following syntax:

kdbgctrl [-e|-d|-c] [-ea|-da|-ca] [-eu|-du|-cu] [-sdb Size | -cdb]

kdbgctrl -cx

kdbgctrl -?

Parameters

-e
Enables the Full Kernel Debugging setting.
-d
Disables the Full Kernel Debugging setting.
-c
Displays the current Full Kernel Debugging setting.
-ea
Enables the Automatic Kernel Debugging setting.
-da
Disables the Automatic Kernel Debugging setting.
-ca
Displays the Automatic Full Kernel Debugging setting.
-eu
Enables the User-Mode Error Handling setting.
-du
Disables the User-Mode Error Handling setting.
-cu
Displays the User-Mode Error Handling setting.
-sdb Size
Sets the size of the DbgPrint buffer. If Size is prefixed with 0x it will be interpreted as a hexadecimal number. If it is prefixed with 0 (zero), it will be interpreted as octal. Otherwise, it will be interpreted as decimal.
-cdb
Displays the current size of the DbgPrint buffer, in bytes.
-cx
Determines the current Full Kernel Debugging setting and returns an appropriate value. This option cannot be combined with other options, and it does not display any output. It is designed for use in a batch file where the return value of the KDbgCtrl program can be tested. Possible return values are as follows:
Value | Meaning
0x10001 | Full Kernel Debugging is enabled.
0x10002 | Full Kernel Debugging is disabled.
Any other value | An error occurred. KDbgCtrl was unable to determine the current status of Full Kernel Debugging.

-?
Displays command-line help for KDbgCtrl.

Additional Information

For a description of all the KDbgCtrl settings, see Using KDbgCtrl.


Dr. Watson Command-Line Options

The Dr. Watson command line uses the following syntax:

drwtsn32 [-i] [-g] [-p pid] [-e event] [-?] [/?]

Parameters

-i
Installs Dr. Watson as the postmortem debugger. For details, see Installing Dr. Watson as the Postmortem Debugger.
-g
Ignored. Provided for compatibility with WinDbg and CDB.
-p pid
Specifies the process ID to debug.
-e event
Specifies the event to signal for process attach completion.
-?
Displays command-line option help.
/?
Displays a pop up options screen.

Additional Information

For more information, see Dr. Watson.


Autodump+ Command-Line Options

Autodump+ uses the following syntax:

adplus.vbs [-quiet] { -hang | -quick | -crash }
   { -iis | -pn Process | -p PID }
   [-notify Name] [-o Directory] [-pageheap]

Parameters

-hang
Configures Autodump+ to run in hang mode. When Autodump+ is running in hang mode, Autodump+ must be started after the process hangs or is consuming high CPU utilization.
-quick
Configures Autodump+ to run in quick mode.
-crash
Configures Autodump+ to run in crash mode. When Autodump+ is running in crash mode, Autodump+ must be started before the process crashes or becomes unstable.
-iis
Used to debug Internet Information Server (IIS) 4.0 or later. When you use Autodump+ with the -iis option, Autodump+ monitors all of the IIS in-process (Inetinfo.exe) and out-of-process (Mtx.exe and Dllhost.exe) applications. This option can be used in addition to the -pn or -p options, or it can be used by itself to analyze IIS and all running MTS/COM+ applications in either crash, hang, or quick modes.

If you are trying to analyze an IIS 3.0 (or earlier), you should use the -pn option and specify Inetinfo.exe as the process to monitor.

-pn Process
Specifies a process name that Autodump+ should analyze. Process should include the file extension. To specify more than one process, use multiple -pn options. For example, "-pn process1.exe -pn process2.exe".
-p PID
The -p option is used to specify the process ID (PID) of a process that Autodump+ should analyze. To specify more than one process, use multiple -p options. For example, "-p 1896 -p 1702".
-notify Name
This option is only valid when Autodump+ is running in crash mode. This option tells Autodump+ to send an alert if a crash occurs. Name is the computer or user that will receive the alert. Whenever the debugger detaches from the process due to a second chance exception, or whenever a user presses CTRL+C to stop debugging, a notification will be sent to this computer or remote user or computer through the local messenger service. The local messenger service must be running on the target computer for this to work.
-o Directory
This option tells Autodump+ where to place the debug output files. Long file names and file names containing spaces should be placed within double quotation marks. If a UNC path (\\server\share) is used, Autodump+ creates a new folder immediately below the UNC path that is specified with the name of the server on which Autodump+ is running (for example, \\server\share\Web1 or \\server\share\Web2). This option is useful if Autodump+ is running on multiple computers in a Web farm that are all placing their output on the same network share.
-quiet
This option tells Autodump+ to suppress all modal dialog boxes. This option is useful if you are running Autodump+ from within a remote command shell where modal dialog boxes can cause Autodump+ to wait indefinitely for a user to press OK.

For best results, make sure this is the first option passed to ADPlus.vbs.

-pageheap
Only use this option when you want to produce a full memory dump in response to a debug break (80000003) exception. Debug break exceptions are typically raised in response to some serious error that should be investigated further if:
  • Your system is running debug builds of a DLL.
  • Your system is running a process under a debugger (for example, when Autodump+ is running in crash mode).
  • Pageheap-related options are enabled on a process through the GFlags utility. If you specify the -pageheap option on the command line, Autodump+ creates a full memory dump, and the debugger quits when a debug break exception is raised. This behavior is identical to what happens when an Administrator presses CTRL+C to stop debugging a process, except the file names are different.

Additional Information

For more information, see Autodump+.


DbgRpc Command-Line Options

The DbgRpc command line must always contain exactly one of the -l, -e, -t, -c, or -a switches. The options following these switches depend on the switch used. The -s, -p, and -r options can be used with any other options.

dbgrpc [-s Server -p ProtSeq] [-r Radix] -l -P ProcessID -L CellID1.CellID2

dbgrpc [-s Server -p ProtSeq] [-r Radix] -e [-E EndpointName]

dbgrpc [-s Server -p ProtSeq] [-r Radix] -t -P ProcessID [-T ThreadID]

dbgrpc [-s Server -p ProtSeq] [-r Radix] [-c|-a] [-C CallID] [-I IfStart] [-N ProcNum] [-P ProcessID]

dbgrpc -?

Parameters

-s Server
Allows DbgRpc to view information on a remote machine. The server name should not be preceded by slash marks. For more information on using DbgRpc remotely, see Using the DbgRpc Tool.
-p ProtSeq
Specifies the remote transport to be used. The possible values of ProtSeq are ncacn_ip_tcp (TCP protocol) and ncacn_np (named pipe protocol). TCP protocol is recommended. For more information on using DbgRpc remotely, see Using the DbgRpc Tool.
-r Radix
Specifies the radix to be used for the command parameters. The default is base 16. If the -r parameter is used, it should be placed first on the line, since it only affects parameters listed after itself. It does not affect the output of the DbgRpc tool.
-l
Displays RPC state information for the specified cell. For an example, see Get RPC Cell Information.
ProcessID
Specifies the process ID (PID) of a process. When the -l option is being used, this should be the process whose server contains the desired cell. When the -t option is being used, this should be the process containing the desired thread. When the -c or -a options are being used, this parameter is optional; it should be the server process that owns the calls you wish to display.
CellID1.CellID2
Specifies the number of the cell to be displayed.
-e
Searches the system's RPC state information for endpoint information. For an example, see Get RPC Endpoint Information.
EndpointName
Specifies the number of the endpoint to be displayed. If omitted, the endpoints for all processes on the system are displayed.
-t
Searches the system's RPC state information for thread information. For an example, see Get RPC Thread Information.
ThreadID
Specifies the thread ID of the thread to be displayed. If omitted, all threads in the specified process will be displayed.
-c
Searches the system's RPC state information for server-side call (SCALL) information. For an example, see Get RPC Call Information.
-a
Searches the system's RPC state information for client call (CCALL) information. For an example, see Get RPC Client Call Information. This option requires full RPC state information.
CallID
Specifies the call ID. This parameter is optional; include it only if you want to display calls matching a specific CallID value.
IfStart
Specifies the first DWORD of the interface's universally unique identifier (UUID) on which the call was made. This parameter is optional; include it only if you want to display calls matching a specific IfStart value.
ProcNum
Specifies the procedure number of this call. (The RPC Runtime identifies individual routines from an interface by numbering them by position in the IDL file — the first routine in the interface is 0, the second 1, and so on.) This parameter is optional; include it only if you want to display calls matching a specific ProcNum value.

Additional Information

For more information on debugging Microsoft Remote Procedure Call (RPC), see RPC Debugging.


SymChk Command-Line Options

SymChk uses the following syntax:

symchk [/r] [/v | /q [/ot] ] FileNames /s SymbolPath Options

symchk [/r] [/v | /q [/ot] ] /ie ExeName /s SymbolPath Options

symchk [/r] [/v | /q [/ot] ] /ip ProcessID /s SymbolPath Options

symchk [/r] [/v | /q [/ot] ] /it TextFileList /s SymbolPath Options

Parameters

/r
If Files specifies a directory, the /r option causes SymChk to recursively search all subdirectories under this directory for program files.
/v
Displays verbose information. This includes the file name of every program file whose symbols were investigated and whether it passed, failed, or was ignored.
/q
Enables quiet mode. All output will be suppressed (unless the /ot option is included).
/ot
Causes result totals to be displayed. This option is only useful if /q is used, because these totals are automatically displayed if quiet mode hasn't been activated.
FileNames
Specifies the program files whose symbols are to be checked. Absolute paths, relative paths, and UNC paths are permitted. An asterisk (*) wildcard is permitted. If FileNames ends in a slash, it is taken to be a directory name, and all files within that directory are checked. If FileNames contains spaces, it must be enclosed in quotation marks.
/ie ExeName
Specifies the name of a program that is currently executing. The symbols for this program will be checked. ExeName must include the file extension (usually .exe), but no path information. If there are two different executables with the same name, this option is not recommended.
/ip ProcessID
Specifies the process ID of a program that is currently executing. The symbols for this program will be checked. ProcessID must be specified as a decimal number.
/it TextFileList
Specifies a text file that contains a list of program files. The symbols for all these programs will be checked. TextFileList must specify exactly one file (by relative, absolute, or UNC path, but with no wildcards); if it contains spaces it should be enclosed in quotation marks. Within this file, each line indicates a program file (by relative, absolute, or UNC paths), and an asterisk wildcard (*) is permitted. However, any line using this wildcard must use a relative path. If a line in this file contains spaces, it should be enclosed in quotation marks. A semicolon within this file is a comment character — everything between a semicolon and the end of the line will be ignored.
/s SymbolPath
Specifies the directories containing symbols. Absolute paths, relative paths, and UNC paths are permitted. Any number of directories can be specified — multiple directories should be separated with semicolons. If you wish to specify a symbol server within this path, you should use one of the following syntaxes:
srv*DownstreamStore*\\Server\Share
srv*\\Server\Share

If SymbolPath contains spaces, it must be enclosed in quotation marks.

Options
One of the following .dbg options can be specified:
Option | Effect
/ds | SymChk will verify that .dbg information was stripped from the executable and only appears in the .dbg file, and that the executable points to the .dbg file. If the program was built without .dbg symbol files, this option has no effect. This is the default.
/de | SymChk will verify that .dbg information was not stripped from the executable and that the executable does not point to a .dbg file. If the program was built without .dbg symbol files, this option has no effect.
/dn | SymChk will verify that .dbg information is not present in the image, and that the image does not point to a .dbg file.

One of the following .pdb options can be specified:
Option | Effect
/pf | SymChk performs no checking on the contents of the .pdb file — it just verifies that the files exist and match the binary This is the default.
/ps | SymChk will verify that the .pdb files have been stripped of source line, data type, and global information.
/pt | SymChk will verify that the .pdb files contain data type information.

Any number of the following options can be specified:
Option | Effect
/cs | SymChk won't verify that CodeView data is present. (By default, the presence of CodeView data is verified.)
/ea File | SymChk won't verify symbols for the programs listed in the specified file. This allows you to veto certain programs that would otherwise be verified. File must specify exactly one file (by relative, absolute, or UNC path, but without wildcards); if it contains spaces it should be enclosed in quotation marks. Within File, each line indicates a program file (by relative, absolute, or UNC paths); no wildcards are permitted. If a line in this file contains spaces it should be enclosed in quotation marks. A semicolon within this file is a comment character — everything between a semicolon and the end of the line will be ignored. If a symbol server is being used, symbols for these programs will not be copied to the downstream store.
/ee File | Error messages for those programs listed in the specified file are suppressed. "Success" and "ignore" messages will appear as usual, and symbol files will be copied to the downstream store as usual. The format of File and the format of its contents are the same as that for /ea File.

Additional Information

For more information on SymChk, see Using SymChk.


SymStore Command-Line Options

The following syntax forms are supported for SymStore transactions. The first parameter must always be add or del. The order of the other parameters is immaterial.

symstore add [/r] [/p [/l]] /f File /s Store /t Product [/v Version] [/o] [/c Comment] [/d LogFile]

symstore add [/r] [/p [/l]] /g Share /f File /x IndexFile [/a] [/o] [/d LogFile]

symstore add /y IndexFile /g Share /s Store [/p] /t Product [/v Version] [/o] [/c Comment] [/d LogFile]

symstore del /i ID /s Store [/o] [/d LogFile]

symstore /?

Parameters

/f File
Specifies the network path of files or directories to add.
/g Share
Specifies the server and share where the symbol files were originally stored. When used with /f, Share should be identical to the beginning of the File specifier. When used with /y, Share should be the location of the original symbol files (not the index file). This allows you to later change this portion of the file path in case you move the symbol files to a different server and share.
/i ID
Specifies the transaction ID string.
/l
Allows the file specified by File to be in a local directory rather than a network path. (This option can only be used when both /f and /p are used.)
/p
Causes SymStore to store a pointer to the file, rather than the file itself.
/r
Causes SymStore to add files or directories recursively.
/s Store
Specifies the root directory for the symbol store.
/t Product
Specifies the name of the product.
/v Version
Specifies the version of the product.
/c Comment
Specifies a comment for the transaction.
/d LogFile
Specifies a log file to be used for command output. If this is not included, transaction information and other output is sent to stdout.
/o
Causes SymStore to display verbose output.
/x IndexFile
Causes SymStore not to store the actual symbol files. Instead, SymStore records information in the IndexFile that will enable SymStore to access the symbol files at a later time.
/a
Causes SymStore to append new indexing information to an existing index file. (This option is only used with the /x option.)
/y IndexFile
Causes SymStore to read the data from a file created with /x.
/?
Displays help text for the SymStore command.

Additional Information

For more information on SymStore, see Using Symbol Servers and Symbol Stores.


Environment Variables

This reference section includes:

General Environment Variables

Kernel-Mode Environment Variables

For information on using environment variables for kernel-mode debugging, see Configuring Software on the Host Computer. For information on using environment variables for user-mode debugging, see Basic User-Mode Configuration.


General Environment Variables

The following table lists the environment variables that can be used in both user-mode and kernel-mode debugging.

Variable | Meaning
_NT_DEBUGGER_EXTENSION_PATH = Path | Specifies the path that the debugger will first search for extension DLLs. Path can contain a drive letter followed by a colon (:). Separate multiple directories with semicolons (;). For details, see Loading Debugger Extension DLLs.
_NT_EXECUTABLE_IMAGE_PATH = Path | Specifies the path containing the binary executable files. Path can contain a drive letter followed by a colon (:). Separate multiple directories with semicolons (;). For details, and for other ways to change this path, see Setting Paths and Loading Files.
_NT_SOURCE_PATH = Path | Specifies the path containing the source files for the target. Path can contain a drive letter followed by a colon (:). Separate multiple directories with semicolons (;). For details, and for other ways to change this path, see Setting Paths and Loading Files.
_NT_SYMBOL_PATH = Path | Specifies the root of a directory tree containing the symbol files. Path can contain a drive letter followed by a colon (:). Separate multiple directories with semicolons (;). For details, and for other ways to change this path, see Setting Paths and Loading Files.
_NT_ALT_SYMBOL_PATH = Path | Specifies an alternate symbol path searched before _NT_SYMBOL_PATH. This is useful for keeping private versions of symbol files. Path can contain a drive letter followed by a colon (:). Separate multiple directories with semicolons (;). For details, see Setting Paths and Loading Files.
_NT_SYMBOL_PROXY = Proxy:Port | Specifies the proxy server to be used by SymSrv. For details, see Firewalls and Proxy Servers.
_NT_DEBUG_HISTORY_SIZE = Number | Specifies the number of commands in the command history that can be accessed during remote debugging. Because commands vary in length, the number of lines available may not exactly match Number. For details, and for other ways to change this number, see Using Debugger Commands.
_NT_DEBUG_LOG_FILE_OPEN = Filename | (CDB and KD only) Specifies the log file to which the debugger should send output. For details, and for other methods of writing to log files, see Keeping a Log File.
_NT_DEBUG_LOG_FILE_APPEND = Filename | (CDB and KD only) Specifies the log file to which the debugger should append output. For details, and for other methods of appending to log files, see Keeping a Log File.
_NT_EXPR_EVAL = {masm | c++} | Specifies the default expression evaluator. If masm is specified, MASM expression syntax will be used. If c++ is specified, C++ expression syntax will be used. MASM expression syntax is the default. See Evaluating Expressions for details.
_NO_DEBUG_HEAP | (Windows XP and Windows .NET Server 2003 only) Specifies that the debug heap should not be used for user-mode debugging. See Behavior of Spawned Processes for details.


Kernel-Mode Environment Variables

The following table lists the environment variables that are used only in kernel-mode debugging.

Variable | Meaning
_NT_DEBUG_PORT = ComPort | Specifies the COM port to be used in a kernel connection. For details, see Choosing Kernel Debugging Settings.
_NT_DEBUG_BAUD_RATE = BaudRate | Specifies the baud rate to be used over the COM port connection. For details, see Choosing Kernel Debugging Settings.
_NT_DEBUG_BUS = 1394 | Specifies that kernel debugging will be done over a 1394 cable connection.
_NT_DEBUG_1394_CHANNEL = 1394Channel | Specifies the channel to be used for the 1394 kernel connection. For details, see Choosing Kernel Debugging Settings.
_NT_DEBUG_1394_SYMLINK = Protocol | Specifies the connection protocol to be used for the 1394 kernel connection. For details, see Choosing Kernel Debugging Settings.
KDQUIET =Anything | If KDQUIET is defined, the debugger will run in quiet mode. Quiet mode involves three distinct effects: 1. The debugger does not display messages each time an extension DLL is loaded or unloaded. 2. The R (Registers) command no longer requires an equal sign in its syntax. 3. The debugger will not display a warning message when breaking into the target computer. Quiet mode can also be controlled by using the SQ (Set Quiet Mode) command.
_NT_DEBUG_CACHE_SIZE = Size | Specifies the maximum kernel debugging cache size, in bytes. This cache holds data received by the host computer from the serial connection. The default is 1,024,000.
_NT_DEBUG_OPTIONS = Option | Specifies one of the following two values: NOEXTWARNING tells the debugger not to output a warning when it cannot find an extension command. NOVERSIONCHECK tells the debugger not to check the version of debugger extensions. These options can be modified or displayed by using the SO command.
_NT_KD_FILES = MapFile | Specifies a driver replacement map file. For details and for other methods of controlling driver replacement, see Mapping Driver Files.


Debugger Commands

This reference section includes:

Syntax Rules

Commands

Meta-Commands

Control Keys


Syntax Rules

Any combination of uppercase and lowercase letters may be used in commands and arguments, except when specifically noted. In general, multiple command parameters can be separated by one or more spaces, or by a single comma (,). The space between a command and its first parameter can nearly always be omitted; other spaces can often be omitted if this does not cause any ambiguity.

On the individual command reference pages, characters in bold font style represent things that are literally typed, while characters in italic font style indicate parameters that are explained in the Parameters section of the reference page. Parameters in brackets are optional: [ xxx ]. Brackets with a vertical bar indicate that any one, or none, of the enclosed parameters can be used: [ xxx | yyy ]. Braces with vertical lines indicate that exactly one of the enclosed parameters must be used: { xxx | yyy }.

This reference section describes the syntax used by the following commonly-used parameter types:

Expression Syntax

Register Syntax

Pseudo-Register Syntax

Source Line Syntax

Address and Address Range Syntax

Thread Syntax

Process Syntax

System Syntax

Multiprocessor Syntax


Expression Syntax

The debugger accepts two different kinds of expressions: C++ expressions and MASM expressions. Each of these obeys its own syntax rules for input and output.

For information on when each syntax type is used, see Evaluating Expressions.

This reference section includes:

MASM Numbers and Operators

C++ Numbers and Operators

MASM Expressions vs. C++ Expressions

Expression Examples


MASM Numbers and Operators

MASM (Microsoft® Macro Assembler) expression syntax was the only syntax used by NTSD, CDB, KD, and WinDbg prior to version 4.0 of Debugging Tools for Windows.

Numerals in MASM Expressions

Numerals in MASM expressions can be input in base 16, 10, 8, or 2.

The N (Set Number Base) command can be used to set the default radix to 16, 10, or 8. All unprefixed numbers will be interpreted in this base. The default radix can be overridden by specifying the 0x prefix (hexadecimal), the 0n prefix (decimal), the 0t prefix (octal), or the 0y prefix (binary).

Hexadecimal 64-bit values can be entered in the xxxxxxxx`xxxxxxxx format, or the grave accent ( ` ) may be omitted. Including the grave accent disables automatic sign extension.

Symbols in MASM Expressions

In a MASM expression, the numerical value of any symbol is its memory address.

Either two colons ( :: ) or two underscores ( __ ) can be used to indicate the members of a class.

A grave accent ( ` ) or an apostrophe ( ' ) can be used in a symbol name only if it is prefixed by a module name and exclamation point.

Operators in MASM Expressions

Any component of an expression can be modified with a unary operator, and any two components can be combined with a binary operator. Unary operators take precedence over binary operators. When multiple binary operators are used, they follow fixed precedence rules.

Parentheses can always be used to override precedence rules.

If part of a MASM expression is enclosed in parentheses and prefixed by a double at sign ( @@ ), it will be interpreted according to C++ expression rules. There can be no space between the double at sign and the opening parenthesis.

When performing arithmetic computations, the MASM expression evaluator will treat all numbers and symbols as ULONG64 types.

Unary address operators assume DS as the default segment for addresses. Expressions are evaluated in order of operator precedence. If adjacent operators have equal precedence, the expression is evaluated from left to right.

The unary operators are:

Operator | Meaning
+ | Unary plus
- | Unary minus
not | Returns 1 if the argument is zero; returns zero for any nonzero argument
hi | High 16 bits
low | Low 16 bits
by | Low-order byte from specified address
wo | Low-order word from specified address
dwo | Double-word from specified address
qwo | Quad-word from specified address
poi | Pointer-sized data from specified address. The pointer size is either 32 bits or 64 bits. In kernel debugging, this is based on the processor of the target computer. In user-mode debugging on an IA-64 computer, this will be either 32 bits or 64 bits in size, depending on the target application. Therefore poi is the best operator to use if you want pointer-sized data.

The following table lists all binary operators. The operators in each cell take precedence over those in lower cells. Operators in the same cell are of the same precedence, and are parsed from left to right.

Operator | Meaning
* / mod (or %) | Multiplication Integer division Modulus (remainder)
+ - | Addition Subtraction
<< >> >>> | Left shift Logical right shift Arithmetic right shift
< > == (or =) != | Less than Greater than Equal to Not equal to
and (or &) | Bitwise AND
xor (or ^) | Bitwise XOR (exclusive OR)
or (or |) | Bitwise OR

The comparison operators <, >, =, ==, and != evaluate to one if true, or zero if false. A single equal sign is the same as a double equal sign; there are no side effects or assignments possible within a MASM expression.

An illegitimate operation (such as division by zero) results in an "Operand error" being returned to the Debugger Command window.

Registers and Pseudo-Registers in MASM Expressions

Registers and pseudo-registers can be used within MASM expressions. All registers and pseudo-registers can be prefixed with a single at sign ( @ ). Using this prefix will cause the debugger to access the value more quickly. This sign is unnecessary for the most common x86 registers. For other registers and pseudo-registers it is not actually required, but it is strongly recommended. If it is omitted for the less common registers, the debugger will first try to parse the text as a hexadecimal number, then as a symbol, and, finally, as a register.

You can also use a single period ( . ) to indicate the current instruction pointer. This period should not be prefixed with an at sign, and cannot be used as the first parameter of the R command. This period has the same meaning as the $ip pseudo-register.

For more details, see Register Syntax and Pseudo-Register Syntax.

Source Line Numbers in MASM Expressions

Source file and line number expressions can be used within MASM expressions. They must be surrounded by grave accents ( ` ). For details, see Source Line Syntax.


C++ Numbers and Operators

The C++ expression parser supports all forms of C++ expression syntax. This includes all data types, including pointers, floating-point numbers, and arrays, as well as all C++ unary and binary operators.

Numerals in C++ Expressions

Numerals in C++ expressions are interpreted as decimal unless otherwise specified. To specify a hexadecimal integer, prefix it with 0x. To specify an octal integer, prefix it with 0 (zero).

The default debugger radix does not affect the input of C++ expressions. It is not possible to directly input a binary number (except by nesting a MASM expression within the C++ expression).

Hexadecimal 64-bit values can be entered in the xxxxxxxx`xxxxxxxx format, or the grave accent ( ` ) can be omitted. Both formats produce the same value.

The L, U, and I64 suffixes can be used with integer values. The actual size of the resultant number depends on the suffix and the number entered; see a C++ language reference for details.

The output of the C++ expression evaluator will retain the data type dictated by the C++ expression rules. However, if this expression is used as an argument for a command, a cast will always be made. For example, you do not need to cast integer values to pointers when they are used as addresses in command arguments. If the expression's value cannot be legally cast to an integer or a pointer, a syntax error results.

The 0n (decimal) prefix is used for some output, although it is not permitted for C++ expression input.

Characters and Strings in C++ Expressions

A character can be entered by surrounding it with single quotation marks ( ' ). The standard C++ escape characters are permitted.

String literals can be entered by surrounding them with double quotation marks ( " ). The escape sequence \" can be used within such a string. However, strings have no meaning to the expression evaluator.

A grave accent ( ` ) or an apostrophe ( ' ) can be used in a symbol name only if it is prefixed by a module name and exclamation point.

Operators in C++ Expressions

Parentheses can always be used to override precedence rules.

If part of a C++ expression is enclosed in parentheses and prefixed by a double at sign ( @@ ), it will be interpreted according to MASM expression rules. There can be no space between the double at sign and the opening parenthesis. The final value of this expression will be passed to the C++ expression evaluator as a ULONG64.

Data types are indicated as usual. The symbols indicating arrays ( [ ] ), pointer members ( -> ), UDT members ( . ), and members of classes ( :: ) are all recognized. All arithmetic operators are supported, including assignment and side-effect operators. However, the new, delete, and throw operators are not permitted, and, of course, a function cannot actually be called.

Pointer arithmetic is supported and offsets are scaled correctly. Note that you cannot add an offset to a function pointer — if you need to do this, cast it to a character pointer first.

As in C++, using operators with invalid data types will result in a syntax error. The debugger's C++ expression parser uses slightly more relaxed rules than most C++ compilers, but all major rules are enforced. For example, shifting a non-integer value is forbidden.

The following table lists all available operators. The operators in each cell take precedence over those in lower cells. Operators in the same cell are of the same precedence, and are parsed from left to right. As with C++, expression evaluation terminates when its value is known; this allows expressions such as ?? myPtr && *myPtr to be used effectively.

Operator | Meaning
Expression // Comment | Disregard all subsequent text
Class :: Member Class ::~Member :: Name | Member of class Member of class (destructor) Global
Structure . Field Pointer -> Field Name [integer] LValue ++ LValue -- dynamic_cast <type>(Value) static_cast <type>(Value) reinterpret_cast <type>(Value) const_cast <type>(Value) | Field in a structure Field in referenced structure Array subscript Increment (after evaluation) Decrement (after evaluation) Typecast (always performed) Typecast (always performed) Typecast (always performed) Typecast (always performed)
(type) Value sizeof value sizeof( type ) ++ LValue -- LValue ~ Value ! Value - Value + Value & LValue * Value | Typecast (always performed) Size of expression Size of data type Increment (before evaluation) Decrement (before evaluation) Bit complement Not (Boolean) Unary minus Unary plus Address of data type Dereference
Structure . * Pointer Pointer -> * Pointer | Pointer to member of structure Pointer to member of referenced structure
Value * Value Value / Value Value % Value | Multiplication Division Modulus
Value + Value Value - Value | Addition Subtraction
Value << Value Value >> Value | Bitwise shift left Bitwise shift right
Value < Value Value <= Value Value > Value Value >= Value | Less than (comparison) Less than or equal (comparison) Greater than (comparison) Greater than or equal (comparison)
Value == Value Value != Value | Equal (comparison) Not equal (comparison)
Value & Value | Bitwise AND
Value ^ Value | Bitwise XOR (exclusive OR)
Value | Value | Bitwise OR
Value && Value | Logical AND
Value || Value | Logical OR
LValue = Value LValue *= Value LValue /= Value LValue %= Value LValue += Value LValue -= Value LValue <<= Value LValue >>= Value LValue &= Value LValue |= Value LValue ^= Value | Assign Multiply and assign Divide and assign Modulo and assign Add and assign Subtract and assign Shift left and assign Shift right and assign AND and assign OR and assign XOR and assign
Value ? Value : Value | Conditional evaluation
Value , Value | Evaluate all values, discard all but rightmost value

Registers and Pseudo-Registers in C++ Expressions

Registers and pseudo-registers can be used within C++ expressions. They must be prefixed with a single at sign ( @ ).

The expression evaluator will perform the proper cast automatically. Actual registers and integer-value pseudo-registers will be cast to ULONG64. All addresses will be cast to PUCHAR, $thread will be cast to ETHREAD*, $proc will be cast to EPROCESS*, $teb will be cast to TEB*, and $peb will be cast to PEB*.

A register or pseudo-register cannot be changed by an assignment or side-effect operator. You must use the R (Registers) command to change these values.

For more details, see Register Syntax and Pseudo-Register Syntax.


MASM Expressions vs. C++ Expressions

The most significant differences between MASM expression evaluation and C++ expression evaluation are the following:

  • In a MASM expression, the numerical value of any symbol is its memory address. In a C++ expression, the numerical value of a variable is its actual value, not its address. Data structures do not have numerical values; they are treated as actual structures and must be used accordingly. The value of a function name or any other entry point is the memory address, treated as a function pointer. A symbol that does not correspond to a C++ data type (such as an unmodified module name) will result in a syntax error.
  • The MASM expression evaluator treats all numbers as ULONG64. The C++ expression evaluator casts numerals to ULONG64, and preserves type information of all data types.
  • The MASM expression evaluator permits any operator to be used with any number. The C++ expression evaluator will generate an error if an operator is used with an inappropriate data type.
  • In the MASM expression evaluator, all arithmetic is performed literally. In the C++ expression evaluator, pointer arithmetic is scaled properly, and is forbidden when inappropriate.
  • A MASM expression can use either two underscores ( __ ) or two colons ( :: ) to indicate members of a class. The C++ expression evaluator only recognizes the two-colon syntax. Debugger output always uses two colons.
  • In a MASM expression, it is recommended that you prefix all but the most common registers with an at sign ( @ ). If this sign is omitted, the register name may be interpreted as a hexadecimal number or as a symbol. In a C++ expression, this prefix is required for all registers.
  • MASM expressions might contain references to source lines. These are indicated by grave accents ( ` ). Source line numbers cannot be referenced in a C++ expression.


Expression Examples

This section contains some examples of MASM and C++ expressions used in various commands.

In all other sections of this help file, MASM expression syntax is used in the examples (unless otherwise noted). C++ expression syntax is very useful for manipulating structures and variables, but it is not very well-suited as a parser for the parameters of debugger commands. When you are using debugger commands for general purposes, or using debugger extensions, you should set MASM expression syntax as the default. If you need a specific parameter to use C++ expression syntax, use the @@( ) syntax.

Conditional Breakpoints

Comparison operators can be used to create conditional breakpoints. (See Using Breakpoints for details.) The following example is using MASM expression syntax. Since the current default radix is 16, the 0n prefix is used so that the number 20 will be understood as decimal:

0:000> bp MyFunction+0x43 "j ( poi(MyVar)>0n20 ) ''; 'g' "

In this example, MyVar is an integer in the C source. Since the MASM parser treats all symbols as addresses, the poi operator is needed to dereference MyVar.

Conditional Expressions

The following command prints the value of ecx if eax is greater than ebx, -1 if eax is less than ebx, and -2 if eax equals ebx. This uses the MASM expression evaluator, so the single equal sign is used as a comparison operator, not an assignment operator:

0:000> ? (eax>ebx)*ecx - (eax<ebx) + (eax=ebx)*3

In C++ syntax, this command becomes:

0:000> ?? (@eax>@ebx)*@ecx - (@eax<@ebx) + (int)(@eax==@ebx)*3

C++ Expression Examples

If myInt is of type ULONG32, and you are using the MASM expression evaluator, both of the following commands will show the value of MyInt:

0:000> ?? myInt
0:000> dd myInt L1

However, the following command will show the address of myInt:

0:000> ? myInt

Mixed Expression Examples

Source-line expressions cannot be used in a C++ expression. In the following example, the @@( ) syntax is used to nest a MASM expression within a C++ expression. This sets MyPtr equal to the address of line 43 of the file myfile.c:

0:000> ?? MyPtr = @@( `myfile.c:43` )

The following commands will set the default expression evaluator to MASM, and then evaluate Expression2 as a C++ expression, while evaluating Expression1 and Expression3 as MASM expressions:

0:000> .expr /s masm
0:000> bp Expression1 + @@( Expression2 ) + Expression3

If myInt is a ULONG64, and you know that it is followed in memory by another ULONG64, you can set an access breakpoint at that location by using either of the following commands. Note the use of pointer arithmetic:

0:000> ba r8 @@( &myInt + 1 )
0:000> ba r8 myInt + 4

Structures

The C++ expression evaluator casts pseudo-registers to their appropriate types. For example, $teb is cast as a TEB*. So the following command will display the process ID:

kd> ??  @$teb->ClientId.UniqueProcess


Register Syntax

Registers and floating-point registers can be controlled by the debugger. See Reading and Writing Registers and Flags for an overview of commands that can control registers.

When using a register in an expression, it is best to precede it with an at sign ( @ ). This signals the debugger that the following text is the name of a register.

If you are using MASM expression syntax, the at sign can be omitted for certain very common registers. On the x86 systems, the registers for which this symbol is optional are eax, ebx, ecx, edx, esi, edi, ebp, eip, and efl. However, if you specify a less common register without an at sign, the debugger will first try to interpret the text as a hexadecimal number. If the text contains non-hexadecimal characters, it will next be interpreted as a symbol. Finally, if no symbol match can be found, it will be interpreted as a register.

If you are using C++ expression syntax, the at sign is always required.

The R (Registers) command is an exception to this rule. Its first argument will always be interpreted as a register; no at sign is required or permitted. If there is a second argument, it will be interpreted according to the default expression syntax. So if the default expression syntax is C++, you would need to use the following command to copy the ebx register to the eax register:

0:000> r eax = @ebx

See Processor Architecture for information on the registers and instructions peculiar to each processor.

Flags on an x86 Processor

The x86 processor also uses a number of 1-bit registers known as flags. For a list of these flags and the syntax used to view them or change them, see The x86 Flags.

Registers and Threads

Each thread has its own register values. These values are stored in the CPU registers when the thread is executing, and in memory when another thread is executing.

In user mode, any reference to a register is interpreted as the register associated with the current thread. See Controlling Processes and Threads for details.

In kernel mode, any reference to a register is interpreted as the register associated with the current register context. The register context can be set to match a specific thread, context record, or trap frame. Only the most important registers for the specified register context can actually be displayed, and their values cannot be changed. See Register Context for details.


Pseudo-Register Syntax

The debugger supports a number of pseudo-registers which hold certain values.

Automatic pseudo-registers are set by the debugger to certain useful values. User-defined pseudo-registers are integer variables that can be written to or read by the debugger operator.

All pseudo-registers begin with a dollar sign ($). If you are using MASM syntax, you can place an at sign ( @ ) before the dollar sign. This tells the debugger that the following token is a register or pseudo-register, not a symbol. If the at sign is omitted, the debugger will respond more slowly, since it will have to search through the entire symbol table.

For example, the following two commands produce the same output, but the second is faster:

0:000> ? $exp
Evaluate expression: 143 = 0000008f
0:000> ? @$exp
Evaluate expression: 143 = 0000008f

If there is an actual symbol with the same name as the pseudo-register, the at symbol is required.

If you are using C++ expression syntax, the at sign ( @ ) is always required.

The R (Registers) command is an exception to this rule. Its first argument will always be interpreted as a register or pseudo-register; no at sign is required or permitted. If there is a second argument, it will be interpreted according to the default expression syntax. So if the default expression syntax is C++, you would need to use the following command to copy the $t2 pseudo-register to the $t1 pseudo-register:

0:000> r $t1 = @$t2

Automatic Pseudo-Registers

The following table displays the pseudo-registers that are set automatically.

Pseudo-Register | Description
$ea | The last effective address displayed.
$exp | The last expression evaluated.
$ra | The return address currently on the stack. This is especially useful in execution commands. For example, g @$ra will go until the return address is hit, thus "stepping out" of the current function.
$retreg | The primary return value register: x86 processor: same as eax IA-64 processor: same as ret0
$ip | The instruction pointer register: x86 processor: same as eip IA-64 processor: related to iip (see the note following this table)
$eventip | The instruction pointer at the time of the current event. This will usually match $ip, unless you have switched threads or have manually changed the value of the instruction pointer.
$previp | The instruction pointer at the time of the previous event. (Breaking into the debugger counts as an event.)
$relip | An instruction pointer that is related to the current event. When you are branch tracing, this is the pointer to the branch source.
$exentry | The address of the entry point of the first executable of the current process.
$p | The value printed by the last D* (Display Memory) command.
$proc | The address of the current process (in other words, the address of the EPROCESS block).
$thread | The address of the current thread (in other words, the address of the ETHREAD block).
$peb | The address of the process environment block (PEB) of the current process.
$teb | The address of the thread environment block (TEB) of the current process.
$tpid | The process ID (PID) for the process that owns the current thread.
$tid | The thread ID for the current thread.
$bp Number | The address of the corresponding breakpoint. For example, $bp3 (or $bp03) refers to the breakpoint whose breakpoint ID is 3. Number is always a decimal number. If no breakpoint has an ID of Number, $bp Number evaluates to zero. For more details, see Using Breakpoints.

Some of these pseudo-registers may not be available in certain debugging scenarios. For example, $peb, $tid, and $tpid cannot be used when debugging a user-mode minidump, $previp cannot be used on the very first debugger event, and $relip cannot be used unless you are branch tracing. Using an unavailable pseudo-register will cause a syntax error.

On an IA-64 processor, the iip register is bundle-aligned and therefore is not the full instruction pointer. The $ip pseudo-register is the actual instruction pointer, including the bundle and the slot. The other pseudo-registers that hold address pointers ($ra, $retreg, $eventip, $previp, $relip, and $exentry) have the same structure as $ip on all processors.

You can use the R command to change the value of $ip. This will automatically change the corresponding register as well. When execution resumes, it will resume at the new instruction pointer address. This is the only automatic pseudo-register that can be changed manually.

Note In MASM syntax, the $ip pseudo-register can be indicated with a single period ( . ). This period should not be prefixed with an at sign, and cannot be used as the first parameter of the R command. This syntax is not permitted within a C++ expression.

User-Defined Pseudo-Registers

The pseudo-registers $t0, $t1, ..., $t9 are integer variables that can be read and written through the debugger. These can be used to store any integer value. They can be especially useful as loop variables.

To write to one of these pseudo-registers, use the R (Registers) command:

0:000> r $t0 = 7
0:000> r $t1 = 128*poi(MyVar)

Like all pseudo-registers, these can be used in any expression:

0:000> bp $t3
0:000> bp @$t4
0:000> ?? @$t1 + 4*@$t2

User-defined pseudo-registers default to zero when the debugger is started.

Note The aliases $u0, $u1, ..., $u9 are not pseudo-registers, despite their similar appearance. For details on these, see Using Aliases.

Example

The following example sets a breakpoint that will be hit every time NtOpenFile is called by the current thread, but not when it is called by other threads:

kd> bp /t @$thread nt!ntopenfile


Source Line Syntax

Source file line numbers can be specified as all or part of a MASM expression. They evaluate to the offset of the executable code corresponding to this source line.

Note Source line numbers may not be used as part of a C++ expression. See Evaluating Expressions for an explanation of when each kind of expression syntax is used.

Source file and line number expressions must be surrounded by grave accents ( ` ). The full format is as follows:

`[[module!]filename][:linenumber]`

If filename is omitted, the source file that corresponds to the current program counter is assumed.

The linenumber will be read as a decimal number unless preceded by an 0x, regardless of the current default radix. If linenumber is omitted, the expression evaluates to the initial address of the executable corresponding to the source file.

Source line expressions will not be evaluated in CDB unless a .lines (Toggle Source Line Support) command has been issued or the debugger was started with the -lines command-line option.

For more details on source debugging, see Debugging in Source Mode.


Address and Address Range Syntax

There are several ways to specify addresses in the debugger.

Addresses are always virtual addresses, except when specifically indicated otherwise.

In user mode, virtual addresses are interpreted according to the page directory of the current process. See Controlling Processes and Threads for details.

In kernel mode, virtual addresses are interpreted according to the page directory of the process specified by the process context. It is also possible to directly set the user-mode address context. See Process Context for details.

Address Modes and Segment Support

On x86 platforms, CDB and KD support two addressing modes. These modes are distinguished by their prefixes:

Prefix | Name | Mode prompt | Address types
% | flat (also 16:32) | KD> | 32-bit addresses (also 16-bit selectors pointing to 32-bit segments — x86 only)
& | virtual 86 | VMKD> | Real-mode addresses — x86 only.

If you access memory through an addressing mode that is not the current default, you can use the address mode prefixes to override the current address mode.

Address Arguments

Address arguments specify the location of variables and functions.

The following table explains the syntax and meaning of the various addresses used in CDB and KD.

Syntax | Meaning
offset | Absolute 32-bit address in virtual memory space.
&[[ segment:]] offset | Real address — x86 only.
%segment:[[ offset]] | Flat 32-bit address — x86 only.
%[[ offset]] | Flat 32-bit address.
name[[ +|– ]] offset | Flat 32-bit address; name can be any symbol. The offset specifies the offset in bytes. The address can be specified as a positive (+) or negative (–) offset.

Use the DG (Display Selector) command to view segment descriptor information.

In MASM expressions, you can also use the poi operator to dereference any pointer. For example, if the pointer at address 0x00123456 points to address location 0x00420000, the following two commands are equivalent:

0:000> dd 420000
0:000> dd poi(123456)

In C++ expressions, pointers behave just like in C++. However, numerals are interpreted as integers, so if you need to derefence an actual numeral, you must cast it first:

0:000> dd *( (long*) 0x123456 )

There are also a variety of pseudo-registers that hold common addresses, such as the current program counter location. See Pseudo-Register Syntax for details.

An address within a program can also be indicated by specifying the original source file name and line number. See Source Line Syntax for details.

Address Ranges

There are two ways to specify an address range: a pair of addresses, or an address and object count.

To use the first method, specify the starting address and the ending address. For example, the following is a range of 8 bytes beginning at the address 0x00001000:

0x00001000  0x00001007

The second form consists of an address argument, the letter L (upper or lower case), and a value argument. The address specifies the starting address; the value specifies the number of objects to be examined or displayed. The size of the object depends on the command. For example, if the object size is 1 byte, the following is a range of 8 bytes beginning at the address 0x00001000:

0x00001000  L8

However, if the object size is a double word (32 bits, or 4 bytes), the following two ranges each give an 8-byte range:

0x00001000  0x00001007
0x00001000  L2

Some commands that ask for address ranges will accept a single address as the argument. In this case, the command will use some default object count to compute the size of the range. Typically, commands for which the address range is the final parameter will allow this syntax. Refer to the individual command pages for the exact syntax and the default range size for each command.


Thread Syntax

Many debugger commands have thread identifiers as their parameters.

A tilde ( ~ ) precedes the thread identifier, which can be one of the following:

Thread Identifier | Description
~. | Current thread
~# | Thread causing present exception/debug event
~* | All threads in the process
~ddd | The thread whose ordinal is ddd

Threads are assigned ordinals as they are created. Note that this is not the same as the Thread ID used by Windows.

When debugging begins, the current thread is the one which caused the present exception or debug event (or the active thread when the debugger attached to the process). That thread remains the current thread until a new one is specified by a ~S (Set Current Thread) command, or changed by the View | Processes and Threads menu command in WinDbg.

Thread identifiers usually appear as command prefixes. Note that not all wildcards are available in all commands using thread identifiers.

Controlling Threads in Kernel Mode

In kernel mode, threads cannot be controlled in this manner. For a description of how to access thread-specific information in kernel mode, see Changing Contexts.

Note The tilde ( ~ ) character is used to specify threads during user-mode debugging. In kernel-mode debugging it is used to specify processors. See Multiprocessor Syntax for more information.


Process Syntax

Many debugger commands have process identifiers as their parameters.

A vertical bar ( | ) precedes the process identifier, which is one of the following:

Process Identifier | Description
|. | Current process
|# | Process causing present exception/debug event
|* | All processes
|ddd | The process whose ordinal is ppp

Processes are assigned ordinals as they are created. Note that this is not the same as the Process ID (PID) used by Windows.

The current process defines the memory space and the set of threads used. When debugging begins, the current process is the one which caused the present exception or debug event (or the process to which the debugger attached). That process remains the current process until a new one is specified by a |S (Set Current Process) command, or changed by the View | Processes and Threads menu command in WinDbg.

Process identifiers are used as parameters in several commands — most often as the command prefix. Note that WinDbg and CDB can debug child processes spawned by the original process, and can also attach to multiple unrelated processes.

Controlling Processes in Kernel Mode

In kernel mode, processes cannot be controlled in this manner. For a description of how to access process-specific information in kernel mode, see Changing Contexts.


System Syntax

Two vertical bars ( || ) precede the system identifier, which is one of the following:

System Identifier | Description
||. | Current system
||# | System causing present exception/debug event
||* | All systems
||ddd | The system whose ordinal is ppp

Systems are assigned ordinals in the order that the debugger attaches to them.

When debugging begins, the current system is the one that caused the present exception or debug event, or the one that the debugger most recently attached to. That remains the current system until a new one is specified by a ||S (Set Current System) command, or changed by the View | Processes and Threads menu command in WinDbg.


Multiprocessor Syntax

KD and kernel-mode WinDbg support multiple processor debugging. This can be done on any multiprocessor platform.

Processors are numbered zero through n.

If the current processor is processor 0 (that is, if it is processor zero that currently causes the debugger to be active), you can look at the other noncurrent processors (processors one through n). However, you cannot change anything in the noncurrent processors — you can only look at their state.

Selecting a Processor

You can immediately tell when you're working on a multiple processor system by the shape of the kernel debugging prompt. Notice the zero in front of the kd> prompt:

0: kd>

The 0: means you're debugging the first processor in the computer.

Use the ~S (Change Current Processor) command to switch between processors:

0: kd> ~1s
1: kd>

Now the second processor in the computer is being debugged.

You may need to change processors on a multiprocessor system if you encounter a break and the stack trace is gibberish. It's possible the break occurred on a different processor.

Specifying Processors in Other Commands

A number of commands can be preceded by a processor number. This number is not preceded by a tilde (~), except in the ~S command.

Note In user-mode debugging, the tilde is used to specify threads. See Thread Syntax for more information.

Examples

The following example uses the K (Display Stack Backtrace) command to display a stack trace from processor two:

1: kd> 2k

The following example uses the R (Registers) command to display the eax register of processor three:

1: kd> 3r eax

However, the following command gives a syntax error, because changing the state of a processor other than the currently-active one is not allowed:

1: kd> 3r eax=808080

Breakpoints

During kernel debugging, the commands BP (Set Breakpoint) and BA (Break on Access) apply to all processors of a multiple processor computer.

For example, if the current processor is three and you type

1: kd> bp SomeAddress

to put a breakpoint at SomeAddress, any processor (not just processor one) executing at that address will cause a breakpoint trap.

Displaying Processor Information

The !running extension can be used to display the status of each processor on the target computer. For each processor, !running can also display the current and next thread fields from the process control block (PRCB), the state of the sixteen built-in queued spinlocks, and a stack trace.

The !cpuinfo and !cpuid extensions can be used to display information about the processors themselves.


Commands

This section of the reference discusses the various debugger commands which can be used in CDB, KD, and WinDbg.


ENTER (Repeat Last Command)

Repeats the last command typed.

Syntax

ENTER

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

In CDB and KD, pressing the ENTER key by itself at a prompt causes the previously-entered command to be reissued.

In WinDbg, the ENTER key can be used to repeat the previous command, or can have no effect. This option can be set in the Options dialog box, which can be accessed by choosing the View | Options menu command or by pressing the following toolbar button:

If ENTER is set to repeat the last command, but you desire to create "white space" in the Debugger Command window, use the * (Comment) specifier and then press ENTER a few times.


* (Comment)

If this character is at the start of a line, then the rest of the line is treated as a comment.

Syntax

* [any string]

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

See Also

.echo (Echo Comment)


; (Command Separator)

The semicolon (;) is used to separate multiple commands on a single line.

Syntax

command1 ; command2 [; command3 ....]

Parameters

command1, command2, ...
The commands to be executed.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Commands are executed sequentially from left to right. All commands on a single line refer to the current thread, unless otherwise specified. If a command causes the thread to execute, the remaining commands on the line will be deferred until that thread stops on a debug event.

A small number of commands cannot be followed by a semicolon, since they automatically take the entire remainder of the line as their argument. These include the AS (Set Alias) command and any command beginning with the * (Comment) specifier.

Here is an example. This executes the current program to source line 123, prints the value of counter, then continues execution:

0:000> g `:123`; ? poi(counter); g


? (Command Help)

Displays a list of all commands and operators.

Note A question mark by itself (?) displays command help. The ? expression syntax evaluates the given expression.

Syntax

?

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

For help on standard commands, use ?. For help on meta-commands, use .help. For help on extension commands, use !help.


? (Evaluate Expression)

Evaluates and displays the value of an expression.

Note that a question mark by itself (?) displays command help. The ? expression syntax evaluates the given expression.

Syntax

? expression

Parameters

expression
Specifies the expression to be evaluated.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The input and output of this command depend on whether you are using MASM expression syntax or C++ expression syntax. For details, see Evaluating Expressions and Expression Syntax.

If you are using MASM syntax, the input and output depend on the current radix. To change the radix, use the N (Set Number Base) command.

Symbols in the expression are evaluated in the context of the current thread and process.

See Also

?? (Evaluate C++ Expression), .formats (Show Number Formats)


?? (Evaluate C++ Expression)

Evaluates and displays the value of an expression according to C++ expression rules.

Syntax

?? expression

Parameters

expression
Specifies the C++ expression to be evaluated. For syntax rules, see C++ Numbers and Operators.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Symbols in the expression are evaluated in the context of the current thread and process.

If you wish a component of this expression to be evaluated according to MASM expression rules, you should enclose it in parentheses and prefix it with a double "at" sign ( @@ ). For more details about MASM expressions and C++ expressions, see Evaluating Expressions and Expression Syntax.

See Also

? (Evaluate Expression), .formats (Show Number Formats)


# (Search for Disassembly Pattern)

Searches for the specified pattern in the disassembly code.

Syntax

# [Pattern] [Address | Range]

Parameters

Pattern
Specifies the pattern to search for in the disassembly code. The question mark (?) wildcard matches any single character, and the asterisk (*)wildcard matches zero or more characters. If you wish to include spaces in Pattern you must enclose it in quotation marks. The pattern is not case-sensitive. If the # command has been previously used and Pattern is omitted, the most recently-used pattern is re-used.
Address
Specifies the address at which the search will begin. For more syntax details, see Address and Address Range Syntax.
Range
Specifies the memory range to be searched. For more syntax details, see Address and Address Range Syntax.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

If the # command has been previously used, and Address and Range are omitted, the search begins where the previous search ended.

This command works by searching the disassembled text for the specified pattern. It can be used to find register names, constants, or any other string that appears in the disassembly output. Repeating the command without the Address parameter will find successive occurrences of the pattern.

Disassembly instructions can be viewed by using the U (Unassemble) command or by using the Disassembly window in WinDbg. The disassembly display appears in four columns: Address offset, Binary code, Assembly language mnemonic, and Assembly language details. Here is an example of this display:

0040116b    45          inc         ebp
0040116c    fc          cld
0040116d    8945b0      mov         eax,[ebp-0x1c]

The # command can search for text within any single column. For instance, the command

#  eax  0040116b

would find the mov eax,[ebp-0x1c] instruction at address 0040116d. The following commands would also find this instruction:

#  [ebp?0x  0040116b
#  mov  0040116b
#  8945*  0040116b
#  116d  0040116b

However, there is no way to search for mov eax* as a single unit, because mov and eax appear in different columns.

Here are some additional examples. Issuing the following command causes the debugger to search for the first reference to the strlen function after the entry point main:

# strlen main

Similarly, issuing the following two commands will find the first jnz instruction after address 0x779F9FBA, and then find the next jnz instruction after that:

# jnz 779f9fba
#

When Pattern or Address are omitted, their values are based on the previous use of the # command. If either parameter is omitted the first time the command is issued, no search is performed. However, the values of Pattern and Address are initialized even in this case. If one of the parameters is included, its value is set to the entered value. If address is omitted, it is initialized to the current value of the program counter. If Pattern is omitted, it is initialized to an empty pattern.

Additional Information

For a description of assembly debugging and related commands, see Debugging in Assembly Mode.


|| (System Status)

Prints status for the specified system, or for all systems currently being debugged.

This command should not be confused with the | (Process Status) command.

Syntax

|| System

Parameters

System
The system to be displayed. If this is omitted, all systems being debugged are displayed. For syntax details, see System Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | all

Comments

Systems can only be specified in user mode.

Unless you have attached to a process server, there will only be one system available to the debugger.

Each system listing includes the server name and the protocol details. The system that the debugger is running on is identified as <Local>.

Here are some examples of the use of this command. The following command will display all systems:

3:2:005> ||

The following command will also display all systems:

3:2:005> ||*

The following command will display the currently-active system:

3:2:005> ||.

The following command will display the system that had the most recent exception or break:

3:2:005> ||#

The following command will display system number 2:

3:2:005> ||2

Additional Information

For more details, and for other methods of displaying or controlling systems, see Debugging Multiple Systems.


||S (Set Current System)

Sets or displays the current system number.

This command should not be confused with the S (Search Memory), ~S (Change Current Processor), ~S (Set Current Thread), or |S (Set Current Process) commands.

Syntax

||System s
|| s

Parameters

System
The system to be activated. For syntax details, see System Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | all

Comments

Systems can only be specified in user mode.

If the ||s syntax is used, information about the current system is printed.

This command also disassembles the current instruction for the current system, process, and thread.

Additional Information

For more details, and for other methods of displaying or controlling systems, see Debugging Multiple Systems.


| (Process Status)

Prints status for the specified process, or for all processes currently being debugged.

This command should not be confused with the || (System Status) command.

Syntax

| Process

Parameters

Process
The process to be displayed. If this is omitted, all processes being debugged are displayed. For syntax details, see Process Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | all

Comments

Processes can only be specified in user mode.

Also note that many commands can be preceded by a process symbol. For the meaning of a pipe (|) followed by a command, see the entry for the command itself.

Unless you enabled the debugging of child processes when starting the debugging session, there will only be one process available to the debugger.

Here are some examples of the use of this command. The following command will display all processes:

2:005> |

The following command will also display all processes:

2:005> |*

The following command will display the currently-active process:

2:005> |.

The following command will display the process that originally caused the exception (or to which the debugger originally attached):

2:005> |#

The following command will display process number 2:

2:005> |2

Here is an example of the output of this command:

0:002> |
#  0 id: 224   name: myprog.exe
.  1 id: 228   name: mychild.exe

On the first line of this example, 0 is the decimal process number; 224 is the hexadecimal process ID, and myprog.exe is the application name of the process. The period (.) before process 1 means that this is the current process. The number sign (#) before process 0 means that this process was the one that originally caused the exception or that was attached to by the debugger.

Additional Information

For more details, and for other methods of displaying or controlling processes and threads, see Controlling Processes and Threads.


|S (Set Current Process)

Sets or displays the current process number.

This command should not be confused with the S (Search Memory), ~S (Change Current Processor), ~S (Set Current Thread), or ||S (Set Current System) commands.

Syntax

|Process s
| s

Parameters

Process
The process to be activated. For syntax details, see Process Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | all

Comments

Processes can only be specified in user mode.

If the |s syntax is used, information about the current process is printed.

This command also disassembles the current instruction for the current system, process, and thread.

Additional Information

For more details, and for other methods of displaying or controlling processes and threads, see Controlling Processes and Threads.


~ (Thread Status)

Prints status for the specified thread, or for all threads in the current process.

Syntax

~ Thread

Parameters

Thread
The thread to be displayed. If this is omitted, all threads are displayed. For syntax details, see Thread Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | all

Comments

Threads can only be specified in user mode. In kernel mode, the tilde (~) refers to a processor.

Also note that many commands can be preceded by a thread symbol. For an explanation of a tilde (~) followed by a command, see the entry for the command itself.

Here are some examples of the use of this command. The following command will display all threads:

0:001> ~

The following command will also display all threads:

0:001> ~*

The following command will display the currently-active thread:

0:001> ~.

The following command will display the thread that originally caused the exception (or which was active when the debugger attached to the process):

0:001> ~#

The following command will display thread number 2:

0:001> ~2

Here is an example of the output of this command:

0:001> ~
   0 id: 4dc.470 Suspend: 0 Teb 7ffde000 Unfrozen
.  1 id: 4dc.534 Suspend: 0 Teb 7ffdd000 Unfrozen
#  2 id: 4dc.5a8 Suspend: 0 Teb 7ffdc000 Unfrozen

On the first line of this example, 0 is the decimal thread number; 4DC is the hexadecimal process ID, 470 is the hexadecimal thread ID, 7FFDE000 is the address of the TEB, and Unfrozen is the thread status. The period (.) before thread 1 means that this is the current thread. The number sign (#) before thread 2 means that this thread was the one that originally caused the exception or that was active when the debugger attached to the process.

Additional Information

For more details, and for other methods of displaying or controlling processes and threads, see Controlling Processes and Threads.


~E (Thread-Specific Command)

Causes one or more commands to be executed for a specific thread, rather than for all threads in the target process.

This qualifier should not be confused with the E (Enter Values) command.

Syntax

~Thread e CommandString

Parameters

Thread
Specifies the thread or threads that CommandString will be executed for. For syntax details, see Thread Syntax.
CommandString
Specifies one or more commands to be executed. Multiple commands should be separated with semicolons. CommandString includes the remainder of the input line; all text following the e is taken as part of this string. CommandString should not be enclosed in quotation marks.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | all

Comments

Threads can only be specified in user mode. In kernel mode, the tilde (~) refers to a processor.

The ~E qualifier cannot be used with execution commands (G, GH, GN, P, T, PC, TC, TB, WT).

The ~E qualifier cannot be used with the J (Execute If-Else) or Z (Execute While) conditional commands.

If you are debugging more than one process, the ~E command cannot be used to access the virtual memory space for a non-active process.

When used with just a single thread, the ~E command simply saves a little typing. For example, the following two commands are equivalent:

0:000> ~2e r; k; kd

0:000> ~2r; ~2k; ~2kd

However, the ~E qualifier can be used to repeat a command or extension command several times. When used in this way, it can save a lot of typing. For example, the following command will repeat the extension command !gle for every single thread being debugged:

0:000> ~*e !gle

Additional Information

For a description of other commands that control threads, see Controlling Processes and Threads.


~F (Freeze Thread)

Freezes the given thread, causing it to stop and wait until it is unfrozen.

This command should not be confused with the F (Fill Memory) command.

Syntax

~Thread f

Parameters

Thread
The thread to be frozen. For syntax details, see Thread Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | all

Comments

Threads can only be specified in user mode. In kernel mode, the tilde (~) refers to a processor.

This command causes the specified thread to freeze. When the debugger lets the target application resume execution, other threads will execute normally, while this thread remains stopped.

Here are some examples.

View the current status of all threads:

~* K

Freeze thread causing current exception:

~# F

Check that the status of this thread is suspended:

~* K

Unfreeze thread 123:

~123 U

Additional Information

For an explanation of how frozen threads behave, and a list of other commands that control the freezing and suspending of threads, see Controlling Processes and Threads.


~U (Unfreeze Thread)

Unfreezes the specified thread.

This command should not be confused with the U (Unassemble) command.

Syntax

~Thread u

Parameters

Thread
The thread or threads to be unfrozen. For syntax details, see Thread Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | all

Comments

Threads can only be specified in user mode. In kernel mode, the tilde (~) refers to a processor.

Here are some examples:

View the current status of all threads:

~* K

Freeze thread causing current exception:

~# F

Check that the status of this thread is suspended:

~* K

Unfreeze thread 123:

~123 U

Additional Information

For an explanation of how frozen threads behave, and a list of other commands that control the freezing and suspending of threads, see Controlling Processes and Threads.


~N (Suspend Thread)

Suspends execution of the specified thread.

This command should not be confused with the N (Set Number Base) command.

Syntax

~Thread n

Parameters

Thread
The thread or threads to be suspended. For syntax details, see Thread Syntax.

Environment

Modes | user mode only
Targets | live debugging only
Platforms | all

Comments

Threads can only be specified in user mode. In kernel mode, the tilde (~) refers to a processor.

Each time this command is used, the thread's suspend count is increased by one.

The thread's start address is displayed when this command is used.

Additional Information

For an explanation of the suspend count and how suspended threads behave, and a list of other commands that control the suspending and freezing of threads, see Controlling Processes and Threads.


~M (Resume Thread)

Resumes execution of the specified thread.

This command should not be confused with the M (Move Memory) command.

Syntax

~Thread m

Parameters

Thread
The thread or threads to be resumed. For syntax details, see Thread Syntax.

Environment

Modes | user mode only
Targets | live debugging only
Platforms | all

Comments

Threads can only be specified in user mode. In kernel mode, the tilde (~) refers to a processor.

Each time this command is used, the thread's suspend count is decreased by one.

Additional Information

For an explanation of the suspend count and how suspended threads behave, and a list of other commands that control the suspending and freezing of threads, see Controlling Processes and Threads.


~S (Set Current Thread)

Sets or displays the current thread number.

In user mode, ~S sets the current thread. This command should not be confused with the ~S (Change Current Processor) command (which only works in kernel mode), the |S (Set Current Process) command, the ||S (Set Current System) command, or the S (Search Memory) command.

Syntax

~Thread s
~ s

Parameters

Thread
The thread to be activated. For syntax details, see Thread Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | all

Comments

Threads can only be specified in user mode. In kernel mode, the tilde (~) refers to a processor.

If the ~s syntax is used, information about the current thread is printed.

This command also disassembles the current instruction for the current system, process, and thread.

Additional Information

For more details, and for other methods of displaying or controlling processes and threads, see Controlling Processes and Threads.


~S (Change Current Processor)

Selects which processor will be debugged on a multiprocessor system.

In kernel mode, ~S changes the current processor. This command should not be confused with the ~S (Set Current Thread) command (which only works in user mode), the |S (Set Current Process) command, the ||S (Set Current System) command, or the S (Search Memory) command.

Syntax

~Processor s

Parameters

Processor
The number of the processor to be debugged.

Environment

Modes | kernel mode only
Targets | live, crash dump
Platforms | all

Comments

Processors can only be specified in kernel mode. In user mode, the tilde (~) refers to a thread.

You can immediately tell when you're working on a multiple processor system by the shape of the kernel debugging prompt. Notice the zero in front of the kd> prompt:

0: kd>

The 0: means you're debugging the first processor in the computer.

Use this command to switch between processors:

0: kd>~1s
1: kd>

Now the second processor in the computer is being debugged.

See Also

Multiprocessor Syntax


$< (Run Script File)

Reads the contents of the specified script file and uses its contents as debugger command input.

Syntax

$<Filename

Parameters

Filename
A file containing valid debugger command text. The filename must follow Microsoft® MS-DOS® filename conventions. There cannot be any spaces between the "$<" and Filename.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Both the commands themselves and their output are displayed in the Debugger Command window. When end of the script file is reached, control returns to the debugger.

Script files are not recursive and cannot be nested. If another $< command is encountered in the script file, this will cause an immediate jump to the new script file with no return.

The "$" doesn't have any special function — it's the "$<" combination that is the command.

In WinDbg, it is also possible to simply paste the additional command text directly into the Debugger Command window.


A (Assemble)

Assembles instruction mnemonics and places the resulting instruction codes into memory.

Syntax

a [address]

Parameters

address
The beginning of the block in memory at which the resulting codes will be placed. For more syntax details, see Address and Address Range Syntax.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

If no address is specified, the assembly starts at the address specified by the current value of the instruction pointer. To assemble a new instruction, type the desired mnemonic and press ENTER. To terminate assembly, press ENTER only.

Since the assembler looks up all the symbols referred to in the code, it may take some time for this command to complete. During this time, CTRL+C will not terminate the A command.

Additional Information

For a description of assembly debugging and related commands, see Debugging in Assembly Mode.


AD (Delete Alias)

Deletes an alias from the alias list.

Syntax

ad Name
ad *

Parameters

Name
The name of the alias to be deleted. If an asterisk (*) is specified, all aliases are deleted (even if there is an alias whose name is "*").

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The AD command can be used to delete any user-named alias, but it cannot be used to delete a fixed-name alias ($u0 to $u9).

Additional Information

For an explanation of how to use aliases, see Using Aliases.


AL (List Aliases)

Displays a list of all currently-defined user-named aliases.

Syntax

al

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The AL command lists all user-named aliases, but it does not list fixed-name aliases ($u0 to $u9).

Additional Information

For an explanation of how to use aliases, see Using Aliases.


AS (Set Alias)

Defines a new alias, or redefines an existing one.

Syntax

as Name Equivalent

Parameters

Name
The alias name. This can be any text string that does not contain spaces or the ENTER keystroke.
Equivalent
The alias equivalent. This can be any text string that does not contain the ENTER keystroke and does not begin with leading spaces.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

There must be at least one space between Name and Equivalent. The number of spaces between these two is irrelevant; the alias equivalent will never contain leading spaces. Absolutely any other characters are allowed, including quotation marks and semicolons. The alias equivalent can contain internal or trailing spaces.

If Name is already the name of an existing alias, that alias is redefined.

The AS command can be used to create or change any user-named alias, but it cannot be used to control a fixed-name alias ($u0 to $u9).

Additional Information

For an explanation of how to use aliases, see Using Aliases.


BA (Break on Access)

Sets a data breakpoint, which will be triggered when the specified memory is accessed.

Syntax

User-Mode Syntax

[~Thread] ba[ID] Access Size [/f PredNum] [Address [Passes]] ["CommandString"]

Kernel-Mode Syntax

ba[ID] Access Size [/p EProcess | /t EThread] [Address [Passes]] ["CommandString"]

Parameters

Thread
The thread that the breakpoint will apply to. For syntax details, see Thread Syntax. Threads can only be specified in user mode.
ID
An optional number identifying the breakpoint. If ID is not specified, the first available breakpoint number is used. There can be no space between ba and the ID number. Each processor only supports a limited number of data breakpoints, but there is no restriction on the value of the ID number itself. If ID is enclosed in square brackets ( [ ] ) it can include any expression. For more syntax details, see Expression Syntax.
Access
The type of access which will satisfy the breakpoint:
Option | Action
e (execute) | Breaks into the debugger when the CPU fetches an instruction from the specified address.
r (read/write) | Breaks into the debugger when the CPU reads or writes at the specified address.
w (write) | Breaks into the debugger when the CPU writes at the specified address.
i (i/o) | (Windows XP and Windows .NET Server 2003 only, kernel-mode only, x86 only) Breaks into the debugger when the I/O port at the specified Address is accessed.

There can be no space between Access and Size.

Size
The size of the location, in bytes, to be monitored for access. On an x86 processor, this parameter can be 1, 2, or 4 — unless Access equals e, in which case Size must be 1. On an AMD64 processor, this parameter can be 1, 2, 4, or 8 — unless Access equals e, in which case Size must be 1. On an IA-64 processor, this parameter can be any power of two, from 1 to 0x80000000. There can be no space between Access and Size.
PredNum
(IA-64 only, user mode only) Specifies a predicate number. The breakpoint will be predicated with the corresponding predicate register (for example, bp /f 4 address will set a breakpoint predicated with the p4 predicate register). For information on predicate registers, see The IA-64 Architecture.
EProcess
(Kernel mode only) Specifies a process that is associated with this breakpoint. EProcess should be the actual address of the EPROCESS structure, not the PID. The breakpoint will only be triggered if it is encountered in the context of this process.
EThread
(Kernel mode only) Specifies a thread that is associated with this breakpoint. EThread should be the actual address of the ETHREAD structure, not the thread ID. The breakpoint will only be triggered if it is encountered in the context of this process. If both /p EProcess and /t EThread are used, they may be entered in either order.
Address
Specifies any valid address. If your program accesses memory at this address, the debugger stops execution and displays the current values of all registers and flags. This address must be an offset, and suitably aligned to match the Size parameter. (For example, if Size is 4, then Address must be a multiple of 4.) If Address is omitted, the current instruction pointer is used. For more syntax details, see Address and Address Range Syntax.
Passes
This specifies the number of times the breakpoint is to be passed by until it activates. It can be any 16-bit value. The number of times the program counter will pass through this point without breaking is 1 less than the value of this number. Thus, omitting this number is the same as setting it equal to 1. Note also that this only counts times the program executes past this point; stepping or tracing past this point does not count. Once the full count has been reached, it can only be reset by clearing and re-setting the breakpoint.
CommandString
The optional CommandString parameter specifies a list of commands to be executed each time the breakpoint is taken. These commands are executed only if the breakpoint is hit after issuing a G (Go) command, rather than after a T (Trace) or P (Step) command. Debugger commands in CommandString can include parameters. This command string must be enclosed in quotation marks, and multiple commands should be separated by semicolons. Standard C control characters (such as \n and \") are allowed. Semicolons contained in second-level quotes (\") will be understood as part of the embedded quoted string.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

The ID number is used to refer to the breakpoint in subsequent BC (Breakpoint Clear), BD (Breakpoint Disable), and BE (Breakpoint Enable), commands. Use the BL (Breakpoint List) command to see the ID numbers associated with all currently-set breakpoints.

This command provides the same functionality that the debug registers provide. You can break execution when the particular memory location is read from, written to, or executed.

The breakpoint is satisfied only when the access occurs at the given address and for the specified number of bytes. If the memory accessed overlaps the specified area to monitor, the breakpoint is not satisfied.

Note that although the size is required for all breakpoint types, an execute breakpoint is only satisfied if the address is the first byte in the instruction.

When debugging a multiprocessor system in kernel mode, breakpoints set with BP (Set Breakpoint) or BA apply to all processors. For example, if the current processor is 3 and you type

3:kd> ba e1 MemoryAddress

to put a breakpoint at MemoryAddress, any processor (not just processor 3) executing at that address will cause a breakpoint trap.

The initial breakpoint in a user-mode process cannot be set with BA.

Here are some examples. The following command sets a breakpoint for read access on four bytes of the variable myVar:

0:000> ba r4 myVar

The following command places a breakpoint on all serial ports with addresses between 0x3F8 and 0x3FB, inclusive. It will be triggered if anything is read or written to these ports:

kd> ba i4 3f8

Additional Information

For more details and examples of the use of breakpoints, other breakpoint commands and methods of controlling breakpoints, information on setting breakpoints in user space from a kernel debugger, and an explanation of conditional breakpoints, see Using Breakpoints.


BC (Breakpoint Clear)

Permanently removes previously set breakpoints from the system.

Syntax

bc breakpoint
bc *

Parameters

breakpoint
The ID number of the breakpoint to be cleared.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

Use the BL (Breakpoint List) command to display currently set breakpoints, their ID numbers, and their status.

Additional Information

For more details on the use of breakpoints, other breakpoint commands and methods of controlling breakpoints, information on setting breakpoints in user space from a kernel debugger, and an explanation of conditional breakpoints, see Using Breakpoints.


BD (Breakpoint Disable)

Disables, but does not delete, previously-set breakpoints.

Syntax

bd breakpoint
bd *

Parameters

breakpoint
The ID number of the breakpoint to be disabled.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

While a breakpoint is disabled, the system does not check to see if the conditions specified in the breakpoint are valid.

Use the BE (Breakpoint Enable) command to reenable a disabled breakpoint.

Use the BL (Breakpoint List) command to display currently set breakpoints, their ID numbers, and their status.

Additional Information

For more details on the use of breakpoints, other breakpoint commands and methods of controlling breakpoints, information on setting breakpoints in user space from a kernel debugger, and an explanation of conditional breakpoints, see Using Breakpoints.


BE (Breakpoint Enable)

Restores one or more breakpoints that were previously disabled.

Syntax

be breakpoint
be *

Parameters

breakpoint
The ID number of the breakpoint to be enabled.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

Use the BL (Breakpoint List) command to display currently set breakpoints, their ID numbers, and their status.

Additional Information

For more details on the use of breakpoints, other breakpoint commands and methods of controlling breakpoints, information on setting breakpoints in user space from a kernel debugger, and an explanation of conditional breakpoints, see Using Breakpoints.


BL (Breakpoint List)

Lists current information about all breakpoints.

Syntax

bl [ID]

Parameters

ID
An optional number identifying the breakpoint. If ID is not specified, all breakpoints are listed. If ID is enclosed in square brackets ( [ ] ) it can include any expression. For more syntax details, see Expression Syntax.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

For each breakpoint, the command displays the following:

  • The breakpoint number. This is a decimal number which can be used to refer to the breakpoint in future commands.
  • The breakpoint status: either e (enabled) or d (disabled).
  • The letter u appears if the breakpoint is unresolved (that is, it doesn't match any currently-loaded module address).
  • The virtual address of the breakpoint. If source line number loading has been enabled, the BL command displays file and line number information rather than address offsets. If the breakpoint is unresolved, the address is omitted here and appears at the end of the listing instead.
  • (Data breakpoints only) Type and size information are displayed for data breakpoints. Possible types are: e (execute), r (read/write), w (write), or i (input/output). These types are followed with the size of the block, in bytes. See the BA (Break on Access) command for details.
  • The number of passes remaining until the breakpoint activates, followed by the initial number of passes in parentheses. The number of times the program counter will pass through this point without breaking is one less than the value of this number; hence this number is never lower than one. Note also that this only counts times the program executes past this point; stepping over this point does not count. Once the full count has been reached, it can only be reset by clearing and resetting the breakpoint.
  • The associated process and thread are displayed. If thread is given as "***", this indicates that this is not a thread-specific breakpoint.
  • The module and function, with offset, corresponding to the breakpoint address. If the breakpoint is unresolved, the breakpoint address appears here instead, in parentheses. If the breakpoint is set on a valid address but symbol information is missing, this field will be blank.
  • The command that will be automatically executed when this breakpoint is hit. This command is displayed in quotation marks.

Additional Information

For more details on the use of breakpoints, other breakpoint commands and methods of controlling breakpoints, information on setting breakpoints in user space from a kernel debugger, and an explanation of conditional breakpoints, see Using Breakpoints.


BP, BU, BM (Set Breakpoint)

Using Debugging Tools for Windows

BP, BU (Set Breakpoint)

[This is preliminary documentation and subject to change.]

Sets a breakpoint. You can combine locations, conditions, and options to set different kinds of breakpoints.

Syntax

User-Mode Syntax

[~Thread] bp[ID] [/f PredNum] [Address [Passes]] ["CommandString"]
[~Thread] bu[ID] [/f PredNum] [Address [Passes]] ["CommandString"]
[~Thread] bm [/f PredNum] SymbolPattern [Passes] ["CommandString"]

Kernel-Mode Syntax

bp[ID] [/p EProcess | /t EThread] [Address [Passes]] ["CommandString"]
bu[ID] [/p EProcess | /t EThread] [Address [Passes]] ["CommandString"]
bm [/p EProcess | /t EThread] SymbolPattern [Passes] ["CommandString"]

Parameters

Thread
The thread that the breakpoint will apply to. For syntax details, see Thread Syntax. Threads can only be specified in user mode. If you do not specify a thread, the breakpoint will apply to all threads.
ID
An optional number identifying the breakpoint. If ID is not specified, the first available breakpoint number is used. There can be no space between "bp" and the ID number. In kernel mode, only 32 breakpoints can be set; in user mode, any number can be set. In either case, there is no restriction on the value of the ID number itself. If ID is enclosed in square brackets ( [ ] ) it can include any expression. For more syntax details, see Expression Syntax.
PredNum
(IA-64 only, user mode only) Specifies a predicate number. The breakpoint will be predicated with the corresponding predicate register (for example, bp /f 4 address will set a breakpoint predicated with the p4 predicate register). For information on predicate registers, see The IA-64 Architecture.
EProcess
(Kernel mode only) Specifies a process that is associated with this breakpoint. EProcess should be the actual address of the EPROCESS structure, not the PID. The breakpoint will only be triggered if it is encountered in the context of this process.
EThread
(Kernel mode only) Specifies a thread that is associated with this breakpoint. EThread should be the actual address of the ETHREAD structure, not the thread ID. The breakpoint will only be triggered if it is encountered in the context of this process. If both /p EProcess and /t EThread are used, they may be entered in either order.
Address
The first byte of the instruction where the breakpoint is to be set. If Address is omitted, the current instruction pointer is used. For more syntax details, see Address and Address Range Syntax.
Passes
This specifies the number of times the breakpoint is to be passed by until it activates. It can be any 16-bit value. The number of times the program counter will pass through this point without breaking is one less than the value of this number. Thus omitting this number is the same as setting it equal to one. Note also that this only counts times the program executes past this point; stepping or tracing past this point does not count. And once the full count has been reached, it can only be reset by clearing and re-setting the breakpoint.
CommandString
The optional CommandString parameter specifies a list of commands to be executed each time the breakpoint is taken. These commands are executed only if the breakpoint is hit after issuing a G (Go) command. If this breakpoint is hit while stepping or tracing, this command will not be executed. The CommandString must be enclosed in quotation marks. Debugger commands in the CommandString can include parameters; multiple commands should be separated by semicolons. Standard C control characters (such as \n and \") are allowed. Semicolons contained in second-level quotes (\") will be understood as part of the embedded quoted string.
SymbolPattern
Specifies a pattern. The debugger will attempt to match this pattern to existing symbols, and will set breakpoints on all pattern matches. The pattern may contain wildcards: an asterisk (*) represents zero or more characters; a question mark (?) represents exactly one character; brackets ( [ ] ) containing any list of characters represent any single character in the list. A single leading underscore represents any quantity of leading underscores. Symbol matching is not case-sensitive. For more syntax details, see Symbol Syntax and Symbol Matching.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

If the breakpoint location cannot be resolved, the breakpoint will be remembered. Each new module loaded will be checked to see if the breakpoint location is in that module's space.

Breakpoints set by BP will remain until they are removed by the BC (Breakpoint Clear) command or the WinDbg Breakpoints dialog box, or until the module containing the breakpoint address is unloaded. Breakpoints set by BU will remain even if the module is unloaded — they are treated as "unresolved" and will be reactivated if the proper module is again loaded.

There are two major differences between BP breakpoints and BU breakpoints:

  • A BP breakpoint location is always converted to an address. If some module change moves the code that a BP breakpoint was set at, the breakpoint will remain at the same address. On the other hand, a BU breakpoint will remain associated with the symbolic value (usually a symbol plus an offset) that was used, and it will track this symbolic location even if its address changes.
  • If a BP breakpoint address is found in a loaded module, and that module is subsequently unloaded, the breakpoint will be removed from the breakpoint list. On the other hand, BU breakpoints persist over repeated unloads and loads.
  • Breakpoints set with BP are not saved in WinDbg workspaces. Breakpoints set with BU are saved in workspaces.

Breakpoints set by BM, or by using the mouse in WinDbg's Disassembly or Source windows have the same characteristics as BP breakpoints.

The ID number is used to refer to the breakpoint when altering it in future actions.

The BM command is useful if you wish to use wildcards in setting breakpoints. The syntax bm SymbolPattern is equivalent to using x SymbolPattern and then using BP on each of the results. For example, the following command can be used to set breakpoints on all symbols in the module myprogram which begin with the string "mem":

0:000> bm myprogram!mem*
  4: 0040d070 MyProgram!memcpy
  5: 0040c560 MyProgram!memmove
  6: 00408960 MyProgram!memset

Of course, many symbols do not represent executable code paths. Breakpoints set on these symbols using BM will have no effect. If you wish to set memory access breakpoints on variables or other read-write memory locations, use BA (Break on Access).

If you want to put a breakpoint on a C++ public, enclose the expression in parentheses. For example, bp (??MyPublic) or bp (operator new).

On x86 computers, the debugger will use debug registers to implement breakpoints if:

  • there is a debug register available
  • memory size is 1
  • memory size is 2 and address is WORD aligned
  • memory size is 4 and address is DWORD aligned

If a single logical source line spans multiple physical lines, the breakpoint will be set on the last physical line of the statement or call. If the debugger cannot set a breakpoint at the requested position, it will search in a downward direction for the next allowable position and place the breakpoint there.

If Thread is specified, breakpoints are set on the specified threads. For example, the ~*bp command sets breakpoints on all threads; ~#bp sets a breakpoint on the thread causing the current exception; and ~123bp sets a breakpoint on thread 123. The ~bp and ~.bp commands both set a breakpoint on the current thread.

When debugging a multiprocessor system in kernel mode, breakpoints set with BP or BA (Break on Access) apply to all processors. For example, if the current processor is 3 and you type

3:kd> bp MemoryAddress

to put a breakpoint at MemoryAddress, any processor (not just processor 3) executing at that address will cause a breakpoint trap.

If the breakpoint is hit, the commands in the CommandString are executed until program execution resumes. Any command which resumes program execution (such as G or T) will terminate the execution of the command list.

Here are some examples of the BP command. This sets a breakpoint 12 bytes past the beginning of the function MyTest. This breakpoint will be ignored for the first six passes; on the seventh pass execution will stop:

0:000> bp MyTest+0xb 7

This command sets a breakpoint at RtlRaiseException, displays the first argument, and continues:

kd> bp ntdll!RtlRaiseException "r a0;dd @a0;g"

Additional Information

For more details on the use of breakpoints, other breakpoint commands and methods of controlling breakpoints, information on setting breakpoints in user space from a kernel debugger, and an explanation of conditional breakpoints, see Using Breakpoints.


C (Compare Memory)

Compares the values held in two memory areas.

Syntax

c Range Address

Parameters

Range
The first of the two memory ranges to be compared. For more syntax details, see Address and Address Range Syntax.
Address
The starting address of the second memory range to be compared. The size of this range will be the same as that specified for the first range. For more syntax details, see Address and Address Range Syntax.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

If the two areas are not identical, the debugger will display all memory addresses in the first range where they do not agree.

Here is an example. Consider the following code:

void main()
{
    char rgBuf1[100];
    char rgBuf2[100];

    memset(rgBuf1, 0xCC, sizeof(rgBuf1));
    memset(rgBuf2, 0xCC, sizeof(rgBuf2));

    rgBuf1[42] = 0xFF;
}

To compare rgBuf1 and rgBuf2, use either of the following commands:

0:000> c rgBuf1 (rgBuf1+100) rgBuf2

0:000> c rgBuf1 L 100 rgBuf2

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


D, DA, DB, DC, Dd, DD, DF, DP, DQ, DU, DW, DYb, DYd (Display Memory)

Displays the contents of memory in the given range.

Syntax

d{a|b|c|d|D|f|p|q|u|w} [range]
dy{b|d} [range]
d [range]

Parameters

range
The memory area to display. For more syntax details, see Address and Address Range Syntax. If you omit range, the command will display memory starting at the ending location of the last display command. If range is omitted and no previous display command has been used, the display begins at the current instruction pointer.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Each line displayed will include the address of the first byte in the line followed by the contents of memory at that and following locations.

If you omit range, the command will display memory starting at the ending location of the last display command. This allows you to continuously scan through memory.

This command exists in the following forms. The second characters of the dd and dD commands are case-sensitive, as are the third characters of the dyb and dyd commands.

Command | Display
d | This displays data in the same format as the most recent display command. If no previous display command has been issued, d has the same effect as db. Notice that d repeats the most recent command which began with "d". This includes dds, dqs, ds, dS, dg, dl, dt, and dv, as well as the display commands on this page. If the parameters given after d are not appropriate, errors may result.
da | ASCII characters. Each line displays up to 48 characters. The display continues until the first null byte or until all characters in range have been displayed. All nonprintable characters, such as carriage returns and line feeds, are displayed as periods (.).
db | Byte values and ASCII characters. Each display line shows the address of the first byte in the line, followed by up to 16 hexadecimal byte values. The byte values are immediately followed by the corresponding ASCII values. The eighth and ninth hexadecimal values are separated by a hyphen (-). All nonprintable characters, such as carriage returns and line feeds, are displayed as periods (.). The default count is 128 bytes.
dc | Double-word values (4 bytes) and ASCII characters. Each display line shows the address of the first word in the line and up to eight hexadecimal word values, as well as their ASCII equivalent. The default count is 32 DWORDs (128 bytes).
dd | Double-word values (4 bytes). The default count is 32 DWORDs (128 bytes).
dD | Double-precision floating-point numbers (8 bytes). The default count is 15 numbers (120 bytes).
df | Single-precision floating-point numbers (4 bytes). The default count is 16 numbers (64 bytes).
dp | Pointer-sized values. This command is equivalent to dd or dq, depending on whether the target computer's processor architecture is 32-bit or 64-bit, respectively. The default count is 32 DWORDs or 16 quad-words (128 bytes).
dq | Quad-word values (8 bytes). The default count is 16 quad-words (128 bytes).
du | Unicode characters. Each line displays up to 48 characters. The display continues until the first null byte or until all characters in range have been displayed. All nonprintable characters, such as carriage returns and line feeds, are displayed as periods (.).
dw | Word values (2 bytes). Each display line shows the address of the first word in the line and up to eight hexadecimal word values. The default count is 64 words (128 bytes).
dyb | Binary values and byte values. The default count is 32 bytes.
dyd | Binary values and double-word values (4 bytes). The default count is 8 DWORDs (32 bytes).

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


DdS, DPS, DQS (Display Words and Symbols)

Displays the contents of memory in the given range. This memory is assumed to be a series of addresses in the symbol table. The corresponding symbols are displayed as well.

Syntax

dds [range]
dqs [range]
dps [range]

Parameters

range
The memory area to display. For more syntax details, see Address and Address Range Syntax. If you omit range, the command will display memory starting at the ending location of the last display command. If range is omitted and no previous display command has been used, the display begins at the current instruction pointer. If a simple address is given, the default range length is 128 bytes.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The second character of dds is case-sensitive.

The dds command displays double-word (4 byte) values like the dd command. The dqs command displays quad-word (8 byte) values like the dq command. The dps command displays pointer-sized values (4 byte or 8 byte, depending on the target computer's architecture) like the dp command.

Each of these words is treated as an address in the symbol table. The corresponding symbol information is displayed for each word.

If line number information has been enabled, source file names and line numbers will be displayed if available.

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


DG (Display Selector)

Show segment descriptor for the specified selector.

Syntax

dg FirstSelector [LastSelector]

Parameters

FirstSelector
Specifies the hexadecimal selector value of the first selector to be displayed.
LastSelector
Specifies the hexadecimal selector value of the last selector to be displayed. If this is omitted, only one selector will be displayed.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64

Comments

No more than 256 selectors can be displayed by this command.

Common selector values are:

Id | decimal | hex
KGDT_NULL | 0 | 0x00
KGDT_R0_CODE | 8 | 0x08
KGDT_R0_DATA | 16 | 0x10
KGDT_R3_CODE | 24 | 0x18
KGDT_R3_DATA | 32 | 0x20
KGDT_TSS | 40 | 0x28
KGDT_R0_PCR | 48 | 0x30
KGDT_R3_TEB | 56 | 0x38
KGDT_VDM_TILE | 64 | 0x40
KGDT_LDT | 72 | 0x48
KGDT_DF_TSS | 80 | 0x50
KGDT_NMI_TSS | 88 | 0x58


DL (Display Linked List)

Display a LIST_ENTRY or SINGLE_LIST_ENTRY linked list.

Syntax

dl[b] address maxcount size

Parameters

b
If this is included, the list is dumped in reverse order. (In other words, the debugger follows the Blinks instead of the Flinks.) This cannot be used with a SINGLE_LIST_ENTRY.
address
The starting address of the list. For more syntax details, see Address and Address Range Syntax.
maxcount
Maximum number of elements to dump.
size
Size of each element. This is the number of consecutive ULONG_PTRs which will be displayed for each element in the list.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This list must be a LIST_ENTRY or SINGLE_LIST_ENTRY structure. If this is embedded in a larger structure, be sure that address points to the linked list structure and not to the beginning of the outer structure.

The display begins with address. Therefore if you are supplying the address of a pointer which points to the beginning of the list, you should disregard the first element printed.

The address, maxcount, and size parameters are in the current default radix. You can use the N (Set Number Base) command or the 0x prefix to change the radix.

If the list loops back on itself, the dump will stop. If a null pointer is encountered, the dump will stop.

If you wish to execute some command for each element of the list, use the !list extension.

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


DS, Ds (Display String)

Displays a STRING, ANSI_STRING, or UNICODE_STRING structure. (This command does not display null-delimited character strings.)

Syntax

d{s|S} [address]

Parameters

s
Specifies that a STRING or ANSI_STRING structure is to be displayed. (This "s" is case-sensitive.)
S
Specifies that a UNICODE_STRING structure is to be displayed. (This "S" is case-sensitive.)
address
The memory address at which the string begins. For more syntax details, see Address and Address Range Syntax. If omitted, the last address used in a display command is assumed.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

If you want to display unicode strings in the Locals window or Watch window of WinDbg, you need to use the .enable_unicode (Enable Unicode Display) command first.

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


DT (Display Type)

Displays information about a local variable, global variable or data type. This can display information about simple data types, as well as structures and unions.

Syntax

User-Mode Syntax

dt [-DisplayOpts] [-SearchOpts] [module!]NAME [[-SearchOpts] Field] [Address] [-l List]
dt [-DisplayOpts] Address [-l List]
dt -h

Kernel-Mode Syntax

[Processor] dt [-DisplayOpts] [-SearchOpts] [module!]NAME [[-SearchOpts] Field] [Address] [-l List]
dt [-DisplayOpts] Address [-l List]
dt -h

Parameters

Processor
Specifies the processor which is running the process containing the information needed. For more information, see Multiprocessor Syntax. Processors can only be specified in kernel mode.
DisplayOpts
Specifies one or more of the options given in the following table. These options are preceded by a hyphen.
Option | Description
-a[quantity] | Show each array element on a new line, with its index. A total of quantity elements will be displayed. There must be no space between the a and the quantity. If -a is not followed by a digit, all items in the array are shown. The -a[quantity] switch should appear immediately before each type name or field name that you want displayed in this manner.
-b | Display blocks recursively. If a displayed structure contains sub-structures, it is expanded recursively to arbitrary depths and displayed in full. Pointers are expanded only if they are in the original structure, not in substructures.
-c | Compact output. All fields are displayed on one line, if possible. (When used with the -a switch, each array element takes one line rather than being formatted as a several-line block.)
-i | Do not indent the sub-types.
-o | Omit offset values of the structure fields.
-p | Address is a physical address rather than a virtual address.
-r[depth] | Recursively dumps the subtype fields. If depth is given, this recursion will stop after depth levels. The depth must be a digit between 1 and 9, and there must be no space between the r and the depth. The -r[depth] switch should appear immediately before the address.
-v | Verbose output. This gives additional information such as the total size of a structure and the number of its elements. When this is used along with the -y search option, all symbols are displayed, even those with no associated type information.

SearchOpts
Specifies one or more of the options given in the following table. These options are preceded by a hyphen.
Option | Description
-n | This indicates that the next parameter is a name. This should be used if the next item consists entirely of hexadecimal characters, since it will otherwise be taken as an address.
-y | This indicates that the next parameter is the beginning of the name, not necessarily the entire name. When -y is included, only the first match is displayed. If -y is not included, only exact matches will be displayed.

module
An optional parameter specifying the module which defines this structure. If there is a local variable or type with the same name as a global variable or type, you should include module to specify that you mean the global variable, since the dt command will display the local variable otherwise — even if the local variable is a case-insensitive match and the global variable is a case-sensitive match.
NAME
Specifies the name of a type or global variable. If NAME ends with an asterisk (*), a list of all matches is displayed. Thus dt A* will list all data types, globals, and statics beginning with "A", but will not display the actual instances of these types. (If the -v display option is used at the same time, all symbols will be displayed — not just those with associated type information.) You can also replace NAME with a period (.) to signify that you wish to repeat the most recently-used value of NAME. If NAME contains a space, it should be enclosed in parentheses.
Field
Specifies the field(s) to be displayed. If Field is omitted, all fields are displayed. If Field is followed by a period (.), the first-level subfields of this field will be displayed as well. If Field is followed with a series of periods, the subfields will be displayed to a depth equal to the number of periods. Any field name followed by a period will be treated as a "prefix" match, as if the -y search option was used.
Address
Specifies the address of the structure to be displayed. If NAME is omitted, Address must be included and must specify the address of a global variable. Address is taken to be a virtual address unless otherwise specified. Use the -p option to specify a physical address. Use an "at" sign ( @ ) to specify a register (for example, @eax).
List
Specifies the field name which links a linked list. The Address parameter must be included.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The DT command output will always display signed numbers in base 10, and unsigned numbers in hexadecimal.

The type information used by DT includes all type names created with typedef, including all the Windows-defined types. For example, unsigned long and char are not a valid type names, but ULONG and CHAR are. See the Platform SDK for a full list of all Windows type names.

All types created by typedefs within your own code will be present, as long as they have actually been used in your program. However, types which are defined in your headers but never actually used will not be stored in the .pdb symbol files and will not be accessible to the debugger.

The -y and -n options can precede any NAME or Field. The -y option allows you to specify the beginning of the type or structure name. For example, dt -y ALLEN will display data about the type ALLENTOWN. However, you could not display the type ALLENTOWN with dt -y A. Instead, you would have to use dt -ny A, because "A" is a valid hexadecimal value and would be interpreted as an address without the -n option.

If NAME indicates a structure, all fields will be displayed: for example, dt myStruct. If you only want one specific field, you can do dt myStruct myField: this displays the member which C would call myStruct.myField. However, note that the command dt myStruct myField1 myField2 displays myStruct.myField1 and myStruct.myField2; it does not display myStruct.myField1.myField2.

If a structure name or field is followed by a subscript, this specifies a single instance of an array. For example, dt myStruct myFieldArray[3] will display the fourth element of the array in question. But if a type name is followed by a subscript, this specifies an entire array. For example, dt CHAR[8] myPtr will display an eight-character string. The subscript is always taken as decimal regardless of the current radix; an 0x prefix will cause an error.

Because the command uses type information from the .pdb file, it can freely be used to debug any CPU platform.

If you want to display unicode strings, you need to use the .enable_unicode (Enable Unicode Display) command first. You can control the display of long integers with the .enable_long_status (Enable Long Integer Display) command.

Here are some examples. First, DT used on a global variable:

0:000> dt mt1
   +0x000 a                : 10
   +0x004 b                : 98 'b'
   +0x006 c                : 0xdd
   +0x008 d                : 0xabcd
   +0x00c gn               : [6] 0x1
   +0x024 ex               : 0x0

Here, DT displays the array field gn:

0:000> dt mt1 -a gn
   +0x00c gn :
    [00] 0x1
    [01] 0x2
    [02] 0x3
    [03] 0x4
    [04] 0x5
    [05] 0x6

The following command displays some subfields of a variable:

0:000> dt mcl1 m_t1 dpo
   +0x010 dpo  : DEEP_ONE
   +0x070 m_t1 : MYTYPE1

The following command displays the subfields of the field m_t1. Since the period automatically causes "prefix" matching, this will also display subfields of any field that begins with "m_t1":

0:000> dt mcl1 m_t1.
   +0x070 m_t1  :
      +0x000 a     : 0
      +0x004 b     : 0 ''
      +0x006 c     : 0x0
      +0x008 d     : 0x0
      +0x00c gn    : [6] 0x0
      +0x024 ex    : 0x0

You could repeat this to any depth: the command dt mcl1 a..c. would display all fields to depth four, such that the first field name began with "a" and the third field name began with "c".

The following command displays the data type MYTYPE1 which is located at the address 0x0100297C:

0:000> dt 0x0100297c MYTYPE1
   +0x000 a                : 22
   +0x004 b                : 43 '+'
   +0x006 c                : 0x0
   +0x008 d                : 0x0
   +0x00c gn               : [6] 0x0
   +0x024 ex               : 0x0

The following command displays all types and globals beginning with the string "MY" in the module thismodule:

0:000> dt thismodule!MY*
010029b8  thismodule!myglobal1
01002990  thismodule!myglobal2
          thismodule!MYCLASS1
          thismodule!MYCLASS2
          thismodule!MYCLASS3
          thismodule!MYTYPE3::u
          thismodule!MYTYPE1
          thismodule!MYTYPE3
          thismodule!MYTYPE3
          thismodule!MYFLAGS

The following command displays an array of ten ULONGs at the address 0x01002BE0:

0:000> dt -ca10 ULONG 01002be0
[0] 0x1001098
[1] 0x1
[2] 0xdead
[3] 0x7d0
[4] 0x1
[5] 0xcd
[6] 0x0
[7] 0x0
[8] 0x0
[9] 0x0

The following command continues the previous display at a different address. Note that "ULONG" does not need to be re-entered:

0:000> dt -ca4 . 01002d00
Using sym ULONG
[0] 0x12
[1] 0x4ac
[2] 0xbadfeed
[3] 0x2

Here is an example of the -b option. The structure is expanded, and the OwnerThreads array within the structure is expanded — but the Flink and Blink list pointers are not followed:

kd> dt nt!_ERESOURCE -b 0x8154f040
   +0x000 SystemResourcesList :  [ 0x815bb388 - 0x816cd478 ]
      +0x000 Flink            : 0x815bb388
      +0x004 Blink            : 0x816cd478
   +0x008 OwnerTable       : (null)
   +0x00c ActiveCount      : 1
   +0x00e Flag             : 8
   +0x010 SharedWaiters    : (null)
   +0x014 ExclusiveWaiters : (null)
   +0x018 OwnerThreads     :
    [00]
      +0x000 OwnerThread      : 0
      +0x004 OwnerCount       : 0
      +0x004 TableSize        : 0
    [01]
      +0x000 OwnerThread      : 0x8167f563
      +0x004 OwnerCount       : 1
      +0x004 TableSize        : 1
   +0x028 ContentionCount  : 0
   +0x02c NumberOfSharedWaiters : 0
   +0x02e NumberOfExclusiveWaiters : 0
   +0x030 Address          : (null)
   +0x030 CreatorBackTraceIndex : 0
   +0x034 SpinLock         : 0

Here is an example of using DT in kernel mode. The following command produces results similar to !process 0 0:

kd> dt EPROCESS -l ActiveProcessLinks.Flink -y Ima -yoi Uni 814856f0
ActiveProcessLinks.Flink at 0x814856f0
---------------------------------------------
UniqueProcessId : 0x00000008
ImageFileName : [16] "System"

ActiveProcessLinks.Flink at 0x8138a030
---------------------------------------------
UniqueProcessId : 0x00000084
ImageFileName : [16] "smss.exe"

ActiveProcessLinks.Flink at 0x81372368
---------------------------------------------
UniqueProcessId : 0x000000a0
ImageFileName : [16] "csrss.exe"

ActiveProcessLinks.Flink at 0x81369930
---------------------------------------------
UniqueProcessId : 0x000000b4
ImageFileName : [16] "winlogon.exe"

....

If you wish to execute some command for each element of the list, use the !list extension.

Finally, the dt -h command will display a short help text summarizing the DT syntax.

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


DV (Display Local Variables)

Displays the names and values of all local variables in the current scope.

Syntax

dv

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

In verbose mode, the addresses of the variables are displayed as well. (This can also be done with the X (Examine Symbols) command.)

Data structures and unfamiliar data types are not displayed in full; rather, their type name is displayed. To display the entire structure, use the DT (Display Type) command.

The local context determines which set of local variables will be displayed. By default, this context matches the current position of the program counter. For information on how this can be changed, see Local Context.

Additional Information

For details on displaying and changing local variables and a description of other memory-related commands, see Reading and Writing Memory.


E, EA, EB, ED, EP, EQ, EU, EW (Enter Values)

Using Debugging Tools for Windows

E, EA, EB, Ed, ED, EF, EP, EQ, EU, EW (Enter Values)

[This is preliminary documentation and subject to change.]

Enters the values that you specify into memory.

This command should not be confused with the ~E (Thread-Specific Command) qualifier.

Syntax

e{b|d|q|w} Address [Values]
e{a|u} Address "String"
e Address [Values]

Parameters

Address
Specifies the starting address at which to enter values. The debugger replaces the value at Address and each subsequent memory location until all Values have been used.
Values
Specifies one or more values to enter into memory. Multiple numeric values should be separated with spaces. If you do not specify any values, the current address and the value at that address will be displayed, and you will be prompted for input.
String
Specifies a string to be entered into memory. The EA command will write a NULL byte to memory at the end of this string; the EU command will write two NULL bytes to memory at the end of this string. String must be enclosed in quotation marks.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This command exists in the following forms. The second characters of the ed and eD commands are not case-sensitive.

Command | Enter
e | This enters data in the same format as the most recent enter command. (If the most recent enter command was EA or EU, the final parameter will be String and may not be omitted.)
ea | ASCII string.
eb | Byte values.
ed | Double-word values (4 bytes).
eD | Double-precision floating-point numbers (8 bytes).
ef | Single-precision floating-point numbers (4 bytes).
ep | Pointer-sized values. This command is equivalent to ed or eq, depending on whether the target computer's processor architecture is 32-bit or 64-bit, respectively.
eq | Quad-word values (8 bytes).
eu | Unicode string.
ew | Word values (2 bytes).

Numeric values will be interpreted as numbers in the current radix (16, 10, or 8). To change the default radix, use the N (Set Number Base) command. The default radix can be overridden by specifying the 0x prefix (hexadecimal), the 0n prefix (decimal), the 0t prefix (octal), or the 0y prefix (binary).

Note The default radix behaves differently when C++ expressions are being used. See Evaluating Expressions for details.

When entering byte values with the EB command, you can use single straight quotation marks to specify characters. If you wish to include multiple characters, each must be surrounded with its own quotation marks. This allows you to enter a character "string" that is not terminated by a null character. For example:

eb 'h' 'e' 'l' 'l' 'o'

C-style escape characters (such as '\0' or '\n') may not be used with these commands.

If you do not specify any values, the current address and the value at that address will be displayed, and you will be prompted for input. You can then do any of the following:

  • enter a new value, by typing the value and pressing ENTER,
  • preserve the current value in memory by pressing SPACE (the ENTER key is not needed in this case),
  • move back to the previous byte by pressing the hyphen (-),
  • exit from the command by pressing ENTER.

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


F, FP (Fill Memory)

Fills the specified memory range with a repeating pattern.

This command should not be confused with the ~F (Freeze Thread) command

Syntax

f Range Pattern
fp PhysicalRange Pattern

Parameters

Range
Specifies the range in virtual memory to fill. For more syntax details, see Address and Address Range Syntax.
PhysicalRange
Specifies the range in physical memory to fill. The syntax of PhysicalRange is the same as that of a virtual memory range, except that no symbol names are permitted.
Pattern
Specifies one or more byte values with which to fill memory.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This command will fills the memory area specified by range with the specified pattern, repeated as many times as necessary.

The pattern parameter must be input as a series of bytes. These can be entered as numeric or as ASCII characters.

Numeric values will be interpreted as numbers in the current radix (16, 10, or 8). To change the default radix, use the N (Set Number Base) command. The default radix can be overridden by specifying the 0x prefix (hexadecimal), the 0n prefix (decimal), the 0t prefix (octal), or the 0y prefix (binary).

Note The default radix behaves differently when C++ expressions are being used. See Evaluating Expressions for details.

If ASCII characters are used, each character must be enclosed in single straight quotation marks. C-style escape characters (such as '\0' or '\n') may not be used.

If multiple bytes are specified, they must be separated by spaces.

If pattern has more values than the number of bytes in the range, the debugger ignores the extra values.

Here are some examples. Assuming the current radix is 16, the following command will fill memory locations 0012FF40 through 0012FF5F with the pattern "ABC", repeated over and over:

0:000> f 0012ff40 L20 'A' 'B' 'C'

The following command has the exact same effect:

0:000> f 0012ff40 L20 41 42 43

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


G (Go)

Starts executing the given process or thread. Execution will halt at the end of the program, when breakaddress is hit, or when another event causes the debugger to stop.

Syntax

User-Mode Syntax

[~thread] g [= startaddress] [breakaddress ...]

Kernel-Mode Syntax

g [= startaddress] [breakaddress ...]

Parameters

thread
The thread to execute. For syntax details, see Thread Syntax. Threads can only be specified in user mode.
startaddress
The address at which execution should begin. If this is not specified, the debugger passes execution to the address specified by the current value of the instruction pointer. For more syntax details, see Address and Address Range Syntax.
breakaddress
The address for an unconditional breakpoint. If breakaddress is specified, it must specify an instruction address (that is, the address must contain the first byte of an instruction). Up to 10 break addresses, in any order, can be specified at one time. For more syntax details, see Address and Address Range Syntax.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

If thread is specified then the go command is executed with the specified thread unfrozen, and all others frozen. For example, if the ~123g, ~#g, or ~*g command is specified, the specified threads are unfrozen and all others are frozen.

Additional Information

For other methods of issuing this command and an overview of related commands, see Controlling the Target.


GH (Go with Exception Handled)

Marks the given thread's exception as having been handled and allows the thread to restart execution at the instruction that caused the exception.

Syntax

[~thread] gh [= startaddress] [breakaddress ...]

Parameters

thread
The thread to execute. This thread must have been stopped by an exception. For syntax details, see Thread Syntax.
startaddress
The address at which execution should begin. If this is not specified, the debugger passes execution to the address where the exception occurred. For more syntax details, see Address and Address Range Syntax.
breakaddress
The address for an unconditional breakpoint. If breakaddress is specified, it must specify an instruction address (that is, the address must contain the first byte of an instruction). Up to 10 break addresses, in any order, can be specified at one time. For more syntax details, see Address and Address Range Syntax.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

The breakpoint associated with breakaddress will only be hit by the current thread. Other threads that execute the code at that location will not be stopped.

If thread is specified then the go command is executed with the specified thread unfrozen, and all others frozen. For example, if the ~123g, ~#g, or ~*g command is specified, the specified threads are unfrozen and all others are frozen.

Additional Information

For other methods of issuing this command and an overview of related commands, see Controlling the Target.


GN (Go with Exception Not Handled)

Continues execution of the given thread without marking the exception as having been handled. This allows the application's exception handler to handle the exception.

Syntax

[~thread] gn [= startaddress] [breakaddress ...]

Parameters

thread
The thread to execute. This thread must have been stopped by an exception. For syntax details, see Thread Syntax.
startaddress
The address at which execution should begin. If this is not specified, the debugger passes execution to the address where the exception occurred. For more syntax details, see Address and Address Range Syntax.
breakaddress
The address for an unconditional breakpoint. If breakaddress is specified, it must specify an instruction address (that is, the address must contain the first byte of an instruction). Up to 10 break addresses, in any order, can be specified at one time. For more syntax details, see Address and Address Range Syntax.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

The breakpoint associated with breakaddress will only be hit by the current thread. Other threads that execute the code at that location will not be stopped.

If thread is specified then the go command is executed with the specified thread unfrozen, and all others frozen. For example, if the ~123g, ~#g, or ~*g command is specified, the specified threads are unfrozen and all others are frozen.

Additional Information

For other methods of issuing this command and an overview of related commands, see Controlling the Target.


IB, ID, IW (Input from Port)

Inputs and displays a byte, word, or double word from the selected port.

Syntax

ib address
iw address
id address

Parameters

address
The address of the port.

Environment

Modes | kernel mode only
Targets | live debugging only
Platforms | x86 only

Comments

The IB command reads a single byte, IW reads a word, and ID reads a double word.

You should be careful that reading the I/O port does not affect the behavior of the device you are reading from. Some devices change state after a read-only port has been read. You also should not attempt to read a word or double-word from a port that does not allow values of this length.

See Also

OB, OD, OW (Output to Port)


J (Execute If - Else)

Conditionally executes commands, depending on the truth of a given condition.

Syntax

j Expression Command1 ; Command2
j Expression 'Command1' ; 'Command2'

Parameters

Expression
The expression to be tested. If this evaluates to a non-zero value, Command1 is executed. If this evaluates to zero, Command2 is executed. For more syntax details, see Expression Syntax.
Command1
The command-string to be executed if the test is true. Multiple commands can be combined by surrounding the command-string with single straight quotation marks ( ' ) and separating commands with semicolons. If this is a single command, the single quotation marks are optional.
Command2
The command-string to be executed if the test is false. Multiple commands can be combined by surrounding the command-string with single straight quotation marks ( ' ) and separating commands with semicolons. If this is a single command, the single quotation marks are optional.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The J command cannot be followed by a semicolon and additional commands; additional commands will be disregarded.

The following command displays the value of eax if MySymbol is equal to zero, and displays the values of ebx and ecx otherwise:

0:000> j (MySymbol=0) 'r eax'; 'r ebx; r ecx'

The quotes around r eax could be omitted, but they make the command easier to read. If you wish to omit one of the commands entirely, you can either include quotes around nothing, or omit that parameter entirely:

0:000> j (MySymbol=0) ''; 'r ebx; r ecx'
0:000> j (MySymbol=0)  ; 'r ebx; r ecx'

This command can also be used inside of other commands — for instance, to create conditional breakpoints:

0:000> bp `mysource.cpp:143` "j (poi(MyVar)>0n20) ''; 'g' "

See Using Breakpoints for a full explanation of this syntax.

See Also

Z (Execute While)


K, KB, KD, KP, KV (Display Stack Backtrace)

Displays the stack frame of the given thread, along with related information..

Syntax

User-Mode Syntax

[~Thread] k[b|p|v] [n] [f] [L] [FrameCount]
[~Thread] k[b|p|v] [n] [f] [L] = BasePtr [FrameCount]
[~Thread] k[b|p|v] [n] [f] [L] = BasePtr StackPtr InstructionPtr
[~Thread] kd [WordCount]

Kernel-Mode Syntax

[Processor] k[b|p|v] [n] [f] [L] [FrameCount]
[Processor] k[b|p|v] [n] [f] [L] = BasePtr [FrameCount]
[Processor] k[b|p|v] [n] [f] [L] = BasePtr StackPtr InstructionPtr
[Processor] kd [WordCount]

Parameters

Thread
Specifies the thread whose stack is to be displayed. If this is omitted, the current thread is assumed. For syntax details, see Thread Syntax. Threads can only be specified in user mode.
Processor
Specifies the processor whose stack is to be displayed. For more information, see Multiprocessor Syntax. Processors can only be specified in kernel mode.
b
Causes the display to include the first three parameters passed to each function.
p
Causes the display to include the full parameters for each function called in the stack trace. This listing will include each parameter's data type, name, and value. This requires full symbol information.
v
Causes the display to include FPO information. On x86 processors, calling convention information is displayed as well.
n
Causes frame numbers to be displayed.
f
Causes the distance between adjacent frames to be displayed. This "distance" is the number of bytes separating the frames on the actual stack.
L
Causes source lines to not be displayed. "L" is case-sensitive.
FrameCount
Specifies the number of stack frames to display. This should be in hexadecimal, unless the radix has been changed using the N (Set Number Base) command. The default value is 20 (0x14), unless the default value has been changed using the .kframes (Set Stack Length) command.
BasePtr
If there is an equal sign after the command, the next argument is taken to specify the base pointer for the stack trace. On an x86 processor, this can be followed by one more argument (which is interpreted as the FrameCount), or by two more arguments (which are interpreted as the InstructionPtr and the StackPtr).
StackPtr
(x86 processor only) Specifies the stack pointer for the stack trace (esp).
InstructionPtr
(x86 processor only) Specifies the instruction pointer for the stack trace (eip).
WordCount
Specifies the number of DWORD_PTRs in the stack to dump. The default value is 20 (0x14), unless the default value has been changed using the .kframes (Set Stack Length) command.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

When the K, KB, KP, or KV command is issued, a stack trace is displayed in a tabular format. If line loading is enabled, source modules and line numbers are displayed as well.

The stack trace will include the base pointer for the stack frame, the return address, and function names.

If the KP command is used, the full parameters for each function called in the stack trace will be displayed. This listing will include each parameter's data type, name, and value. This command may be slow. When MyFunction1 calls MyFunction2, the debugger must have full symbol information for MyFunction1 in order to display the parameters passed in this call. Internal Windows routines which are not exposed in public symbols will not be fully displayed by this command.

If the KB or KV commands are used, the first three parameters passed to each function are displayed. If the KV command is used, FPO data is displayed as well.

On an x86 processor, the KV command also displays calling convention information.

On an IA-64 processor, the KV command also causes nonvolatile registers to be displayed. This allows you to trace the register stack.

When the KV command is used, the FPO information is added at the end of the line. It takes the following format:

FPO text Meaning
FPO: [non-Fpo]
 No FPO data for frame
FPO: [N1,N2,N3]
 N1 is the total number of parameters.

N2 is the number of DWORDs for the locals.

N3 is number of registers saved.

FPO: [N1,N2] TrapFrame @ Address
 N1 is the total number of parameters.

N2 is the number of DWORDs for the locals.

Address is the address of the trap frame.

FPO: TaskGate Segment:0
 Segment is task gate segment selector.
FPO: [EBP 0xBase]
 Base is the base pointer for the frame.

The KD command displays the raw stack data. Each DWORD is displayed on a separate line. Symbol information is displayed for those lines with associated symbols. This results in a much more detailed list than the other K* commands. The KD command is equivalent to a DdS (Display Memory) with the stack address as its parameter.

Using the K command at the beginning of a function (before the function prolog has been executed) will give incorrect results. The debugger uses the frame register to compute the current backtrace, and this register is not correctly set for a function until its prolog has been executed.

In user mode, the stack trace is based on the stack of the current thread. See Controlling Processes and Threads for details.

In kernel mode, the stack trace is based on the current register context. The register context can be set to match a specific thread, context record, or trap frame. See Register Context for details.

Additional Information

For more information on stack traces, and for other ways to display stack traces, see Viewing the Call Stack. For more information on the register context and other context settings, see Changing Contexts.


L+, L- (Set Source Options)

Sets the source line options which control source display and program stepping options.

Syntax

l+option
l-option
l{+|-}

Parameters

+ or -
This signifies whether a given option is to be toggled on or off.
option
This can be any one of the following options. Options must be in lower-case.
l
Source line numbers will be displayed at the command prompt. Source file name and line numbers will also be displayed when executing the LN (List Nearest Symbols) command.
o
When stepping through code, all messages other than the source line and line number are suppressed. (The s option must also be active for this to have any effect.)
s
Source lines and source line numbers will be displayed at the command prompt.
t
Activates source mode. If this is not set, the debugger is in assembly mode.
*
This signifies that all options are to be turned on (or off).

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

If option is omitted, the current options are displayed. In this case, the l+ and l- commands have identical effects; however, either + or - must be included for this command to work.

Only one option can be included each time this command is issued. If more than one option is listed, only the first will be detected. However, by repeatedly issuing this command you can turn on or off as many options as you need. (In other words, l+lst will not work, but l+l; l+s; l+t will achieve the desired effect.)

When the s option is active, both source lines and line numbers will be displayed during stepping, regardless of whether the l option is active. The o option has no effect unless the s option is active.

Source line options do not take effect unless line number loading has been enabled by using the .lines (Toggle Source Line Support) command or the -lines command-line option. This option defaults to "on" in WinDbg, and "off" in CDB.

Additional Information

For a description of source debugging and related commands, see Debugging in Source Mode. For a description of assembly debugging and related commands, see Debugging in Assembly Mode.


LD (Load Symbols)

Loads symbols for the specified module, and refreshes all module information.

Syntax

ld [modulename]

Parameters

modulename
Module whose symbols are to be loaded.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The debugger's default behavior is to use lazy symbol loading (also called deferred symbol loading). This means that symbols are not actually loaded until they are needed.

The LD command forces all symbols for the specified module to be actually loaded.

Additional Information

For more details on deferred (lazy) symbol loading, see Deferred Symbol Loading. For information on other symbol options, see Setting Symbol Options.


LM (List Loaded Modules)

Lists the specified loaded modules. The output includes the status and the path to the module.

Syntax

lm Options [mPattern]

Parameters

Options
Any of the following can be included:
l
Causes only loaded symbol information to be displayed.
v
Causes the display to be verbose. Checksum information, date stamps, and time stamps are displayed. Both the symbol file name and the image file name are displayed.
u
(Kernel mode only) Causes the display to include only user-mode symbol information.
k
(Kernel mode only) Causes the display to include only kernel-mode symbol information.

In addition, at most one of the following can be included. If none of these are included, the display will include the symbol file name:

f
Causes the display to include the full image path. (This will always match the path displayed in the initial load notification, unless a .reload -s has been issued.)
i
Causes the display to include the image file name.
p
Causes the display to include the mapped image name.
t
Causes the display to only include the basic image names and the file timestamps.
m Pattern
Specifies a pattern that the module name must match. You can use wildcards: the asterisk (*) represents zero or more characters; the question mark (?) represents exactly one character; brackets ( [ ] ) containing any list of characters represent any single character in the list. A single leading underscore represents any quantity of leading underscores. There can be no space between the m and the Pattern.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The LM command will list all the modules and the status of symbols for each module.

Windows .NET Server 2003 maintains an unloaded module list for user-mode processes. When you are debugging a user-mode process or dump file, the LM command will show these unloaded modules as well.

Here is an example of this command with a Windows .NET Server 2003 target computer. The m option is followed by "s*", and therefore only modules beginning with "s" are displayed:

kd> lm ms*
start    end        module name
f9f73000 f9f7fd80   sysaudio     (deferred)
fa04b000 fa09b400   srv          (deferred)
faab7000 faac8500   sr           (deferred)
facac000 facbae00   serial       (deferred)
fb008000 fb00ba80   serenum      e:\mysymbols\SereEnum.pdb\.......
fb24f000 fb250000   swenum       (deferred)

Unloaded modules:
f9f53000 f9f61000   swmidi.sys
fb0ae000 fb0b0000   splitter.sys
fb040000 fb043000   Sfloppy.SYS

Note that the module name does not have an extension. So if you wanted to display information about the flpydisk.sys driver, you would use the command lm mflpydisk, not lm mflpydisk.sys.

For an explanation of the various status values, see Symbol Status Abbreviations.


LN (List Nearest Symbols)

Displays the symbols at or near the given address.

Syntax

ln address

Parameters

address
The address at which to begin searching for symbols. The nearest symbols, either before or after address, are displayed. For more syntax details, see Address and Address Range Syntax.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

You can use this command to help determine what a pointer is pointing to. It also can be useful when looking at a corrupted stack to determine which procedure made a call.

If source line information is available, you can use the L+l command to cause source file name and line number information to be displayed when the LN command is issued.


LS, LSA (List Source Lines)

Displays a series of lines from the current source file, and advances the current source line number.

Syntax

ls [.] [first] [, count]
lsa [.] address [, first [, count]]

Parameters

.
This causes the command to look for the source file being used by the debugger engine or by the .srcpath (Set Source Path) command. If the period is not included, LS will use the file most recently loaded with the LSF (Load Source File) command.
address
The address where the source display is to begin. For more syntax details, see Address and Address Range Syntax.
first
The first line to be displayed. The default is the current line.
count
The quantity of lines to be displayed. The default is 20 (0x14), unless this has been changed with the LSP -a command.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

After this command is executed, the current line is redefined as the final line displayed plus one. This current line is used in future LS, LSA, and LSC commands.

See Also

LSC (List Current Source), LSF, LSF- (Load or Unload Source File)


LSC (List Current Source)

Displays the current source file name and line number.

Syntax

lsc

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

See Also

LS, LSA (List Source Lines), LSF, LSF- (Load or Unload Source File)


LSF, LSF- (Load or Unload Source File)

Loads or unloads a source file.

Syntax

lsf filename
lsf- filename

Parameters

filename
The file to load or unload. If this file is not located in the directory from which the debugger was launched, an absolute or relative path must be included. The filename must follow MS-DOS filename conventions.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

LSF loads a file. LSF- unloads a file.

Successfully executing an LSF command automatically unloads any previously-loaded file.

In CDB or KD, this file can be browsed in the Debugger Command window. In WinDbg, this file will be loaded as a new Source window.

For more details on source files and source paths, and for other ways to load source files, see Setting Paths and Loading Files.

See Also

LS, LSA (List Source Lines), LSC (List Current Source)


LSP (Set Number of Source Lines)

Controls how many source lines are displayed while stepping and executing, or while using LS and LSA commands.

Syntax

lsp [-a] LeadingLines TrailingLines
lsp [-a] TotalLines
lsp [-a]

Parameters

-a
Causes this command to set or display the number of lines shown by LS and LSA. If -a is omitted, this command will set or display the number of lines shown while stepping and executing.
LeadingLines
Specifies the number of lines to show prior to the current line.
TrailingLines
Specifies the number of lines to show after the current line.
TotalLines
Specifies the total number of lines to show. This will be divided evenly between leading and trailing lines. (If this number is odd, trailing lines will be the larger of the two.)

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

When LSP is used with no parameters, it will display the current leading line and trailing line values used while stepping. When it is used with just the -a parameter, it will display the values used while stepping and used for LS and LSA commands.

When you step through a program or break in after program execution, the number of leading and trailing lines displayed is determined by the previous LSP command. When you use LSA, the number of leading and trailing lines displayed is determined by the previous LSP -a command. When you use LS, all lines appear as a single block, so the total number of lines shown is determined by the previous LSP -a command.

Additional Information

For a description of source debugging and related commands, see Debugging in Source Mode.


M (Move Memory)

Copies the contents of memory from one location to another.

This command should not be confused with the ~M (Resume Thread) command.

Syntax

m range address

Parameters

range
The memory area to copy. For more syntax details, see Address and Address Range Syntax.
address
The starting address of the destination memory area. For more syntax details, see Address and Address Range Syntax.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

It is legal for address to be part of range. Overlapping moves are handled correctly.

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


N (Set Number Base)

Sets the default number base (radix) to the specified value, or displays the current number base.

This command should not be confused with the ~N (Suspend Thread) command.

Syntax

n [radix]

Parameters

radix
The default number base used for numeric display and entry. The following are legal values.
Value | Description
8 | Octal
10 | Decimal
16 | Hexadecimal

If radix is omitted, the current default number base is displayed.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The current radix affects the input and output of MASM expressions. It does not affect the input or output of C++ expressions. For details, see Evaluating Expressions.

The default radix is set to 16 when the debugger is started.

In all MASM expressions, numeric values will be interpreted as numbers in the current radix (16, 10, or 8). The default radix can be overridden by specifying the 0x prefix (hexadecimal), the 0n prefix (decimal), the 0t prefix (octal), or the 0y prefix (binary).


OB, OD, OW (Output to Port)

Sends a byte, word, or double word to the selected port.

Syntax

ob address value
ow address value
od address value

Parameters

address
Specifies the address of the port.
value
Specifies the hexadecimal value to be written to the port.

Environment

Modes | kernel mode only
Targets | live debugging only
Platforms | x86 only

Comments

The OB command writes a single byte, OW writes a word, and OD writes a double word.

You should be careful not to try to output a word or a double-word to a port that does not support this size.

See Also

IB, ID, IW (Input from Port)


P (Step)

Executes a single instruction or source line, and optionally displays the resulting values of all registers and flags. When subroutine calls or interrupts occur, they are treated as a single step.

Syntax

User-Mode Syntax

[~Thread] p [r] [= StartAddress] [Count]

Kernel-Mode Syntax

p [r] [= StartAddress] [Count]

Parameters

Thread
If Thread is specified, the indicated threads are thawed and all others are frozen. For syntax details, see Thread Syntax. Threads can only be specified in user mode.
r
Toggles the display of registers and flags. The default is for the registers and flags to be displayed. To control which registers and flags are displayed, use the Rm (Register Mask) command.
StartAddress
If StartAddress is specified, the debugger begins execution at the specified address. Otherwise, it begins at the instruction pointed to by the instruction pointer. For more syntax details, see Address and Address Range Syntax.
Count
The number of instructions or source lines to step through before stopping. Each step is displayed as a separate action in the Debugger Command window.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

When Count is specified, each instruction is displayed as it is stepped through.

If the debugger encounters a CALL instruction or interrupt while stepping, the called subroutine will execute completely unless a breakpoint is encountered. Control is returned to the debugger at the next instruction after the call or interrupt.

Additional Information

For other methods of issuing this command and an overview of related commands, see Controlling the Target.


PC (Step to Next Call)

Executes the program until a call instruction is reached.

Syntax

User-Mode Syntax

[~Thread] pc [r] [= StartAddress] [Count]

Kernel-Mode Syntax

pc [r] [= StartAddress] [Count]

Parameters

Thread
If Thread is specified, the indicated threads are thawed and all others are frozen. For syntax details, see Thread Syntax. Threads can only be specified in user mode.
r
Toggles the display of registers and flags. The default is for the registers and flags to be displayed. To control which registers and flags are displayed, use the Rm (Register Mask) command.
StartAddress
If StartAddress is specified, the debugger begins execution at the specified address. Otherwise, it begins at the instruction pointed to by the instruction pointer. For more syntax details, see Address and Address Range Syntax.
Count
The number of instructions or source lines to trace through before stopping. If this parameter is included, execution will stop when the count is exhausted or when a call instruction is reached, whichever occurs first.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

This command causes the target to begin executing. This execution continues until a call instruction is reached.

If the program counter is already on a call instruction, the entire call will be executed. After this call is returned, execution will continue until another call is reached. This is the only difference between PC and TC (Trace to Next Call).

In source mode, one source line can be associated with multiple assembly instructions. This command will not stop at a call instruction that is associated with the current source line.

Additional Information

For an overview of related commands, see Controlling the Target.


Q, QQ (Quit)

Ends the debugging session. (In CDB and KD, this also exits the debugger itself. In WinDbg, this returns the debugger to dormant mode.)

Syntax

q
qq

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

In user-mode debugging, the Q command will end the debugging session and terminate the target application.

In kernel-mode debugging, the Q command will save the log file and end the debugging session. The target computer will remain locked.

If this command fails to work in KD, try pressing CTRL+R ENTER on the debugger keyboard, and then retry the Q command. If this does not work, you must use CTRL+B ENTER to exit the debugger.

The QQ command behaves exactly like the Q command, unless you are performing remote debugging. During remote debugging, the Q command will have no effect, but the QQ command will terminate the Debugging Server. See Remote Debugging Through the Debugger for details.

Additional Information

For other methods of exiting the debugger or detaching from the target, see Ending the Debugging Session.


QD (Quit and Detach)

Ends the debugging session, but leaves any user-mode target application running. (In CDB and KD, this also exits the debugger itself. In WinDbg, this returns the debugger to dormant mode.)

Syntax

qd

Environment

Modes | user mode only
Targets | live debugging only
Platforms | all

Comments

The QD command will detach from the target application and end the debugging session, leaving the target still running. However, this command is only supported on Windows XP and Windows .NET Server 2003. On Windows NT and Windows 2000, it will generate a warning message and have no effect.

While performing remote debugging through the debugger, the QD command cannot be used from a Debugging Client.

Additional Information

For other methods of exiting the debugger or detaching from the target, see Ending the Debugging Session.


R (Registers)

Displays or modifies registers, floating-point registers, flags, pseudo-registers, and fixed-name aliases.

Syntax

User-Mode Syntax

[~Thread] r[M Mask|F|X] [ Register[:[Num]Type] [= [Value]] ]

Kernel-Mode Syntax

Processor r[M Mask|F|X]
r[M Mask|F|X] [ Register[:[Num]Type] [= [Value]] ]

Parameters

Processor
Specifies the processor from which the registers are to be read. The default is zero. If Processor is specified, Register cannot be included — all registers will be displayed. For more information, see Multiprocessor Syntax. Processors can only be specified in kernel mode.
Thread
Specifies the thread from which the registers are to be read. If you do not specify a thread, the current thread is used. For syntax details, see Thread Syntax. Threads can only be specified in user mode.
M Mask
Specifies the mask to use when displaying the registers. The "M" must be upper-case. Mask is a sum of any number of bits, each of which indicates something about the register display. The meaning of the bits depends on the processor and the mode; see the tables in the following Comments section for details. If M is omitted, the default mask is used. The default mask can be set or displayed with the Rm (Register Mask) command.
F
Causes the floating-point registers to be displayed. The "F" must be upper-case. This option is equivalent to M 0x4.
X
Causes the SSE XMM registers to be displayed. The "X" must be upper-case. This option is equivalent to M 0x40.
Register
Specifies the register, flag, pseudo-register, or fixed-name alias to display or modify. This must never be preceded with an "at" ( @ ) sign. For syntax details, see Register Syntax.
Num
Specifies the number of elements to display. If this is omitted but Type is included, the full register length is displayed.
Type
Specifies the data format in which to display each register element. Type can only be used with 64-bit and 128-bit vector registers. Possible values for Type are:
Type | Display Format
ib | Signed byte
ub | Unsigned byte
iw | Signed word
uw | Unsigned word
id | Signed DWORD
ud | Unsigned DWORD
iq | Signed quad-word
uq | Unsigned quad-word
f | 32-bit floating-point
d | 64-bit floating point

Value
Specifies the value to assign to the register. See Expression Syntax for details.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

If register is not specified, the R command will display all the non-floating-point registers, and the RF command will display all the floating-point registers. This behavior can be changed by the Rm (Register Mask) command.

If register is specified, but the equal sign and value are absent, the command displays the current value of the register.

If register is specified and followed by an equal sign, but value is absent, the command displays the current value of the register and prompts for a new value.

If register, the equal sign, and value are specified, the command changes the register to contain the value. (If quiet mode is active, this equal sign may be omitted. Quiet mode can be activated by the SQ (Set Quiet Mode) command. In kernel mode, it can also be activated by the KDQUIET environment variable.)

It is possible to specify multiple registers, separated by commas.

In user mode, the registers displayed are those associated with the current thread. See Controlling Processes and Threads for details.

In kernel mode, the registers displayed are those associated with the current register context. The register context can be set to match a specific thread, context record, or trap frame. Only the most important registers for the specified register context are actually displayed, and their values cannot be changed. See Register Context for details.

The following Mask bits are supported for an x86 processor or an AMD64 processor:

Bit | Value | Description
0 1 | 0x1 0x2 | Displays the basic integer registers. (Setting any one, or both, of these bits has the same effect.)
2 | 0x4 | Displays the floating-point registers.
3 | 0x8 | Displays the segment registers.
4 | 0x10 | Displays the MMX registers.
5 | 0x20 | Displays the debug registers. In kernel mode, this also displays the CR4 register.
6 | 0x40 | Displays the SSE XMM registers.
7 | 0x80 | (Kernel mode only) Displays the CR0, CR1, and CR3 registers.
8 | 0x100 | (Kernel mode only) Displays the descriptor and task state registers.

The following Mask bits are supported for an IA-64 processor:

Bit | Value | Description
0 1 | 0x1 0x2 | Displays the basic integer registers. (Setting any one, or both, of these bits has the same effect.)
2 | 0x4 | Displays the floating-point registers.
3 | 0x8 | Displays the high floating-point registers (f32 to f127).
4 | 0x10 | Displays the user debug registers.
5 | 0x20 | (Kernel mode only) Displays the KSPECIAL_REGISTERS.

Here are some examples from an x86 processor.

In kernel mode, the following command will show the registers for processor two:

1: kd> 2r

In user mode, the following command will show the registers for thread two:

0:000> ~2 r

The following command will display all the eax registers associated with all threads (in thread ordinal order):

0:000> ~* r eax

This will set the eax register for the current thread to 0x000000FF:

0:000> r eax=0x000000FF

This will set the st0 register to 1.234e+10 (the F is optional):

0:000> rF st0=1.234e+10

This will display the zero flag:

0:000> r zf

This will display the the xmm0 register as sixteen unsigned bytes, and then display the full contents of the xmm1 register in double-precision floating point format:

0:000> r xmm0:16ub, xmm1:d

If the current syntax is C++, registers in expressions must be preceded by an "at" sign. Therefore the following command would be used to copy the ebx register to the eax register:

0:000> r eax = @ebx

The R command can display pseudo-registers in the same way it displays registers:

0:000> r $teb

The R command can also be used to create fixed-name aliases. These are neither registers nor pseudo-registers, despite their association with the R command. See Using Aliases for details.

Additional Information

For more details on registers and their manipulation, see Reading and Writing Registers and Flags. For more information on the register context and other context settings, see Changing Contexts.


RDMSR (Read MSR)

Reads a Model Specific Register (MSR) value from the specified address.

Syntax

rdmsr Address

Parameters

Address
Specifies the address of the MSR.

Environment

Modes | kernel mode only
Targets | live debugging only
Platforms | x86 only

See Also

WRMSR (Write MSR)


Rm (Register Mask)

Modifies or displays the register display mask. This mask controls how registers are displayed by the R (Registers) command.

Syntax

Rm
Rm ?
Rm Mask

Parameters

?
Causes the debugger to display a list of possible Mask bits.
Mask
Specifies the mask to use when displaying the registers. The "M" must be upper-case. Mask is a sum of any number of bits, each of which indicates something about the register display. The meaning of the bits depends on the processor and the mode; see the tables in the following Comments section for details.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The "m" must be lower-case.

If Rm is used with no arguments, the current value is displayed, along with an explanation of its bits.

To display the basic integer registers, either bit 0 (0x1) or bit 1 (0x2) needs to be set. 0x1 is on by default for 32-bit targets and 0x2 is on by default for 64-bit targets. These two bits cannot be set at the same time — if this is attempted, 0x2 will override 0x1.

The default mask can be overridden by using the M option when issuing the R (Registers) command.

The following Mask bits are supported for an x86 processor or for an AMD64 processor:

Bit | Value | Description
0 1 | 0x1 0x2 | Displays the basic integer registers. (Setting any one, or both, of these bits has the same effect.)
2 | 0x4 | Displays the floating-point registers.
3 | 0x8 | Displays the segment registers.
4 | 0x10 | Displays the MMX registers.
5 | 0x20 | Displays the debug registers. In kernel mode, this also displays the CR4 register.
6 | 0x40 | Displays the SSE XMM registers.
7 | 0x80 | (Kernel mode only) Displays the CR0, CR1, and CR3 registers.
8 | 0x100 | (Kernel mode only) Displays the descriptor and task state registers.

The following Mask bits are supported for an IA-64 processor:

Bit | Value | Description
0 1 | 0x1 0x2 | Displays the basic integer registers. (Setting any one, or both, of these bits has the same effect.)
2 | 0x4 | Displays the floating-point registers.
3 | 0x8 | Displays the high floating-point registers (f32 to f127).
4 | 0x10 | Displays the user debug registers.
5 | 0x20 | (Kernel mode only) Displays the KSPECIAL_REGISTERS.

Additional Information

For more details registers and their manipulation, see Reading and Writing Registers and Flags.


S (Search Memory)

Searches though memory to find a specific byte pattern.

This command should not be confused with the ~S (Change Current Processor), ~S (Set Current Thread), |S (Set Current Process), or ||S (Set Current System) commands.

Syntax

s [-Type] Range Pattern
s -v Range Object

Parameters

Type
The memory type to search for. Type should be preceded by a hyphen. The following Type values are permitted:
Type | Description
w | WORD (16 bits)
d | DWORD (32 bits)
q | QWORD (64 bits)
a ASCII string
(not necessarily null-terminated)
u Unicode string
(not necessarily null-terminated)

If Type is omitted, byte values will be used.

Range
The memory area to search through. This range cannot be more than 256 MB in length. For more syntax details, see Address and Address Range Syntax.
Pattern
One or more values to search for. These are byte values, unless specified otherwise by Type. If you are specifying a WORD, DWORD, or QWORD, enclose it in single quotation marks (for example, 'Tag7'). If you are specifying a string, enclose it in double quotation marks (for example, "This string").
-v
Causes the debugger to search for objects of the same type as the specified Object.
Object
Specifies either the address of an object or the address of a pointer to an object. The debugger will search for objects of the same type as this one.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

If the pattern is found, the debugger will display the first memory address in Range where it was found.

The Pattern parameter must be input as a series of bytes, unless a different Type is specified. Byte values can be entered as numeric or as ASCII characters.

Numeric values will be interpreted as numbers in the current radix (16, 10, or 8). To change the default radix, use the N (Set Number Base) command. The default radix can be overridden by specifying the 0x prefix (hexadecimal), the 0n prefix (decimal), the 0t prefix (octal), or the 0y prefix (binary).

Note The default radix behaves differently when C++ expressions are being used. See Evaluating Expressions for details.

If ASCII characters are used in a byte search, each character must be enclosed in single straight quotation marks. C-style escape characters, such as '\0' or '\n', may not be used.

If multiple bytes are specified, they must be separated by spaces.

The s-a and s-u command search for ASCII and Unicode strings, respectively. These strings do not need to be null-terminated.

The s-v command searches for objects of the same data type as Object. This command can only be used if the desired object is a C++ class or another object associated with virtual function tables (Vtables). The s-v command searches Range for the addresses of this class's Vtables. If multiple Vtables exist in this class, the search algorithm looks for all these pointer values, separated by the proper number of bytes. If any matches are found, the debugger returns the base address of the object as well as full information about this object — similar to the output of the DT (Display Type) command.

Here are some examples of the S command. Assuming the current radix is 16, the following command will search memory locations 0012FF40 through 0012FF5F for the pattern "Hello":

0:000> s 0012ff40 L20 'H' 'e' 'l' 'l' 'o'

The following command has the exact same effect:

0:000> s 0012ff40 L20 48 65 6c 6c 6f

The following s-a command also has the same effect:

0:000> s -a 0012ff40 L20 "Hello"

These commands will locate each appearance of the pattern "Hello", and return the address of each such pattern — or more precisely, the address of the 'H'.

Only patterns that are completely contained in the search range are returned. Overlapping patterns are found correctly. (In other words, the pattern "QQQ" will be found three times in the block "QQQQQ".)

Here is an example of a search using the Type parameter. This command will search memory locations 0012FF40 through 0012FF5F for the double-word 'VUTS':

0:000> s -d 0012ff40 L20 'VUTS'

On little-endian machines, this is the same as the byte pattern 'S' 'T' 'U' 'V'. However, searches for WORDs, DWORDs, and QWORDs will only return results that are properly byte-aligned.

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


SO (Set Kernel Debugging Options)

This sets or displays the kernel debugging options.

Syntax

so [Options]

Parameters

Options
Any or all of the following options can be listed.
NOEXTWARNING
This tells the debugger not to issue a warning when it is unable to find an extension command.
NOVERSIONCHECK
This tells the debugger not to check the version of debugger extension DLLs.

If Options is omitted, the current options are displayed.

Environment

Modes | kernel mode only
Targets | live, crash dump
Platforms | all

Comments

These options can also be set by using the _NT_DEBUG_OPTIONS environment variable.


SQ (Set Quiet Mode)

Turns quiet mode on or off.

Syntax

sq
sq{e|d}

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The sqe command turns quiet mode on, and sqd turns it off. The sq command toggles quiet mode on and off. Each of these commands also displays the new quiet mode status.

Quiet mode can also be set in KD or kernel-mode WinDbg by using the KDQUIET environment variable. (Note that quiet mode exists in both user-mode and kernel-mode debugging, but the KDQUIET environment variable is only recognized in kernel mode.)

Quiet mode has three distinct effects:

  • The debugger does not display messages each time an extension DLL is loaded or unloaded.
  • The R (Registers) command no longer requires an equal sign in its syntax.
  • When breaking into the target computer while kernel debugging, the long warning message is suppressed.

Quiet mode should not be confused with the effects of the -myob command-line option (in CDB and KD) or the -Q command-line option (in WinDbg).


SS (Set Suffix)

Sets or displays the current suffix value.

Syntax

ss [a|w|n]

Parameters

a
Specifies that the symbol suffix should be "A", matching many ASCII symbols.
w
Specifies that the symbol suffix should be "W", matching many Unicode symbols.
n
Specifies that no symbol suffix should be used. (This is the default.)

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The SS command with no argument outputs the current state of the suffix value.

Additional Information

For more details, see Symbol Syntax and Symbol Matching.


SX, SXD, SXE, SXI, SXN (Set Exceptions)

Controls the action the debugger takes when an exception occurs in the application being debugged, or when certain events occur.

Syntax

sx
sx{e|d|i|n} [-c "Cmd1"] [-c2 "Cmd2"] [-h] {Exception|Event|*}

Parameters

Cmd1
Specifies a command that will be executed if this exception or event occurs. This command will be executed when the first chance to handle this exception occurs, regardless of whether this exception breaks into the debugger. The Cmd1 string must be enclosed in quotation marks. It can include multiple commands, separated by semicolons.
Cmd2
Specifies a command that will be executed if this exception or event occurs and is not handled on the first chance. This command will be executed when the second chance to handle this exception occurs, regardless of whether this exception breaks into the debugger. The Cmd2 string must be enclosed in quotation marks. It can include multiple commands, separated by semicolons.
-h
Causes this command to change the specified event's handling status rather than its break status. If Event is cc, hc, bpec, or ssec, the -h option is not needed.
Exception
Specifies the exception number that the command acts upon, in the current radix.
Event
Specifies the event that the command acts upon. These events are identified by short abbreviations. See Controlling Exceptions and Events for a list of these events.
*
Causes this command to affect all numbered exceptions (but not any non-exception events).

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

The SX command displays the list of exceptions for the current process and the list of all non-exception events. The default behavior of the debugger for each exception and event is also displayed.

The SXE, SXD, SXN, and SXI commands control the debugger settings for each exception and event.

If the -h option is included (or if the cc, hc, bpec, or ssec events are specified) these commands control the handling status of the exception or event. In all other cases, these commands control the break status of the exception or event.

When setting the break status, these commands have the following effects:

Command | Status Name | Description
SXE | Break (Enabled) | When this exception occurs, the target will immediately break into the debugger. This will happen before any other error handlers are activated — this is called first chance handling.
SXD | Second chance break (Disabled) | The debugger will not break for a first-chance exception of this type (although a message will be displayed). If other error handlers then fail to address this exception, execution will halt and the target will break into the debugger. This is called second chance handling.
SXN | Output (Notify) | When this exception occurs, the target application will not break into the debugger at all. However, a message informing the user of this exception will be displayed.
SXI | Ignore | When this exception occurs, the target application will not break into the debugger at all, and no message will be displayed.

When setting the handling status, these commands have the following effects:

Command | Status Name | Description
SXE | Handled | The event will be considered handled when execution resumes.
SXD, SXN, SXI | Not Handled | The event will be considered not handled when execution resumes.

The -h option is for use with exceptions, not events. Using it with ch, bpe, or sse will simply set the handling status for hc, bpec, or ssec, respectively. If the -h option is used with any other event, it has no effect.

Using the -c or -c2 options with hc, bpec, or ssec will associate the specified commands with ch, bpe, or sse, respectively.

Additional Information

For more information regarding break status and handling status, descriptions of all event codes, a list of the default status for all events, and details on other methods of controlling this status, see Controlling Exceptions and Events.


T (Trace)

Executes a single instruction or source line, and optionally displays the resulting values of all registers and flags. When subroutine calls or interrupts occur, each of their steps is traced as well.

Syntax

User-Mode Syntax

[~Thread] t [r] [= StartAddress] [Count]

Kernel-Mode Syntax

t [r] [= StartAddress] [Count]

Parameters

Thread
If Thread is specified, the indicated threads are thawed and all others are frozen. For syntax details, see Thread Syntax. Threads can only be specified in user mode.
r
Toggles the display of registers and flags. The default is for the registers and flags to be displayed. To control which registers and flags are displayed, use the Rm (Register Mask) command.
StartAddress
If StartAddress is specified, the debugger begins execution at the specified address. Otherwise, it begins at the instruction pointed to by the instruction pointer. For more syntax details, see Address and Address Range Syntax.
Count
The number of instructions or source lines to trace through before stopping. Each step is displayed as a separate action in the Debugger Command window.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

When Count is specified, each instruction is displayed as it is stepped through.

The T command can be used to trace instructions in ROM.

Additional Information

For other methods of issuing this command and an overview of related commands, see Controlling the Target.


TB (Trace to Next Branch)

Executes the program until a branch instruction is reached.

Syntax

tb [r] [= StartAddress] [Count]

Parameters

r
Toggles the display of registers and flags. The default is for the registers and flags to be displayed. To control which registers and flags are displayed, use the Rm (Register Mask) command.
StartAddress
If StartAddress is specified, the debugger starts execution at the specified address. Otherwise, it starts execution at the instruction pointed to by the instruction pointer. For more syntax details, see Address and Address Range Syntax.
Count
The number of branches to allow. Each time a branch is encountered, the instruction address and the instruction are displayed. If Count is omitted, the default is one.

Environment

Modes | kernel mode only
Targets | live debugging only
Platforms | x86 (GenuineIntel® Pentium® II and above), IA-64

Comments

This command causes the target to begin executing. This execution continues until a branch command is reached.

Execution stops at any branch command which is to be taken. This is always based on the disassembly code, even when the debugger is in source mode.

Branch instructions include calls, returns, jumps, counted loops, and while loops. Any time the debugger encounters an unconditional branch, or a conditional branch for which the condition is true, execution will stop. If the debugger encounters a conditional branch whose condition is false, execution will continue.

When execution stops, the address of the branch instruction is displayed, along with any associated symbols. This is followed by an arrow and then the address and instructions of the new program counter location.

The TB command only works on the current processor. If it is used on a multiprocessor system, execution will stop when a branch command is reached, or when another processor's event occurs, whichever comes first.

Additional Information

For an overview of related commands, see Controlling the Target.


TC (Trace to Next Call)

Executes the program until a call instruction is reached.

Syntax

User-Mode Syntax

[~Thread] tc [r] [= StartAddress] [Count]

Kernel-Mode Syntax

tc [r] [= StartAddress] [Count]

Parameters

Thread
If Thread is specified, the indicated threads are thawed and all others are frozen. For syntax details, see Thread Syntax. Threads can only be specified in user mode.
r
Toggles the display of registers and flags. The default is for the registers and flags to be displayed. To control which registers and flags are displayed, use the Rm (Register Mask) command.
StartAddress
If StartAddress is specified, the debugger begins execution at the specified address. Otherwise, it begins at the instruction pointed to by the instruction pointer. For more syntax details, see Address and Address Range Syntax.
Count
The number of instructions or source lines to trace through before stopping. If this parameter is included, execution will stop when the count is exhausted or when a call instruction is reached, whichever occurs first.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

This command causes the target to begin executing. This execution continues until a call instruction is reached.

If the program counter is already on a call instruction, the debugger will trace into the call and continue executing until another call is reached. This is the only difference between TC and PC (Step to Next Call).

In source mode, one source line can be associated with multiple assembly instructions. This command will not stop at a call instruction that is associated with the current source line.

Additional Information

For an overview of related commands, see Controlling the Target.


U (Unassemble)

Displays an assembly translation of the specified program code in memory.

This command should not be confused with the ~U (Unfreeze Thread) command.

Syntax

u [Range]

Parameters

Range
The memory area that contains the instructions to unassemble. If Range is not specified, the disassembly begins at the current address. If no range size is specified, the default size is eight instructions on an x86 processor and nine instructions on an IA-64 processor. For more syntax details, see Address and Address Range Syntax.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Additional Information

For a description of assembly debugging and related commands, see Debugging in Assembly Mode.


UR (Unassemble Real Mode BIOS)

Displays an assembly translation of the specified 16-bit real mode code.

Syntax

ur [Range]

Parameters

Range
The memory area that contains the instructions to unassemble. If Range is not specified, the disassembly begins at the current address. If no range size is specified, the default size is eight instructions. For more syntax details, see Address and Address Range Syntax.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

If you are examining 16-bit real-mode code on an x86 processor, both the UR command and the U (Unassemble) command will give correct results.

However, if real-mode code exists in some location that the debugger isn't expecting it — for example, a non-x86 machine that is running or emulating x86 BIOS code from a plug-in card — you must use UR to correctly disassemble this code.

If you use UR on 32-bit or 64-bit code, it will attempt to disassemble it as if it were 16-bit, producing meaningless results.

Additional Information

For more information, see Debugging BIOS Code.


UX (Unassemble x86 BIOS)

Displays the instruction set of the x86 BIOS code.

Syntax

ux [Address]

Parameters

Address
Specifies the memory offset within the x86 BIOS code. If this is omitted or zero, the default is the beginning of the BIOS.

Environment

Modes | kernel mode only
Targets | live, crash dump
Platforms | x86 only

Comments

The debugger will display the instructions generated from the first eight lines of code beginning at Address.

For this command to work properly, HAL symbols must be available to the debugger. If these symbols cannot be found, the debugger will display a "couldn't resolve" error.

Additional Information

For more information, see Debugging BIOS Code.


vercommand (Show Debugger Command Line)

Displays the command line that was used to start the debugger.

Syntax

vercommand

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all


version (Show Debugger Version)

Displays version information for the debugger and all loaded extension DLLs. Also displays the current version of the operating system of the target computer.

This command should not be confused with the !version (Show DLL Version) extension command.

Syntax

version

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

See Also

CTRL+W (Show Debugger Version) , vertarget (Show Target Computer Version)


vertarget (Show Target Computer Version)

Displays the current version of the Windows® operating system of the target computer.

Syntax

vertarget

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

See Also

CTRL+W (Show Debugger Version), version (Show Debugger Version)


WRMSR (Write MSR)

Writes a value to a Model Specific Register (MSR) at the specified address.

Syntax

wrmsr address value

Parameters

address
The address of the MSR.
value
The 64-bit hexadecimal value to write to the MSR.

Environment

Modes | kernel mode only
Targets | live debugging only
Platforms | x86 only

See Also

RDMSR (Read MSR)


WT (Trace and Watch Data)

When this command is executed at the beginning of a function call, it will run through the entire function until completion and then display statistics.

Syntax

User-Mode Syntax

[~Thread] wt [WatchOptions] [= StartAddress] [EndAddress]

Kernel-Mode Syntax

wt [WatchOptions] [= StartAddress] [EndAddress]

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | user mode: all kernel mode: x86 only

Parameters

Thread
If Thread is specified, the indicated threads are thawed and all others are frozen. For syntax details, see Thread Syntax. Threads can only be specified in user mode.
WatchOptions
Specifies how the display is to be modified. Any of the following options can be used:
Option | Effect
-nc | Does not display individual call information.
-ns | Does not display summary information.
-oa | (User mode only) Displays the actual address of call sites.
-or | (User mode only) Displays the return register values of the called function.
-l Depth | (User mode only) Specifies the maximum depth of the calls to display. Any calls that are at least Depth levels deeper than the starting point are executed silently.

StartAddress
If StartAddress is specified, the debugger begins execution at the specified address. Otherwise, it begins at the instruction pointed to by the instruction pointer. For more syntax details, see Address and Address Range Syntax.
EndAddress
The address at which to end tracing. If EndAddress is omitted, a single instruction or function call will be executed.

Comments

This command is useful if you want information about the behavior of a specific function, but don't want to step through it. Go to the beginning of that function, and then issue the WT command.

If the program counter is at a point corresponding to a symbol — such as the beginning of a function or entry point into a module — the WT command will trace until it reaches the current return address. If it is on a call instruction, this command will trace until it returns to the current location. This tracing will be profiled in the Debugger Command window with output describing the various calls encountered.

If the WT command is issued at any other point, it behaves like the P (Step) command. However, if EndAddress is specified, execution will continue until that address is reached, even if this involves a large number of program steps and function calls.

When you are debugging in source mode, you should trace into the function just to the point that you see the opening bracket of the function body, and then use this command. (It is usually easier to place a breakpoint at the first line of the function in question, or use Debug | Run to Cursor, and then use this command.)

Because the output from this command can be quite long, you might prefer to use a log file to record your output. See Keeping a Log File for details.

Here is an example:

0:000> l+                  Source options set to show source lines
Source options are f:
     1/t - Step/trace by source line
     2/l - List source line for LN and prompt
     4/s - List source code at prompt
     8/o - Only show source code at prompt
0:000> p                   Not yet at the function call: use "p"
>  44:       minorVariableOne = 12;
0:000> p
>  45:       variableOne = myFunction(2, minorVariable);
0:000> t                   At the function call: now use "t"
MyModule!ILT+10(_myFunction):
0040100f e9cce60000      jmp     MyModule!myFunction (0040f6e0)
0:000> t
>  231:    {
0:000> wt                  At the function beginning:  now use "wt"
Tracing MyModule!myFunction to return address 00401137
 141 [  0]  MyModule!myFunction
  20 [  1]    MyModule!anotherFunction
   5 [  2]      MyModule!deeperFunction
  10 [  1]    MyModule!anotherFunction
   3 [  2]      MyModule!deeperFunction
  30 [  1]    MyModule!anotherFunction
   4 [  0]  MyModule!myFunction

147 Instructions were executed 146(0 from other threads) traces 147 sums

Function Name           Invocations  MinInstr  MaxInstr  AvgInstr

MyModule!deeperFunction        2           3          5         4
MyModule!anotherFunction       1          68         68        68
MyModule!myFunction            1         213        213       213
0 system calls were executed

System Call:

In the listing of the trace, the first number gives the number of instructions executed, and the second gives the depth of the function in the stack (taking the initial function as zero). The call depth is also shown by the indentation of the function name.

In the example above, MyModule!myFunction executed 141 instructions before calling anotherFunction, and then 4 additional instructions after anotherFunction returned. However, in the final tally, myFunction is credited with 213 instructions, as this tally includes all instructions executed by myFunction and its "children" (functions called from myFunction, either directly or indirectly).

Note also that deeperFunction was called twice. In the final tally there is a summary of this function's behavior: the number of times it was invoked, the smallest number of instructions in any single execution, the largest number of instructions in any single execution, and the average number of instructions per execution.

If any system calls are made, they appear in the tally and then are listed again at the end of the command output.

This example is taken from user-mode debugging. In kernel mode, the display is somewhat different. Function calls will be accompanied by two columns of numbers: the first is the number of instructions executed by the function named on that line; the second is the number of instructions executed by all of that function's children.

Additional Information

For other methods of issuing this command and an overview of related commands, see Controlling the Target.


X (Examine Symbols)

Displays the symbols in all contexts that match the specified pattern.

Syntax

x Module!Symbol
x *

Parameters

Module
Specifies the module to search. (This can be an .exe, .dll, or .sys file.) See syntax and wildcard details in the Comments section.
Symbol
Specifies a pattern that the symbol must contain. See syntax and wildcard details in the Comments section.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Both Module and Symbol may contain wildcards. The asterisk (*) represents zero or more characters; the question mark (?) represents exactly one character; brackets ( [ ] ) containing any list of characters represent any single character in the list. A single leading underscore represents any quantity of leading underscores. Symbol matching is not case-sensitive. See Symbol Syntax and Symbol Matching for more details.

This command displays all the public symbols for the specified module that match the specified pattern. For instance, the following will find all symbols in MyModule that contain the string "spin":

x mymodule!*spin*

The following will quickly locate the symbols "LaunchAlert" and "LaunchAbort" in MyModule:

x mymodule!launcha??rt

Or you can just show all symbols in the module:

x mymodule!*

All three of these commands will also force the debugger to reload symbol information from MyModule. If you simply want to reload the symbols in the module with a minimum display, use the following command:

x mymodule!*start*

There will always be a few symbols containing the string "start", so there will be some display from this command to let you see that it has worked, but it avoids the excessive display length of X mymodule!*.

The display will show the starting address of each symbol and the full symbol name. If the symbol is a function name, a list of its argument types is shown as well. If the symbol is a global variable, its current value is displayed.

There is one other special case of this command. To display all the local variables for the current context, use the following:

x *

This shows the addresses and names of all local variables. (To display the values of local variables, use the DV (Display Local Variables) command.)

There are several kinds of symbols in the symbol data. Free builds contain only public symbols, while checked builds contain full symbolic information.

See Also

Verifying Symbols, DV (Display Local Variables)


Z (Execute While)

Conditionally executes a command while a given condition is true.

Syntax

User-Mode Syntax

Command ; z( Expression )

Kernel-Mode Syntax

Command ; [Processor] z( Expression )

Parameters

Command
The command to be executed while the test is true. This command will always be executed at least once.
Processor
The processor which is applicable to the test. For more information, see Multiprocessor Syntax. Processors can only be specified in kernel mode.
Expression
The expression to be tested. If this evaluates to a non-zero value, command is executed again and then Expression is tested again. For more syntax details, see Expression Syntax.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The semicolon normally separates unrelated commands. The Z command is an exception to this rule: the Z is separated from Command by a semicolon.

The command is always executed at least once. Then Expression is tested; if this is nonzero the command is again executed, and then Expression is tested again. (This behavior is similar to a C-language do - while loop, rather than a simple while loop.)

If there are several semicolons to the left of the Z, all commands to the left of the Z will repeat as long as the test is true. These commands can be any debugger commands which allow a terminal semicolon.

If the Z is followed by another semicolon and additional commands, these additional commands will be executed after the loop is complete. A line beginning with Z is generally not advised; it will generate uninteresting output forever unless the condition becomes false as a result of some other action. It is possible to nest Z commands.

To break a loop which is going on too long, use CTRL+C in CDB or KD, or Debug | Break or CTRL+BREAK in WinDbg.

Here are some examples. The following is an unnecessarily complicated way to zero the eax register:

0:000> reax = eax - 1 ; z(eax)

The following will increment the eax and ebx registers until one of them is at least 8, and then it will increment the ecx register once:

0:000> reax=eax+1; rebx=ebx+1; z((eax<8)|(ebx<8)); recx=ecx+1

The following example uses C++ expression syntax, and uses the pseudo-register $t0 as a loop variable:

0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions

0:000> db pindexcreate[@$t0].szKey; r$t0=@t0+1; z( @$t0 < cIndexCreate )

See Also

J (Execute If-Else)


Meta-Commands

This section of the reference discusses the various debugger meta-commands which can be used in CDB, KD, and WinDbg. These commands are preceded by a period (.).


.abandon (Abandon Process)

Ends the debugging session, but leaves the target application in a debugging state. This returns the debugger to dormant mode.

Syntax

.abandon

Environment

This command is only supported on Windows XP and Windows .NET Server 2003.

Modes | user mode only
Targets | live debugging only
Platforms | all

Additional Information

If the target is left in a debugging state, a new debugger can be attached to it. See Re-attaching to the Target Application for details. However, once a process has once been abandoned, it can never be restored to a running state without a debugger attached.

For other methods of exiting the debugger or detaching from the target, see Ending the Debugging Session.


.asm (Change Disassembly Options)

Controls how disassembly code will be displayed.

Syntax

.asm
.asm[-] Options

Parameters

-
Causes the specified options to be disabled. If no minus sign is used, the specified options will be enabled.
Options
Specifies the options to be enabled or disabled. Any of the following options are permitted:
verbose
(IA-64 target only) Causes bundle type information to be displayed along with the standard disassembly information.
no_code_bytes
(x86 target only) Suppresses the display of raw bytes.
ignore_output_width
Prevents the debugger from checking the width of lines in the disassembly display.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Using .asm by itself displays the current state of the options.

This command affects the display of any disassembly instructions in the Debugger Command window. In WinDbg it also changes the contents of the Disassembly window.


.attach (Attach to Process)

Attaches to a new target application.

Syntax

.attach [-premote RemoteOptions] AttachOptions PID

Parameters

RemoteOptions
Specifies a process server to attach to. The options are the same as those for the command line -premote option. See Activating the Smart Client for syntax details.
AttachOptions
Specifies how the attach is to be done. This can include any of the following options:
-b
(Windows XP and Windows .NET Server 2003 only) Prevents the debugger from requesting an initial break-in when attaching to a target process. This can be useful if the application is already suspended, or if you wish to avoid creating a break-in thread in the target.
-e
(Windows XP and Windows .NET Server 2003 only) Allows the debugger to attach to a process that is already being debugged. See Re-attaching to the Target Application for details.
-r
(Windows XP and Windows .NET Server 2003 only) Causes the debugger to start the target process running when it attaches to it. This can be useful if the application is already suspended and you wish it to resume execution.
-v
Causes the specified process to be debugged noninvasively.
PID
Specifies the process ID of the new target application.

Environment

Modes | user mode only
Targets | live debugging only
Platforms | all

Comments

This command can be used when CDB is dormant, or if it is already debugging one or more processes. It cannot be used when WinDbg is dormant.

If this command is successful, the debugger will attach to the specified process the next time the debugger issues an execution command. If this command is used several times in a row, execution will have to be requested as many times as this command was used.

Since execution is not permitted during noninvasive debugging, the debugger is not able to noninvasively debug more than one process at a time. This also means that using the .attach -v command may render an already-existing invasive debugging session less useful.

Multiple target processes will always be executed together, unless some of their threads are frozen or suspended.

If the -premote option is used, the new process will be part of a new system. For details, see Debugging Multiple Systems.

Additional Information

For more details, and for other methods of attaching to a processs, see Attaching to a Running Process (User Mode) and Noninvasive Debugging (User Mode).


.breakin (Break to the Kernel Debugger)

Switches from user-mode debugging to kernel-mode debugging. This command is particularly useful when you are controlling the user-mode debugger from the kernel debugger.

Syntax

.breakin

Environment

Modes | user mode only
Targets | live debugging only
Platforms | all

Comments

If kernel-mode debugging was enabled during the boot process and you are running a user-mode debugger, you can use the .breakin command to halt the operating system and transfer control to a kernel debugger.

The .breakin command causes a kernel-mode break in the debugger's process context. If a kernel debugger is attached, it will become active. The kernel debugger's process context will automatically be set to the process of the user-mode debugger — not the user-mode debugger's target process.

This command is primarily useful when debugging a user-mode problem requires retrieving information about the kernel state of the system. Resuming execution in the kernel debugger is necessary before the user-mode debugging session can continue.

When you are controlling the user-mode debugger from the kernel debugger and the user-mode debugger prompt is visible in the kernel debugger, this command will pause the user-mode debugger and make the kernel-mode debugging prompt appear.

If the system is unable to break into the kernel debugger, an error message is displayed.

This command is also useful if you use the kernel debugger to set a breakpoint in user space, and that breakpoint is caught by a user-mode debugger instead of the kernel debugger. Issuing this command in the user-mode debugger will transfer control to the kernel debugger.

If the .breakin command is used on a system that wasn't booted with debugging enabled, it has no effect.


.bugcheck (Display Bug Check Data)

Displays the data from a bug check on the target computer.

Syntax

.bugcheck

Environment

Modes | kernel mode only
Targets | live, crash dump
Platforms | all

Comments

This command displays the current bug check data. (This bug check data will be accessible until the crashed machine is rebooted.)

In most situations, dd NT!KiBugCheckData L5 will also display bug check data. However, the .bugcheck command is more reliable, since it works in some scenarios that the D* command will not (such as user-mode minidumps).

The !analyze extension command is also useful after a bug check occurs.

Additional Information

For more information about bug checks, see Bug Checks (Blue Screens). For a description of individual bug checks, see the Bug Check Code Reference section.


.cache (Set Cache Size)

Sets the size of the cache used to hold data obtained from the target. Also sets a number of cache and memory options.

Syntax

.cache Size
.cache Option
.cache

Parameters

Size
The size of the kernel debugging cache, in kilobytes. If Size is zero, the cache is disabled. The command output displays the cache size in bytes. (The default size is 1000 KB.)
Option
Can be any one of the following options:
hold
Automatic cache flushing is disabled.
unhold
Turns off the hold option. (This is the default setting.)
decodeptes
All transition page table entries (PTEs) will be implicitly decoded. (This is the default setting.)
nodecodeptes
Turns off the decodeptes option.
forcedecodeptes
All virtual addresses will be translated into physical addresses before access. This option also causes the cache to be disabled.

This option is required when using .thread (Set Register Context), .context (Set User-Mode Address Context), .process (Set Process Context), or !session during live debugging. If you use the /p option with .thread and .process, this option is automatically set. In any other case, you will need to use the .cache forcedecodeptes command explicitly.

noforcedecodeptes
Turns off the forcedecodeptes option. (This is the default setting.)
flushall
Deletes the entire virtual memory cache.
flushu
Deletes all entries of ranges with errors from the cache, as well as all user-mode entries.
flush Address
Deletes a 4096-byte block of the cache, beginning at Address.

Environment

Modes | kernel mode only
Targets | live debugging only
Platforms | all

Comments

If .cache is used with no arguments, the current cache size, status, and options are displayed.

The .cache forcedecodeptes option will only last as long as the debugger remains broken into the target computer. If any stepping or execution of the target takes place, the noforcedecodeptes state will again take effect. This prevents the debugger from interfering with execution or a reboot in an unproductive manner.


.chain (List Debugger Extensions)

Lists all loaded debugger extensions, in their default search order.

Syntax

.chain

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Additional Information

For details on loading, unloading, and controlling extensions, see Loading Debugger Extension DLLs. For details on executing extension commands and an explanation of the default search order, see Using Debugger Extension Commands.


.childdbg (Debug Child Processes)

Controls the debugging of child processes.

Syntax

.childdbg {1|0}
.childdbg

Environment

This command is only supported on Windows XP and Windows .NET Server 2003.

Modes | user mode only
Targets | live debugging only
Platforms | x86 and IA-64 only

Comments

Child processes are additional processes launched by the original target application.

The .childdbg 1 command will cause the debugger to debug child processes. The .childdbg 0 command will deactivate this debugging.

With no parameters, .childdbg will display the current status of child-process debugging.

Additional Information

For more details, and for other methods of controlling the debugging of child processes, see Spawning a New Process (User Mode).


.clients (List Debugging Clients)

Lists all Debugging Clients currently connected to the debugging session.

Syntax

.clients

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Additional Information

For more details, and other commands that can be used while performing remote debugging through the debugger, see Controlling the Remote Debugging Session.


.closehandle (Close Handle)

Closes a handle owned by the target application.

Syntax

.closehandle Handle
.closehandle -a

Parameters

Handle
Specifies the handle to be closed.
-a
Causes all handles owned by the target application to be closed.

Environment

Modes | user mode only
Targets | live debugging only
Platforms | all

Comments

You can use the !handle extension to display the existing handles.


.cls (Clear Screen)

Clears the Debugger Command window display and

Syntax

.cls

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all


.context (Set User-Mode Address Context)

Specifies which process' page directory will be used for the user-mode address context, or displays the current user-mode address context.

Syntax

.context [PageDirectoryBase]

Parameters

PageDirectoryBase
Specifies the base address for a page directory of a desired process. The user-mode address context will be set to this page directory. If PageDirectoryBase is zero, the user-mode address context will be set to the page directory for the current system state. If PageDirectoryBase is omitted, the current user-mode address context is displayed.

Environment

Modes | kernel mode only
Targets | live, crash dump
Platforms | all

Comments

Normally, when you are doing kernel debugging, the only visible user-mode address space is the one associated with the current process.

The .context command instructs the kernel debugger to use the specified page directory as the user-mode address context. Once this command is executed, the debugger will have access to this virtual address space. The page tables for this address space will be used to interpret all user-mode memory addresses. This allows you to read and write to this memory.

The .process (Set Process Context) command has a similar effect. However, the .context command sets the user-mode address context to a specific page directory, while the .process command sets the process context to a specific process. On an x86 processor, these two commands have essentially the same effect. However, on an IA-64 processor, a single process may have more than one page directory. In this case, the .process command is more powerful, since it will allow access to all the page directories associated with a process. See Process Context for more details.

If you are doing live debugging, you should issue a .cache forcedecodeptes command in addition to the .context command. This forces the debugger to look up the physical addresses of the memory space needed. (This can be slow, since it often means a huge amount of data must be transferred across the debug cable.)

If you are doing crash dump debugging, the .cache command is not needed. However, you will not have access to any portions of the user-mode process' virtual address space which were paged to disk when the crash occurred.

Here is an example. Use the !process extension to find the directory base for the desired process:

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS fe5039e0  SessionId: 0  Cid: 0008    Peb: 00000000  ParentCid: 0000
    DirBase: 00030000  ObjectTable: fe529b68  TableSize:  50.
    Image: System

.....

PROCESS fe3c0d60  SessionId: 0  Cid: 0208    Peb: 7ffdf000  ParentCid: 00d4
    DirBase: 0011f000  ObjectTable: fe3d0f48  TableSize:  30.
    Image: regsvc.exe

Now use the .context command with this page directory base.

kd> .context 0011f000

This enables us to examine the address space in various ways. For example, here is the output of the !peb extension:

kd> !peb
PEB at 7FFDF000
    InheritedAddressSpace:    No
    ReadImageFileExecOptions: No
    BeingDebugged:            No
    ImageBaseAddress:         01000000
    Ldr.Initialized: Yes
    Ldr.InInitializationOrderModuleList: 71f40 . 77f68
    Ldr.InLoadOrderModuleList: 71ec0 . 77f58
    Ldr.InMemoryOrderModuleList: 71ec8 . 77f60
        01000000 C:\WINNT\system32\regsvc.exe
        77F80000 C:\WINNT\System32\ntdll.dll
        77DB0000 C:\WINNT\system32\ADVAPI32.dll
        77E80000 C:\WINNT\system32\KERNEL32.DLL
        77D40000 C:\WINNT\system32\RPCRT4.DLL
        77BE0000 C:\WINNT\system32\secur32.dll
    SubSystemData:     0
    ProcessHeap:       70000
    ProcessParameters: 20000
        WindowTitle:  'C:\WINNT\system32\regsvc.exe'
        ImageFile:    'C:\WINNT\system32\regsvc.exe'
        CommandLine:  'C:\WINNT\system32\regsvc.exe'
        DllPath:     'C:\WINNT\system32;.;C:\WINNT\System32;C:\WINNT\system;C:\WINNT;C:\WINNT\system32;C:\WINNT;C:\WINNT\System32\Wbem;C:\PROGRA~1\COMMON~1\AUTODE~1'
        Environment:  0x10000

Additional Information

For more information on the user-mode address context and other context settings, see Changing Contexts.


.crash (Force System Crash)

Causes the target computer to issue a bug check.

Syntax

.crash

Environment

Modes | kernel mode only
Targets | live debugging only
Platforms | all

Comments

This command will immediately cause the target computer to crash.

A kernel-mode dump file will be written if crash dumps have been enabled. See Creating a Kernel-Mode Dump File for details.

Additional Information

For an overview of related commands, and a description of the options available after a system crash, see Crashing and Rebooting the Target Computer.


.create (Create Process)

Creates a new target application.

Syntax

.create [-premote RemoteOptions] CommandLine

Parameters

RemoteOptions
Specifies a process server to attach to. The options are the same as those for the command line -premote option. See Activating the Smart Client for syntax details.
CommandLine
Specifies the complete command line for the new process. CommandLine may contain spaces, and must not be surrounded with quotes. All text after the .create command is taken as part of CommandLine; this command cannot be followed with a semicolon and additional debugger commands.

Environment

Modes | user mode only
Targets | live debugging only
Platforms | all

Comments

This command can be used when CDB is dormant, or if it is already debugging one or more processes. It cannot be used when WinDbg is dormant.

If this command is successful, the debugger will create the specified process the next time the debugger issues an execution command. If this command is used several times in a row, execution will have to be requested as many times as this command was used.

Multiple target processes will always be executed together, unless some of their threads are frozen or suspended.

If the -premote option is used, the new process will be part of a new system. For details, see Debugging Multiple Systems.

Additional Information

For more details, and for other methods of starting new processes for debugging, see Spawning a New Process (User Mode).


.createdir (Set Created Process Directory)

Sets the starting directory for any processes created by the debugger.

Syntax

.createdir [Path]

Parameters

Path
Specifies the starting directory. If Path contains spaces, it must be enclosed in quotation marks.

Environment

Modes | user mode only
Targets | live debugging only
Platforms | all

Comments

If .createdir is used with no parameters, the current starting directory is displayed.

If .createdir has never been used, any created process will use its usual default directory as its starting directory. If you have already set a path with .createdir and want to return to the default status, use .createdir "" with nothing inside the quotation marks.

This setting affects all processes created by .create (Create Process). It also affects processes created by WinDbg's File | Open Executable menu command, unless the Start directory text box is used to override this setting.

Additional Information

For information about starting new processes for debugging, see Spawning a New Process (User Mode).


.cxr (Display Context Record)

Displays the context record saved at the specified address. Also sets the register context.

Syntax

.cxr [Address]

Parameters

Address
Address of the system context record. Omitting the address does not display any context record information, but it does reset the register context.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The information from a context record can be used to assist in debugging a system halt where an unhandled exception has occurred and an exact stack trace is not available. The .cxr command displays the important registers for the specified context record.

This command also instructs the debugger to use the specified context record as the register context. Once this command is executed, the debugger will have access to the most important registers and the stack trace for this thread. This register context persists until you allow the target to execute or use another register context command (.thread, .cxr, .ecxr, or .trap). In user mode it will also be reset if you change the current process or thread. See Register Context for full details.

This extension is commonly used when debugging bug check 0x1E is issued. See Bug Check 0x1E (KMODE_EXCEPTION_NOT_HANDLED) for details and an example.

Additional Information

For more information on the register context and other context settings, see Changing Contexts.


.detach (Detach from Process)

Ends the debugging session, but leaves any user-mode target application running.

Syntax

.detach

Environment

For live user-mode debugging, this command is only supported on Windows XP and Windows .NET Server 2003.

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This command will end the debugging session in any of the following scenarios:

  • When you are debugging a user-mode or kernel-mode dump file
  • (Windows XP and Windows .NET Server 2003) When you are debugging a live user-mode target
  • When you are non-invasively debugging a user-mode target

If you are only debugging a single system, the debugger will return to dormant mode after it detaches.

If you are debugging multiple systems, the debugging session will continue with the remaining target systems.

Additional Information

For other methods of exiting the debugger or detaching from the target, see Ending the Debugging Session.


.dump (Create Dump File)

Creates a user-mode or kernel-mode crash dump file.

Syntax

.dump Options FileName
.dump /?

Parameters

Options
Can be any number of the following:
/o
Allows the debugger to overwrite a previous dump file with the same name. If this is not included and the file name is in use, the dump file will not be written.
/f
(Kernel mode:) Causes the debugger to create a Complete Memory Dump.

(User mode:) Causes the debugger to create a full user dump. Note that, despite their names, the largest "minidump" file actually contains more information than a "full" user-mode dump! For example, .dump /mf or .dump /ma will create a larger and more complete file than .dump /f.

/m[MiniOptions]
Causes the debugger to create a Small Memory Dump (in kernel mode) or a minidump (in user mode). If neither /f nor /m is specified, /m is the default.

In user mode, /m can be followed with additional MiniOptions that specify extra data that should be included in the dump. If no MiniOptions are included, the dump will include module, thread, and stack information, but no additional data. Any of the following MiniOptions can be added to change the contents of the dump file; they are case-sensitive.
MiniOption | Effect
f | Adds full memory data to the minidump. All accessible committed pages owned by the target application will be included.
h | Adds data about the handles associated with the target application to the minidump.
u | Adds unloaded module information to the minidump. This is only available in Windows .NET Server 2003.
a | Creates the largest minidump. The /ma option is equivalent to /mfhu — it adds full memory data, handle data, and unloaded module information to the minidump.
i | Adds secondary memory to the minidump. Secondary memory is any memory referenced by a pointer on the stack or backing store, plus a small region surrounding this address.
p | Adds process environment block (PEB) and thread environment block (TEB) data to the minidump. This can be useful if you need access to Windows system information regarding the application's processes and threads.
w | Adds all committed read-write private pages to the minidump.
d | Adds all read-write data segments within the executable image to the minidump.
r | Deletes from the minidump those portions of the stack and store memory that are not useful for recreating the stack trace. Local variables and other data type values are deleted as well. This option does not make the minidump smaller (since these memory sections are simply zeroed), but it is useful if you wish to protect the privacy of other applications.
R | Deletes the full module paths from the minidump. Only the module names will be included. This is a useful option if you wish to protect the privacy of the user's directory structure.

These MiniOptions can only be used when creating a user-mode minidump. They should follow the /m specifier.

/u
Causes dump file names to have the date, time, and PID appended to them. This assures that dump file names will be unique.
/a
Causes dumps to be generated for all currently-debugged processes. If /a is used, the /u option should be included as well to assure that each file has a unique name.
/b[a]
Causes a .cab file to be created. If this option is included, FileName is taken to be the CAB file name, not the dump file name. A temporary dump file will be created, this file will be packaged into a CAB, and then the dump file is deleted. If the b option is followed by a, all symbol and image files will be packaged into the CAB as well.
/c "Comment"
Specifies a comment string which will be written to the dump file. If Comment contains spaces, it must be enclosed in double-quotes. When the dump file is loaded, the Comment string will be displayed.
FileName
Specifies the name of the dump file. You can specify a full path and file name or just the file name. If the file name contains spaces, FileName should be enclosed in quotation marks. If no path is specified, the current directory is used.
-?
Displays a short help text for this command. This text is different in kernel mode and in user mode.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This command can be used in a variety of situations:

  • During live user-mode debugging, this command will cause the target application to generate a dump file, yet the target application will not terminate.
  • During live kernel-mode debugging, this command will cause the target computer to generate a dump file, yet the target computer will not actually crash.
  • During crash dump debugging, this command will create a new crash dump file from the old one. This is useful if you have a large crash dump file and wish to create a smaller one.
  • You can control exactly what type of dump file will be produced:
  • In kernel mode, you can produce a Complete Memory Dump by using the /f switch. You can produce a Small Memory Dump by using the /m switch (or no switch at all).
  • In user mode, you can produce a standard dump by using this command with the /f switch. You can produce a minidump by using the /m switch (or no switch at all).

The following example will create a user-mode minidump, containing full memory and handle information:

0:000> .dump /mfh myfile.dmp

Handle information can be read by using the !handle extension command.

Additional Information

For a description of kernel-mode dump files and an explanation of their use, see Kernel-Mode Dump Files. For a description of user-mode dump files and an explanation of their use, see User-Mode Dump Files.


.dumpcab (Create Dump File CAB)

Creates a CAB file containing the current dump file.

Syntax

.dumpcab [-a] CabName

Parameters

-a
Causes all symbol files and executable image files to be included in the CAB file.
CabName
The CAB file name, including extension. CabName can include an absolute or relative path; relative paths are relative to the directory in which the debugger was started. It is recommended that you choose the extension .cab.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This command can only be used if you are already debugging a dump file.

If you are debugging a live target and wish to create a dump file and place it in a CAB, you should use the .dump (Create Dump File) command. Then start a new debugging session with the dump file as its target, and use .dumpcab.

The .dumpcab cannot be used to place multiple dump files into one CAB file.

Additional Information

For more details on crash dumps, see Crash Dump Files.


.echo (Echo Comment)

Displays a comment string.

Syntax

.echo String
.echo "String"

Parameters

String
Specifies the text to be echoed. String cannot contain semicolons. It can contain any number of spaces, commas, and single-quotes. Double-quotes can be used in one of two ways: they can be used as literal characters — but never as the first character of String — or they can be used to surround String. (Surrounding String with double-quotes has no advantages and is never necessary, and it prevents double-quotes from appearing elsewhere.)

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The .echo command causes String to be repeated by the debugger immediately after the command is entered. On the other hand, strings which begin with the * (Comment) specifier are not repeated.

Another difference between these two forms of "comments" is that .echo commands are terminated by semicolons. This allows them to be used in complex constructions such as:

0:000> bp `:143` "j (poi(MyVar)>5) '.echo MyVar Too Big'; '.echo MyVar Acceptable; g' "

(See Using Breakpoints for an explanation of this example.)

The .echo command also provides an easy way for users of Debugging Servers and Debugging Clients to communicate with each other. See Controlling the Remote Debugging Session for details.


.echotimestamps (Show Time Stamps)

Toggles the display of time stamp information.

Syntax

.echotimestamps

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Each time this command is used, the display of time stamps is toggled on or off, and the new state is displayed. The default setting is "off".

Time stamps of module loads, thread creations, exceptions, and other events are shown if this display is enabled.

The kernel-mode routines DbgPrint, KdPrint, DbgPrintEx, and KdPrintEx send a formatted string to a buffer on the host computer. The string is displayed in the Debugger Command window (unless such printing has been disabled), and can also be displayed with the !dbgprint extension command.

When the .echotimestamps is used to toggle the display of timestamps on, the time and date of each comment in the DbgPrint buffer is shown.

Additional Information

For information on DbgPrint, KdPrint, DbgPrintEx, and KdPrintEx, see the Windows DDK.


.ecxr (Display Exception Context Record)

Displays the context record associated with the current exception.

Syntax

.ecxr

Environment

Modes | user mode only
Targets | crash dump only (minidumps only)
Platforms | all

Comments

The .ecxr command locates the current exception's context information and displays the important registers for the specified context record.

This command also instructs the debugger to use the specified context record as the register context. Once this command is executed, the debugger will have access to the most important registers and the stack trace for this thread. This register context persists until you allow the target to execute, change the current process or thread, or use another register context command (.cxr or .ecxr). See Register Context for full details.

Additional Information

For more information on the register context and other context settings, see Changing Contexts.


.enable_long_status (Enable Long Integer Display)

Causes the debugger to display LONG integers in the default base.

Syntax

.enable_long_status {1|0}

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The .enable_long_status 1 command will cause the debugger to display all LONG integers in the default base.

The .enable_long_status 0 command will cause the debugger to display all LONG integers in decimal format. If this command has never been issued, this is the default.

This command affects the display of the DT (Display Type) command. In WinDbg, it also affects the Locals window and the Watch window. These windows will automatically be refreshed after this command is issued.

Note that the DV (Display Local Variables) command always displays long integers in the current number base.

To change the current number base, use the N (Set Number Base) command.


.enable_unicode (Enable Unicode Display)

Causes the debugger to display USHORT pointers and arrays as Unicode strings, or disables this display.

Syntax

.enable_unicode {1|0}

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The .enable_unicode 1 command will cause the debugger to display all USHORT arrays and pointers as Unicode strings. The .enable_unicode 0 command will deactivate this display.

If the .enable_unicode command has never been issued, this display will be deactivated.

This command affects the display of the DT (Display Type) command. In WinDbg, it also affects the Locals window and the Watch window. These windows will automatically be refreshed after this command is issued.

See Also

DS (Display String)


.endpsrv (End Process Server)

Causes the process server currently in use to exit.

Syntax

.endpsrv

Environment

This command can only be used when performing remote debugging through a process server.

Modes | user mode only
Targets | live, crash dump
Platforms | all

Additional Information

For information on process servers, see Remote Debugging Through a Process Server.


.endsrv (End Debugging Server)

Causes the debugger to cancel an active Debugging Server.

Syntax

.endpsrv [ServerID]

Parameters

ServerID
Specifies the ID of the Debugging Server.

Environment

This command can only be used when performing remote debugging through the debugger.

Modes | user mode only
Targets | live, crash dump
Platforms | all

Comments

This command must be issued from the Debugging Server itself or from one of the Debugging Clients connected to it.

To determine the ID of a Debugging Server, use the .servers (List Debugging Servers) command.

Terminating a server will prevent any future clients from attaching to it. It will not cut off any clients that are currently attached through the server.

Here is an example. You start some Debugging Servers:

0:000> .server npipe:pipe=rabbit
Server started with 'npipe:pipe=rabbit'
0:000> .server tcp:port=7
Server started with 'tcp:port=7'

But then you decide you should be using a password:

0:000> .server npipe:pipe=tiger,password=hardtoguess
Server started with 'npipe:pipe=tiger,password=hardtoguess'

But the earlier servers are still around. Now you should cancel them:

0:000> .servers
0 - Debugger Server - npipe:Pipe=rabbit
1 - Debugger Server - tcp:Port=7
2 - Debugger Server - npipe:Pipe=tiger,Password=*
0:000> .endsrv 0
Server told to exit.  Actual exit may be delayed until
the next connection attempt.
0:000> .endsrv 1
Server told to exit.  Actual exit may be delayed until
the next connection attempt.
0:000> .servers
0 - <Disabled, exit pending>
1 - <Disabled, exit pending>
2 - Debugger Server - npipe:Pipe=tiger,Password=*

Finally, just to make sure that no one attached to your machine while the earlier servers were active, use .clients (List Debugging Clients):

0:000> .clients
HotMachine\HostUser, last active Mon Mar 04 16:05:21 2002

Warning Using a password with TCP, NPIPE, 1394, or COM protocols only offers a small amount of protection. The password itself is not encrypted in any way. If you want to establish a secure remote session, you must use SSL or SPIPE protocol!

Additional Information

For additional information, see Remote Debugging Through the Debugger.


.enumtag (Enumerate Secondary Callback Data)

Displays secondary bug check callback data and all data tags.

Syntax

.enumtag

Environment

Modes | kernel mode only
Targets | live, crash dump
Platforms | all

Comments

This command can only be used after a bug check has occurred, or when you are debugging a kernel-mode crash dump file.

For each block of secondary but check callback data, the .enumtag command will display the tag (in GUID format) and the data (as bytes and ASCII characters). Here is an example:

kd> .enumtag
{87654321-0000-0000-0000000000000000} - 0xf9c bytes
  4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00  MZ..............
  B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00  ........@.......
  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  ....
  00 00 00 00 00 00 00 00 00 00 00 00              ............

{12345678-0000-0000-0000000000000000} - 0x298 bytes
  F4 BF 7B 80 F4 BF 7B 80 00 00 00 00 00 00 00 00  ..{...{.........
  4B 44 42 47 98 02 00 00 00 20 4D 80 00 00 00 00  KDBG..... M.....
  54 A5 57 80 00 00 00 00 A0 50 5A 80 00 00 00 00  T.W......PZ.....
  40 01 08 00 18 00 00 00 BC 7D 50 80 00 00 00 00  @........}P.....
  ....
  00 00 00 00 00 00 00 00                          ........

In this example, the first batch of secondary data has GUID {87654321-0000-0000-0000000000000000} as its tag, and the second batch of data has GUID {12345678-0000-0000-0000000000000000} as its tag. However, the data itself it not in a very useful format.

Additional Information

For more information and for other ways of displaying this data, see Reading Bug Check Callback Data.


.exepath (Set Executable Path)

Sets or displays the executable file search path.

Syntax

.exepath[+] [directory [; ...]]

Parameters

+
Signifies that the new directories will be appended to (rather than replacing) the previous executable file search path.
directory
Specifies one or more directories to put in the search path. If directory is not specified, the current path is displayed. Separate multiple directories with semicolons.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Additional Information

For details, and for other ways to change this path, see Setting Paths and Loading Files.


.expr (Choose Expression Evaluator)

Chooses the default expression evaluator.

Syntax

.expr /s masm
.expr /s c++
.expr /q
.expr

Parameters

/s masm
Changes the default expression type to MASM (the Microsoft Assembler expression evaluator). This is the default when the debugger is started.
/s c++
Changes the default expression type to the C++ expression evaluator.
/q
Displays the list of possible expression types.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

When .expr is used with no arguments, the current default expression type is displayed.

The ?? (Evaluate C++ Expression) command, the Watch window, and the Locals window always use C++ expression syntax. All other commands and debugging information windows use the default expression evaluator.

For other methods of controlling which syntax is used, see Evaluating Expressions. For syntax details, see Expression Syntax.


.exr (Display Exception Record)

Displays the contents of an exception record.

Syntax

.exr Address
.exr -1

Parameters

Address
The address of the exception record. If -1 is specified, the most recent exception is displayed.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This command will display information related to an exception encountered on the target computer. The information displayed will include the exception address, exception code, exception flags, and a variable list of parameters to the exception.

The address can usually be obtained by using the !pcr extension.

This extension is commonly used when debugging bug check 0x1E. See Bug Check 0x1E (KMODE_EXCEPTION_NOT_HANDLED) for details and an example.


.fiber (Set Fiber Context)

Specifies which fiber will be used for the fiber context.

Syntax

.fiber [Address]

Parameters

Address
The address of the fiber. If this is omitted or zero, the fiber context is reset to the current fiber.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Additional Information

For information on the process context, the register context, and the local context, see Changing Contexts.


.fnent (Display Function Data)

Displays information about the function table entry for a specified function.

Syntax

.fnent Address

Parameters

Address
Specifies the address of the function.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The symbol-lookup algorithm for .fnent is the same as that of LN (List Nearest Symbols). The display will first show the nearest symbols. Then the function entry for the first of these symbols will be displayed.

If the nearest symbol is not in the function table, no information will be displayed.

Here is an example:

0:001> .fnent 77f9f9e7
Debugger function entry 00b61f50 for:
(77f9f9e7)   ntdll!RtlpBreakWithStatusInstruction   |  (77f9fa98)   ntdll!DbgPrintReturnControlC

Params:    1
Locals:    0
Registers: 0

0:001> .fnent 77f9fa98
Debugger function entry 00b61f70 for:
(77f9fa98)   ntdll!DbgPrintReturnControlC   |  (77f9fb21)   ntdll!DbgPrompt

Non-FPO

0:001> .fnent 01005a60
No function entry for 01005a60


.force_radix_output (Use Radix for Integers)

Controls whether integers will be displayed in decimal or in the default radix.

Syntax

.force_radix_output 0
.force_radix_output 1

Parameters

0
Causes all integers to be displayed in decimal. This is the default manner in which integers are displayed.
1
Causes all integers to be displayed in the default radix. To change the default radix, use the N (Set Number Base) command.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all


.formats (Show Number Formats)

Evaluates an expression or symbol in the context of the current thread and process, and displays it in multiple numerical formats.

Syntax

.formats expression

Parameters

expression
Specifies the expression to be evaluated. See Expression Syntax for details.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The number is displayed in hexadecimal, decimal, octal, and binary formats. It is also converted to single-precision and double-precision floating point format. ASCII character formats are also displayed when the bytes correspond to standard ASCII characters. The number is also interpreted as a timestamp if it is in the permissible range, .

Here is an example:

0:000> .formats 1c407e62
Evaluate expression:
  Hex:     1c407e62
  Decimal: 473988706
  Octal:   03420077142
  Binary:  00011100 01000000 01111110 01100010
  Chars:   .@~b
  Time:    Mon Jan 07 15:31:46 1985
  Float:   low 6.36908e-022 high 0
  Double:  2.34182e-315

The .formats command displays CRT-style timestamps. If you wish to display a FILETIME-style timestamp, use dt FILETIME Address instead.

See Also

? (Evaluate Expression), ?? (Evaluate C++ Expression)


.frame (Set Local Context)

Specifies which local context (scope) will be used to interpret local variables, or displays the current local context.

Syntax

.frame [FrameNumber]

Parameters

FrameNumber
The number of the frame whose local context is desired. If this is zero, it specifies the current frame. If this is omitted, this command displays the current local context.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

When a program is executing, the meaning of local variables depends on the location of the program counter, since the scope of such variables extends only to the function in which they are defined. Unless the .frame command is used, the debugger uses the scope of the current function (the current frame on the stack) as the local context.

To change the local context, use the .frame command and specify the desired frame number.

The frame number is the position of the stack frame within the stack trace. You can view this stack trace with the K (Display Stack Backtrace) command or the Calls window. The first line (the current frame) has frame number 0. The subsequent lines represent frame numbers 1, 2, 3, and so forth.

If you use the n parameter with the K command, it will display frame numbers alongside the stack trace. Note that these frame numbers are always displayed in hexadecimal. On the other hand, the .frame command will interpret its argument in the default radix, unless this is overridden with a prefix such as 0x. To change the default radix, use the N (Set Number Base) command.

Setting the local context to a different stack frame allows you to look at new local variable information. However, the actual variables available will depend on the code being executed.

The local context will be reset to the scope of the program counter if any program execution takes place. It will be reset to the top stack frame if the register context is changed.

Additional Information

For more information on the local context and other context settings, see Changing Contexts. For details on displaying local variables and other memory-related commands, see Reading and Writing Memory.


.help (Meta-Command Help)

Displays a list of all meta-commands.

Syntax

.help

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

For help on meta-commands, use .help. For help on standard commands, use ?. For help on extension commands, use !help.


.hh (Open HTML Help File)

Opens the Using Debugging Tools for Windows help file.

Syntax

.hh [Text]

Parameters

Text
The text to look up in the help file index.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

This command cannot be used when you are performing remote debugging through remote.exe.

Comments

This command opens the Using Debugging Tools for Windows (debugger.chm) file. If text is specified, the Index panel is selected and text is used as a keyword in the index. If no text is specified, the Contents panel is selected.

Additional Information

For more information on using the HTML Help file, see Using the Help File.


.kdfiles (Set Driver Replacement Map)

Reads a file and uses its contents as the driver replacement map.

Syntax

.kdfiles MapFile
.kdfiles -c
.kdfiles

Parameters

MapFile
Specifies a driver replacement map file.
-c
Causes the existing driver replacement map to be deleted. (This does not alter the map file itself — it simply clears the debugger's current map settings.)

Environment

This command is only supported on Windows XP and Windows .NET Server 2003. Using it on earlier versions of Windows will have no effect, although it will not generate an error.

Modes | kernel mode only
Targets | live debugging only
Platforms | x86 and IA-64 only

Comments

If .kdfiles is used with no parameters, the path and name of the current driver replacement map file will be displayed.

When this command is executed, the specified file is read. If the file is not found, or it does not contain text in the proper format, a message reading Unable to load file associations will be displayed.

If this specified file is in the correct driver replacement map file format, its contents will be loaded and used as the driver replacement map. This map will last until you exit the debugger, or until another .kdfiles command is issued.

Once the file has been read, the driver replacement map will not be affected by subsequent changes to the file (unless these changes are followed by another use of the .kdfiles command).

Additional Information

For an explanation and examples of driver replacement, a description of the format for driver replacement map files, and other methods of controlling this feature, see Mapping Driver Files.


.kframes (Set Stack Length)

Sets the default length of a stack trace display.

Syntax

.kframes FrameCountDefault

Parameters

FrameCountDefault
Specifies the number of stack frames to display when a stack trace command is used.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This command can be used to set the default length of a stack trace display. This controls the number of frames displayed by the K, KB, KP, and KV commands, and the number of DWORD_PTRs displayed by the KD command.

This default length can be overridden by using the FrameCount or WordCount parameters for these commands.

If the .kframes command has never been issued, the default count is 20 (0x14).

See Also

K, KB, KD, KP, KV (Display Stack Backtrace)


.kill (Kill Process)

In user mode, this command ends the debugging session and terminates the target application. In kernel mode, this command terminates a process on the target computer.

Syntax

User-Mode Syntax

.kill

Kernel-Mode Syntax

.kill Process

Parameters

Process
Specifies the address of the process to be terminated. If Process is omitted or zero, the default process for the current system state will be terminated.

Environment

In kernel mode, this command is only supported on Windows .NET Server 2003.

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | all

Comments

In user mode, this ends the debugging session, terminates the target application, and returns the debugger to dormant mode.

In kernel mode, this schedules the selected process on the target computer for termination. The next time the target is allowed to run (for example, by using a G (Go) command) the specified process will be terminated.

This command is not available during local kernel debugging.

Additional Information

For other methods of terminating or detaching from a user-mode target, see Ending the Debugging Session.


.lastevent (Display Last Event)

Displays the most recent exception or event that occurred.

Syntax

.lastevent

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Since breaking into the debugger always results in an exception, there is always a "last event" whenever the debugger is accepting command input. Breaking into the debugger by using CTRL+C, CTRL+BREAK, or Debug | Break generates an exception code of 0x80000003.

Additional Information

For more information regarding exceptions and events, see Controlling Exceptions and Events.


.lines (Toggle Source Line Support)

Enables or disables support for source-line information.

Syntax

.lines [-e|-d|-t]

Parameters

-e
Enables source line support.
-d
Disables source line support.
-t
Toggles source line support on or off. If no parameters are specified, this is the default.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Source line support must be active before any source-level debugging can be done. This allows the debugger to load source line symbols.

Source line support can be activated by the .lines command or by the -lines command-line option. If source line support is already enabled, .lines will disable this support.

If these options are not used, WinDbg defaults to source line support "on", while CDB defaults to source line support "off". For more ways to change this setting, see Setting Symbol Options.

Additional Information

For a description of source debugging and related commands, see Debugging in Source Mode.


.load (Load Extension DLL)

This command loads a new extension DLL into the debugger.

Syntax

.load DLLName
!DLLName.load

Parameters

DLLName
Specifies the fully qualified path and filename of the debugger extension DLL.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Once this command has been completed, it allows the user to access the commands stored in the loaded extension.

There are two ways to load an extension DLL. One is to use this command. The other is to simply executing an extension by issuing the full !DLLName.ExtensionCommand syntax — if the debugger has not yet loaded DLLName.dll, it will do so at this point.

Additional Information

For more details on loading, unloading, and controlling extensions, see Loading Debugger Extension DLLs.


.locale (Set Locale)

This command sets the locale, or displays the current locale.

Syntax

.locale [Locale]

Parameters

Locale
The desired locale. If this is omitted, the current locale is displayed.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The locale controls how Unicode strings are displayed.

Here are some examples of this command:

kd> .locale
Locale: C

kd> .locale E
Locale: English_United States.1252

kd> .locale c
Locale: Catalan_Spain.1252

kd> .locale C
Locale: C

Additional Information

For information on locale, see the setlocale routine in the MSDN.


.logappend (Append Log File)

Appends a copy of the events and commands from the Debugger Command window to the specified log file.

Syntax

.logappend [FileName]

Parameters

FileName
Specifies the name of the log file. You can specify a full path and file name or just the file name. If the file name contains spaces, FileName should be enclosed in quotation marks. If no path is specified, the current directory is used. If FileName is omitted, the file will be named dbgeng.log.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

If there is already a log file open, it will be closed. If the file name specified already exists, new information will be appended to it. If it does not exist, it will be created.

Additional Information

For details, and for other commands that affect log files, see Keeping a Log File.


.logclose (Close Log File)

Closes any currently-open log file.

Syntax

.logclose

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Additional Information

For details, and for other commands that affect log files, see Keeping a Log File.


.logfile (Display Log File Status)

Reveals whether a log file exists, and displays its status.

Syntax

.logfile

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Additional Information

For details, and for other commands that affect log files, see Keeping a Log File.


.logopen (Open Log File)

Sends a copy of the events and commands from the Debugger Command window to a new log file.

Syntax

.logopen [/t] [FileName]

Parameters

/t
Causes the debugger to append the current date and time to the log file name. This data is inserted after the file name and before the file name extension.
FileName
Specifies the name of the log file. You can specify a full path and file name or just the file name. If the file name contains spaces, FileName should be enclosed in quotation marks. If no path is specified, the current directory is used. If FileName is omitted, the file will be named dbgeng.log.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

If there is already a log file open, it will be closed. If you specify a file name which already exists, its contents will be overwritten.

Additional Information

For details, and for other commands that affect log files, see Keeping a Log File.


.noshell (Prohibit Shell Commands)

Prevents .shell commands from being used.

Syntax

.noshell

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

If this command is used, no future .shell (MS-DOS Shell) commands can be used. This prohibition will last as long as the debugger is running, even if a new debugging session is begun.

If you are performing remote debugging, this command can be useful for security purposes.

Additional Information

For details regarding the MS-DOS shell, and for other ways to disable shell commands, see Using Shell Commands.


.noversion (Disable Version Checking)

This command causes the debugger to disable all version checking of extension DLLs.

Syntax

.noversion

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The build number of extension DLLs should match the build number of the machine you are debugging because they are compiled and linked with dependencies on specific versions of data structures. If the versions don't match you will normally get a message similar to the following:

*** Extension DLL(1367 Free) does not match target system(1552 Free)


.ocommand (Expect Commands from Target)

Allows the target application to send commands to the debugger.

Syntax

.ocommand String
.ocommand -d
.ocommand

Parameters

String
Specifies the command prefix string. String may include spaces, but C-style control characters such as \" and \n are not permitted. Enclosing String in quotation marks is optional — unless String includes a semicolon, leading spaces, or trailing spaces, in which case quotation marks are required.
-d
Causes the command prefix string to be deleted.

Environment

Modes | user mode only
Targets | live debugging only
Platforms | all

Comments

If .ofilter is used with no parameters, the current command prefix string is displayed. To clear the existing string, use .ocommand -d or .ocommand "".

When a command prefix string has been set, any target output (such as the contents of an OutputDebugString command) will be analyzed. If this output begins with the command prefix string, the entire text of this output following the prefix string will be treated as a debugger command string, and executed.

After the commands execute, the target will remain broken into the debugger — unless the final command is G (Go).

The comparison between the command prefix string and the target output is case-insensitive (even though subsequent uses of .ocommand will display the string you entered with case preserved).

Here is an example. Suppose you enter the following command in the debugger:

0:000> .ocommand magiccommand

Subsequently, the following line is executed by the target application:

OutputDebugString("MagicCommand kb;g");

The debugger will recognize the command string prefix, and execute the command string kb;g immediately.

However, the following line will not result in any commands being executed:

OutputDebugString("Command on next line.\nmagiccommand kb;g");

This is because the command string prefix is not at the beginning of the output (even though it does begin a new line).

Note You should choose a command string prefix that is very unlikely to appear in any target output other than your own commands!

Additional Information

For information on OutputDebugString and other user-mode functions that communicate with a debugger, see the Platform SDK.


.ofilter (Filter Target Output)

Filters the output from the target application or target computer.

Syntax

.ofilter [/!] String
.ofilter ""
.ofilter

Parameters

/!
Causes the filter to be reversed: only output that does not contain String will be displayed. If this parameter is not used, only output that contains String will be displayed.
String
Specifies the string to be matched in the target's output. String may include spaces, but C-style control characters such as \" and \n are not permitted. Enclosing String in quotation marks is optional — unless String includes a semicolon, leading spaces, or trailing spaces, in which case quotation marks are required. Alphabetic characters in String will be converted to upper-case, but the actual pattern-matching is case-insensitive.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

If .ofilter is used with no parameters, the current pattern-matching criteria are displayed. To clear the existing filter, use the .ofilter "" command.

This will filter any data sent by user-mode routines such as OutputDebugString and kernel-mode routines such as DbgPrint. However, prompts sent by DbgPrompt are always displayed.

The DbgPrintEx and KdPrintEx routines supply another method of filtering out undesired debugging messages.

Additional Information

For information on OutputDebugString and other user-mode routines, see the Platform SDK. For information on DbgPrint, DbgPrintEx, and other kernel-mode routines, see the Windows DDK.


.open (Open Source File)

Searches the source path for a source file, and opens this file.

Syntax

.open FileName

Parameters

FileName
The source file name. This can include an absolute or relative path. Unless an absolute path is given, the path is taken to be relative to a directory in the source path.

Environment

This command is only available in WinDbg.

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Additional Information

For more details on source files and source paths, and for other ways to load source files, see Setting Paths and Loading Files.


.opendump (Open Dump File)

Opens a dump file for debugging.

Syntax

.opendump FileName

Parameters

FileName
The dump file name, including extension. This can include an absolute or relative path; relative paths are relative to the directory in which the debugger was started.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This command can be used even if a debugging session is already in progress. This allows you to debug more than one crash dump simultaneously.

Once you have used this command, you must use the G (Go) command to finish loading the dump file.

Additional Information

For more details, see Opening a Crash Dump.


.pagein (Page In Memory)

Pages in the specified region of memory.

Syntax

.pagein [/p Process] Address

Parameters

/p Process
Specifies the address of the process that owns the desired memory (or more precisely, the address of the EPROCESS block for this process). If Process is omitted or zero, the default process for the current system state will be used.
Address
Specifies the address to be paged in.

Environment

This command is only supported on Windows XP and Windows .NET Server 2003.

Modes | kernel mode only
Targets | live debugging only
Platforms | all

Comments

After executing this command, you must use the G (Go) command to resume program execution. After a brief time, the target computer will automatically break into the debugger again.

At this point, the desired address will be paged in. If you use the /p option, the process context will also be set to the specified process, exactly as if you had used a .process /i Process command.

If the address is already paged in, this command will still check that the address is paged in and then break back into the debugger. If the address is invalid, this command will simply break back into the debugger.

Warning Only user-mode addresses can be paged in with this command. If you use .pagein on an address in a kernel stack, a bug check may result.


.process (Set Process Context)

Specifies which process will be used for the process context.

Syntax

.process [/i] [/p [/r] ] [Process]

Parameters

/i
(Windows XP and Windows .NET Server 2003 only; live debugging only) Specifies that Process is to be debugged invasively. This means that the operating system of the target machine will actually make the specified process active. (Without this option, the .process command alters the debugger's output, but does not affect the target machine itself.) If this option is used, you must use the G (Go) command to execute the target. After a few seconds, the target will break back in to the debugger, and the specified Process will be active and used for the process context.
/p
(Live debugging only) If this option is included and Process is nonzero, all transition page table entries (PTEs) will be automatically translated into physical addresses before access. This forces the debugger to look up the physical addresses of the memory space needed. Note that this may take a while, since a huge amount of data may need to be transferred across the debug cable. (This behavior is the same as that of .cache forcedecodeptes.)

If the /p option is included and Process is zero or omitted, this translation will be disabled. (This behavior is the same as that of .cache noforcedecodeptes.)

/r
(Live debugging only) If the /r option is included along with the /p option, user-mode symbols will be reloaded once the process context has been set. (This behavior is the same as that of .reload /user.)
Process
Specifies the address of the desired process (or more precisely, the address of the EPROCESS block for this process). The process context will be set to this process. If Process is omitted or zero, the process context will be reset to the default process for the current system state. (If you used the /i option to set process context, then you need to use the /i option to reset the process context as well.)

Environment

Modes | kernel mode only
Targets | live, crash dump
Platforms | all

Comments

Normally, when you are doing kernel debugging, the only visible user-mode address space is the one associated with the current process.

The .process command instructs the kernel debugger to use a specific user-mode process as the process context. This has a number of effects, but the most important is that this gives the debugger access to the virtual address space of this process. The page tables for this process will be used to interpret all user-mode memory addresses. This allows you to read and write to this memory.

The .context (Set User-Mode Address Context) command has a similar effect. However, the .context command sets the user-mode address context to a specific page directory, while the .process command sets the process context to a specific process. On an x86 processor, these two commands have essentially the same effect. However, on an IA-64 processor, a single process may have more than one page directory. In this case, the .process command is more powerful, since it will allow access to all the page directories associated with a process. See Process Context for more details.

If you are performing live debugging, you should use either the /i parameter to activate the target process, or the /p parameter to activate the forcedecodeptes setting. (You do not need to use /p if the forcedecodeptes option is already active.)

The process context and the forcedecodeptes state only last until the target executes again. If the /i option is used, you must execute once for this command to take effect — if you execute a second time, the process context will be lost.

If you are performing crash dump debugging, the /i and /p options are not available. However, you will not have access to any portions of the user-mode process' virtual address space which were paged to disk when the crash occurred.

Here is an example. Use the !process extension to find the address of the EPROCESS block for the desired process:

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS fe5039e0  SessionId: 0  Cid: 0008    Peb: 00000000  ParentCid: 0000
    DirBase: 00030000  ObjectTable: fe529b68  TableSize:  50.
    Image: System

.....

PROCESS fe3c0d60  SessionId: 0  Cid: 0208    Peb: 7ffdf000  ParentCid: 00d4
    DirBase: 0011f000  ObjectTable: fe3d0f48  TableSize:  30.
    Image: regsvc.exe

Now use the .process command with this process address:

kd> .process fe3c0d60
Implicit process is now fe3c0d60

Notice that this command has made the .context command unnecessary. The user-mode address context already has the desired value:

kd> .context
User-mode page directory base is 11f000

This enables us to examine the address space in various ways. For example, here is the output of the !peb extension:

kd> !peb
PEB at 7FFDF000
    InheritedAddressSpace:    No
    ReadImageFileExecOptions: No
    BeingDebugged:            No
    ImageBaseAddress:         01000000
    Ldr.Initialized: Yes
    Ldr.InInitializationOrderModuleList: 71f40 . 77f68
    Ldr.InLoadOrderModuleList: 71ec0 . 77f58
    Ldr.InMemoryOrderModuleList: 71ec8 . 77f60
        01000000 C:\WINNT\system32\regsvc.exe
        77F80000 C:\WINNT\System32\ntdll.dll
        77DB0000 C:\WINNT\system32\ADVAPI32.dll
        77E80000 C:\WINNT\system32\KERNEL32.DLL
        77D40000 C:\WINNT\system32\RPCRT4.DLL
        77BE0000 C:\WINNT\system32\secur32.dll
    SubSystemData:     0
    ProcessHeap:       70000
    ProcessParameters: 20000
        WindowTitle:  'C:\WINNT\system32\regsvc.exe'
        ImageFile:    'C:\WINNT\system32\regsvc.exe'
        CommandLine:  'C:\WINNT\system32\regsvc.exe'
        DllPath:     'C:\WINNT\system32;.;C:\WINNT\System32;C:\WINNT\system;C:\WINNT;C:\WINNT\system32;C:\WINNT;C:\WINNT\System32\Wbem;C:\PROGRA~1\COMMON~1\AUTODE~1'
        Environment:  0x10000

Additional Information

For more information on the process context and other context settings, see Changing Contexts.


.reboot (Reboot Target Computer)

Reboots the target computer.

Syntax

.reboot

Environment

Modes | kernel mode only
Targets | live debugging only
Platforms | all

Additional Information

For an overview of related commands, and an explanation of how the reboot process affects the debugger, see Crashing and Rebooting the Target Computer.


.reload (Reload Module)

Deletes all symbol information for the specified module, and reloads these symbols as needed.

Syntax

.reload [Options] [Module [= Address [, Size] ] ]
.reload -?

Parameters

Options
Can be any of the following options:
/d
Reload all modules in the debugger's module list. (When all parameters are omitted, this is the default during user-mode debugging.)
/f
Force immediate symbol load. This overrides lazy symbol loading. See the Comments section for details.
/i
Ignore a mismatch in the .pdb file versions. (If this is not included, the debugger will not load mismatched symbol files.) When /i is used, /f is assumed as well, regardless of whether it is explicitly specified.
/l
List the modules, but do not actually reload their symbols. (In kernel mode, this gives the same output as the !drivers extension.)
/n
Reload kernel symbols only; do not reload any user symbols. (This option is allowed only during kernel-mode debugging.)
/s
Reload all modules in the system's module image list. (When all parameters are omitted, this is the default during kernel-mode debugging.)
/u
Unload the specified symbols and do not reload them. The specified Module is unloaded if its name matches any loaded module, regardless of the full path. Image names are also searched. See the note in the Comments section following.
/user
Reload user symbols only. (This option is allowed only during kernel-mode debugging.)
/v
Verbose mode.
/w
Treats Module as a literal string, preventing wildcards from being expanded.
Module
Specifies the name of an image on the target system to reload symbols for on the host computer. Module should include the name and extension of the file. Unless the /w option is used, Module may end with an asterisk (*) wildcard. If Module is omitted, the behavior depends on which Options were used; see the notes on Options in this section.
Address
Specifies the base address of the module. This is usually only needed if the image header has been corrupted or is paged out.
Size
Specifies the size of the module image. In many cases, the debugger will know the correct size of the module. When this is not the case, you should specify Size; this can be the actual module size or a larger number, but should not be a smaller number. This is usually only needed if the image header has been corrupted or is paged out.
-?
Displays a short help text for this command.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The .reload command does not actually cause symbol information to be read. Rather, it lets the debugger know that the symbol files may have changed, or that a new module should be added to the module list. This causes the debugger to revise its module list and to delete its symbol information for the specified modules. The actual symbol information will not be read from the individual .pdb files until it is needed. (This is known as lazy symbol loading or deferred symbol loading.)

You can force actual symbol loading to occur by using the /f option, or by issuing an LD (Load Symbols) command.

This command is useful in the event of a system crash, which may result in the loss of symbols for the target computer being debugged. The command can also be useful if you have updated the symbol tree.

If the image header is incorrect for some reason, or is paged out, you must specify both Address and Size for symbols to be loaded properly.

The .reload /u command performs a very broad search. The debugger first tries to match Module with an exact module name, regardless of path. If this is not found, Module is treated as the name of the loaded image. For example, if the HAL residing in memory has the module name of halacpi.dll, either of the following commands will unload its symbols:

kd> .reload /u halacpi.dll

kd> .reload /u hal

Additional Information

For more details on deferred (lazy) symbol loading, see Deferred Symbol Loading. For information on other symbol options, see Setting Symbol Options.


.remote (Create Remote.exe Server)

Starts a Remote.exe Server, allowing a remote connection to the current debugging session.

Syntax

.remote session

Parameters

session
This is a name you give to the debugging session.

Environment

This command can be used in KD and CDB, but it cannot be used in WinDbg.

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This command creates a remote.exe process, turning the current debugger into a Remote.exe Server. This permits a Remote.exe Client to connect to the current debugging session.

Additional Information

For full details on using Remote.exe Servers and Remote.exe Clients, see Remote Debugging Through Remote.exe.


.remote_exit (Exit Debugging Client)

Exits the Debugging Client but does not end the debugging session.

Syntax

.remote_exit

Environment

This command can only be used within a script. It can be used in KD and CDB, but it cannot be used in WinDbg.

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

If you are using KD or CBD directly, rather than using a script, you can exit from the Debugging Client by using the CTRL+B key.

Additional Information

For information on scripts, see $< (Run Script File). For full details on Debugging Clients and Debugging Servers, see Remote Debugging Through the Debugger.


.restart (Restart Target Application)

Restarts the target application.

This command should not be confused with the .restart (Restart Kernel Connection) command, which only works in kernel mode.

Syntax

.restart

Environment

Modes | user mode only
Targets | live debugging only
Platforms | all

Comments

CDB and WinDbg can restart a target application if the application was originally created by the debugger. The .restart command can be used even if the target application has already terminated.

However, if the application was already running and the debugger subsequently attached to the process, the .restart command will have no effect.

After the process is restarted it immediately breaks into the debugger.

Additional Information

For other methods of issuing this command and an overview of related commands, see Controlling the Target.


.restart (Restart Kernel Connection)

Restarts the kernel connection.

This command should not be confused with the .restart (Restart Target Application) command, which only works in user mode.

Syntax

.restart

Environment

This command is only available in KD.

Modes | kernel mode only
Targets | live, crash dump
Platforms | all

Comments

This command is similar to the CTRL+R (Re-synchronize) command, except that it is even more sweeping in its effect. It is equivalent to terminating the debugger and then attaching a fresh debugger to the target computer.

This command is most useful when performing remote debugging through remote.exe, when actually ending and restarting the debugger may be difficult. However, it cannot be used from a Debugging Client if you are performing remote debugging through the debugger.

Additional Information

For other methods of re-establishing contact with the target, see Synchronizing with the Target Computer.


.secure (Activate Secure Mode)

Activates or displays the status of Secure Mode.

Syntax

.secure 1
.secure

Environment

Secure Mode can only be enabled while the debugger is dormant. It only applies to subsequent kernel-mode sessions.

Modes | kernel mode only
Targets | live, crash dump
Platforms | all

Comments

To activate Secure Mode, use the command .secure 1 (or .secure followed by any nonzero value).

The command .secure will show whether Secure Mode is currently active.

Additional Information

For details, see Secure Mode.


.server (Create Debugging Server)

Starts a Debugging Server, allowing a remote connection to the current debugging session.

Syntax

.server tcp:port=Socket[,password=Password]
.server npipe:pipe=PipeName[,password=Password]
.server 1394:channel=1394Channel[,password=Password]
.server com:port=COMPort,baud=BaudRate,channel=COMChannel[,password=Password]
.server ssl:SSL-Parameters
.server spipe:SPIPE-Parameters

Parameters

Socket
When TCP protocol is used, Socket is the socket port number. It is also possible to specify a range of ports separated by a colon — for example, port=2:7. If this is done, the debugger will check each port in this range to see if it is free. If it finds a free port and no error occurs, the Debugging Server will be created.
PipeName
When NPIPE protocol is used, PipeName is a string that will serve as the name of the pipe. Each pipe name should identify a unique Debugging Server. If you attempt to reuse a pipe name, you will receive a message saying "Unable to start server, 0x800700B7". In user mode, PipeName can include a numerical printf-style format code. The debugger will replace this with the process ID of the target application. A second such code will be replaced with the thread ID of the target application. (The printf codes %04x and %05d will allow sufficient space for these numbers.)
1394Channel
(Windows XP and Windows .NET Server 2003 only) When 1394 protocol is used, Channel specifies the 1394 channel to be used. Valid channel numbers are 1 through 62. Any unused channel number can be selected; of course if you are performing kernel debugging over another 1394 connection, this should not be the same channel used for the kernel connection. The channel number does not depend on the physical 1394 port chosen on the adapter.
COMPort
When COM protocol is used, COMPort specifies the COM port to be used. The prefix "COM" is optional — for example, both "com2" and "2" are acceptable.
BaudRate
When COM protocol is used, BaudRate specifies the baud rate at which the connection will run. Any baud rate that is supported by the hardware is permitted.
COMChannel
If COM protocol is used, COMChannel specifies the COM channel to be used in communicating with the Debugging Client. This can be any value between 0 and 254, inclusive.
SSL-Parameters
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) See the Secure Channel (S-Channel) documentation in the MSDN for details.
SPIPE-Parameters
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) See the Secure Channel (S-Channel) documentation in the MSDN for details.
Password
This can be any alphanumeric string. If Password is used when the server is created, any Debugging Client must supply this password in order to connect to the debugging session.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This command turns the current debugger into a Debugging Server. This allows you to start the server after the debugger is already running, whereas the -server command-line option can only be issued when the debugger is started.

This permits a Debugging Client to connect to the current debugging session. Note that it is possible to start multiple servers using different options, allowing different kinds of Debugging Clients to join the session.

Additional Information

For full details on how to start a Debugging Server, see Activating the Debugging Server.


.servers (List Debugging Servers)

Lists all Debugging Servers that have been established by this debugger.

Syntax

.server

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Each Debugging Server is identified by a unique ID. This allows you cancel a server by using the .endsrv (End Debugging Server) command.

Additional Information

For full details on Debugging Servers, see Remote Debugging Through the Debugger.


.setdll (Set Default Extension DLL)

Changes the default extension DLL for the debugger.

Syntax

.setdll DLLName
!DLLName.setdll

Parameters

DLLName
The name and path of the extension DLL. If the full path was specified when the DLL was loaded, it needs to be given in full here as well.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The debugger maintains a default extension DLL which is implicity loaded when the debugger is started. This allows the user to specify an extension command without first having to load an extension DLL. This command allows modification of which DLL is loaded as the default DLL.

When a command is issued, the debugger looks for it in the default extension first. If a match is not found, all other loaded extension DLLs are searched in the order they were loaded.

Additional Information

For details on loading, unloading, and controlling extensions, see Loading Debugger Extension DLLs. For details on executing extension commands, see Using Debugger Extension Commands.


.shell (MS-DOS Shell)

Launches a shell process and redirects its output to the debugger, or to a specified file.

Syntax

.shell [ShellCommand]
.shell -i InFile [-o OutFile [-e ErrFile]] ShellCommand

Parameters

InFile
Specifies the path and filename of a file to be used for input. If you intend to offer no input after the initial command, you can specify a single hyphen (-) instead of InFile — with no space before the hyphen.
OutFile
Specifies the path and filename of a file to be used for standard output. If -o OutFile is omitted, output is sent to the Debugger Command window. If you do not want this output displayed or saved in a file, you can specify a single hyphen (-) instead of OutFile — with no space before the hyphen.
ErrFile
Specifies the path and filename of a file to be used for error output. If -e ErrFile is omitted, error output is sent to the same place as standard output. If you do not want this output displayed or saved in a file, you can specify a single hyphen (-) instead of ErrFile — with no space before the hyphen.
ShellCommand
Specifies the MS-DOS command to be executed.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The entire line after the .shell command will be interpreted as an MS-DOS® command (even if it contains a semicolon). This line should not be enclosed in quotation marks. There must be a space between .shell and the ShellCommand (additional leading spaces are ignored).

The output from the command will appear in the Debugger Command window, unless the -o OutFile parameter is used.

Issuing a .shell command with no parameters will activate the shell and leave it open. All subsequent commands will be interpreted as MS-DOS commands. During this time, the debugger will display messages reading <.shell process may need input>, and the WinDbg prompt will be replaced with an Input> prompt. Sometimes a separate MS-DOS Command Prompt window will appear when the debugger leaves the shell open. This window should be ignored; all input and output will be done through the Debugger Command window.

To close this shell and return to the debugger itself, type exit or .shell_quit. (The .shell_quit command is more powerful, since it works even if the shell is frozen.)

This command cannot be used while debugging CSRSS, since new processes cannot be created without CSRSS being active.

Additional Information

For other ways of accessing the Windows or MS-DOS shell, see Using Shell Commands.


.sleep (Pause Debugger)

Causes the user-mode debugger to pause, and the target computer to become active. This command is only used when you are controlling the user-mode debugger from the kernel debugger.

Syntax

.sleep milliseconds

Parameters

milliseconds
Specifies the length of the pause, in milliseconds.

Environment

Modes | controlling the user-mode debugger from the kernel debugger
Targets | live debugging only
Platforms | all

Comments

When you are controlling the user-mode debugger from the kernel debugger, and the user-mode debugger prompt is visible in the kernel debugger, this command will activate sleep mode. The kernel debugger, the user-mode debugger, and the target application will all freeze, but the rest of the target computer will become active.

If you use this command in any other scenario, it will simply freeze the debugger for a period of time.

The sleep time is in milliseconds, and interpreted according to the default radix, unless a prefix such as 0n is used. Thus if the default radix is 16, the following command will cause about 65 seconds of sleep:

0:000> .sleep 10000

Additional Information

For details, and for information on how to wake up a debugger in sleep mode, see Controlling the User-Mode Debugger from the Kernel Debugger.


.srcpath, .lsrcpath (Set Source Path)

Sets or displays the source file search path.

Syntax

.srcpath[+] [directory [; ...]]
.lsrcpath[+] [directory [; ...]]

Parameters

+
Signifies that the new directories will be appended to (rather than replacing) the previous source file search path.
directory
Specifies one or more directories to put in the search path. If directory is not specified, the current path is displayed. Separate multiple directories with semicolons.

Environment

The .srcpath command is available on all debuggers, but the .lsrcpath command is only available on WinDbg.

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

When this command is issued from a Debugging Client, .srcpath sets the source path on the Debugging Server, while .lsrcpath sets the source path on the local machine.

Additional Information

For details, and for other ways to change this path, see Setting Paths and Loading Files. For more information on commands that can be used while performing remote debugging through the debugger, see Controlling the Remote Debugging Session.


.symfix (Set Symbol Store Path)

Automatically sets the symbol path to point to the Microsoft symbol store.

Syntax

.symfix[+] [DownstreamStore]

Parameters

+
Causes the Microsoft symbol store path to be appended to the existing symbol path. If this is not included, the existing symbol path is replaced.
DownstreamStore
Specifies the directory to be used as a downstream store. If this is omitted, the localsym subdirectory of the debugger installation directory will be used. If this directory does not exist, it will be created when the symbol server begins copying files.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This command is equivalent to

.sympath[+] srv*DownstreamStore*http://msdl.microsoft.com/download/symbols

Additional Information

For details, see Using Symbol Servers and Symbol Stores.


.symopt (Set Symbol Options)

Sets or displays the symbol options.

Syntax

.symopt+ Flags
.symopt- Flags

Parameters

Flags
Specifies the flags to be changed. If .symopt+ is used, the specified flags are set; if .symopt- is used, the specified flags are cleared.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Use .symopt+0 or .symopt-0 to display the flags without changing them.

Additional Information

For a list and description of each symbol option, along with other methods of setting and clearing these flags, see Setting Symbol Options.


.sympath (Set Symbol Path)

Changes the default path of the host debugger for symbol search.

Syntax

.sympath[+] [path [; ...]]

Parameters

+
Signifies that the new directories will be appended to (rather than replacing) the previous symbol search path.
path
The fully qualified path, on the host computer, of a new symbol search. Multiple symbol paths should be separated with semicolons. If path is omitted, the current symbol path is displayed.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

New symbol information will not be loaded when the symbol path is changed. If this is desired, follow .sympath with the .reload (Reload Module) command.

Additional Information

For details, and for other ways to change this path, see Setting Paths and Loading Files.


.thread (Set Register Context)

Specifies which thread will be used for the register context.

Syntax

.thread [/p [/r] ] [Thread]

Parameters

/p
(Live debugging only) If this option is included and Thread is nonzero, all transition page table entries (PTEs) for the process owning this thread will be automatically translated into physical addresses before access. This forces the debugger to look up the physical addresses of the memory space needed. Note that this may take a while, since a huge amount of data may need to be transferred across the debug cable. (This behavior is the same as that of .cache forcedecodeptes.)

If the /p option is included and Thread is zero or omitted, this translation will be disabled. (This behavior is the same as that of .cache noforcedecodeptes.)

/r
(Live debugging only) If the /r option is included along with the /p option, user-mode symbols for the process owning this thread will be reloaded once the process and register contexts have been set. (This behavior is the same as that of .reload /user.)
Thread
The address of the thread. If this is omitted or zero, the thread context is reset to the current thread.

Environment

Modes | kernel mode only
Targets | live, crash dump
Platforms | all

Comments

Normally, when you are doing kernel debugging, the only visible registers are the ones associated with the current thread.

The .thread command instructs the kernel debugger to use the specified thread as the register context. Once this command is executed, the debugger will have access to the most important registers and the stack trace for this thread. This register context persists until you allow the target to execute or use another register context command (.thread, .cxr, or .trap). See Register Context for full details.

This command does not actually change the current thread. In other words, extensions such as !thread and !teb will still default to the current thread if no arguments are used with them.

Here is an example. Use the !process extension to find the address of the desired thread. (In this case, we use !process 0 0 to list all processes, then use !process a second time to list all the threads for the desired process.)

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS fe5039e0  SessionId: 0  Cid: 0008    Peb: 00000000  ParentCid: 0000
    DirBase: 00030000  ObjectTable: fe529a88  TableSize: 145.
    Image: System

.....

PROCESS ffaa5280  SessionId: 0  Cid: 0120    Peb: 7ffdf000  ParentCid: 01e0
    DirBase: 03b70000  ObjectTable: ffaa4e48  TableSize:  23.
    Image: winmine.exe

kd> !process ffaa5280
PROCESS ffaa5280  SessionId: 0  Cid: 0120    Peb: 7ffdf000  ParentCid: 01e0
    DirBase: 03b70000  ObjectTable: ffaa4e48  TableSize:  23.
    Image: winmine.exe
    VadRoot ffaf6e48 Clone 0 Private 50. Modified 0. Locked 0.
    DeviceMap fe502e88
    Token                             e1b55d70

.....

        THREAD ffaa43a0  Cid 120.3a4  Teb: 7ffde000  Win32Thread: e1b4fea8 WAIT: (WrUserRequest) UserMode Non-Alertable
            ffadc6a0  SynchronizationEvent
        Not impersonating
        Owning Process ffaa5280
        WaitTime (seconds)      24323
        Context Switch Count    494                   LargeStack

.....

Now use the .thread command with the address of the desired thread. This sets the register context, and enables us to examine the important registers and the call stack for this thread.

kd> .thread ffaa43a0
Using context of thread ffaa43a0

kd> r
Last set context:
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=00000000 edi=00000000
eip=80403a0d esp=fd581c2c ebp=fd581c60 iopl=0         nv up di pl nz na pe nc
cs=0000  ss=0000  ds=0000  es=0000  fs=0000  gs=0000             efl=00000000
0000:3a0d ??              ???

kd> k
  *** Stack trace for last set context - .thread resets it
ChildEBP RetAddr
fd581c38 8042d61c ntoskrnl!KiSwapThread+0xc5
00001c60 00000000 ntoskrnl!KeWaitForSingleObject+0x1a1

Additional Information

For more information on the register context and other context settings, see Changing Contexts.


.time (Display System Time)

Displays information about the system time variables.

Syntax

.time

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The system time variables control performance counter behavior.

Here is an example in kernel mode:

kd> .time
Debug session time: Wed Jan 31 14:47:08 2001
System Uptime: 0 days 2:53:56

Here is an example in user mode:

0:001> .time
Debug session time: Wed Jan 31 16:04:23 2001
System Uptime: 12 days 12:41:37
Process Uptime: 0 days 4:42:51


.tlist (List Process IDs)

Lists all processes running on the system.

Syntax

.tlist Options

Parameters

Options
Any of the following can be included:
-v
Causes the display to be verbose.
-c
Limits the display to just the current process.

Environment

Modes | user mode only
Targets | live debugging only
Platforms | all

Comments

Each process ID is displayed with an 0n prefix, to emphasize that the PID is a decimal number.

Additional Information

For other methods of displaying processes, see Finding the Process ID.


.trap (Display Trap Frame)

Displays the trap frame register state. Also sets the register context.

Syntax

.trap [Address]

Parameters

Address
Hexadecimal address of the trap frame on the target system. Omitting the address does not display any trap frame information, but it does reset the register context.

Environment

Modes | kernel mode only
Targets | live, crash dump
Platforms | all

Comments

The .trap command displays the important registers for the specified trap frame.

This command also instructs the kernel debugger to use the specified context record as the register context. Once this command is executed, the debugger will have access to the most important registers and the stack trace for this thread. This register context persists until you allow the target to execute or use another register context command (.thread, .cxr, or .trap). See Register Context for full details.

This extension is commonly used when debugging bug check 0xA and 0x7F. See Bug Check 0xA (IRQL_NOT_LESS_OR_EQUAL) for details and an example.

Additional Information

For more information on the register context and other context settings, see Changing Contexts.


.tss (Display Task State Segment)

Displays a formatted view of the saved Task State Segment (TSS) information for the current processor.

Syntax

.tss [Address]

Parameters

address
Address of the TSS.

Environment

Modes | kernel mode only
Targets | live, crash dump
Platforms | x86 only

Comments

The address of the TSS can be found by examining the output of the !pcr extension.


.unload (Unload Extension DLL)

Unloads an extension DLL from the debugger.

Syntax

.unload DLLName
!DLLName.unload

Parameters

DLLName
Specifies the filename of the debugger extension DLL to be unloaded. If the full path was specified when the DLL was loaded, it needs to be given in full here as well. If DLLName is omitted, the current extension DLL is unloaded.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This command is useful when testing an extension you are creating. When the extension is recompiled, you must unload and then load the new DLL.

Additional Information

For more details on loading, unloading, and controlling extensions, see Loading Debugger Extension DLLs.


.unloadall (Unload All Extension DLLs)

Unloads all extension DLLs from the debugger on the host system.

Syntax

.unloadall

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Additional Information

For more details on loading, unloading, and controlling extensions, see Loading Debugger Extension DLLs.


.wake (Wake Debugger)

Causes sleep mode to end. This command is only used when you are controlling the user-mode debugger from the kernel debugger.

Syntax

.wake PID

Parameters

PID
The process ID of the user-mode debugger.

Environment

Modes | controlling the user-mode debugger from the kernel debugger
Targets | live debugging only
Platforms | all

Comments

When you are controlling the user-mode debugger from the kernel debugger, and the system is in sleep mode, this command can be used to wake up the debugger before the sleep timer runs out.

This command is not issued in the user-mode debugger on the target machine, nor in the kernel debugger on the host machine. It must be issued from a third debugger — KD, CDB, or NTSD — which is running on the target machine.

This debugger can be started expressly for this purpose, or can be another debugger which just happens to be running. However, if there is no other debugger already running, it is easier just to use CDB with the -wake command-line option.

Additional Information

For more details, see Controlling the User-Mode Debugger from the Kernel Debugger. For information on how to find the process ID of the debugger, see Finding the Process ID.


.writemem (Write Memory to File)

Writes a section of memory to a file.

Syntax

.writemem FileName Range

Parameters

FileName
Specifies the name of the file to be created. You can specify a full path and file name or just the file name. If the file name contains spaces, FileName should be enclosed in quotation marks. If no path is specified, the current directory is used.
Range
Specifies the memory range to be written to the file. For syntax details, see Address and Address Range Syntax.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

The memory is copied literally to the file. It is not parsed in any way.


.wtitle (Set Window Title)

Sets the title in the main WinDbg window.

Syntax

.wtitle Title

Parameters

Title
The title to use for the main WinDbg window.

Environment

This command is only available in WinDbg.

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Unless this command is used, the WinDbg window title includes the name of the target. If a Debugging Server is active, its connection string is displayed as well. If multiple Debugging Servers are active, only the most recent one is displayed.

When .wtitle is used, Title replaces all of this information. Even if a Debugging Server is started later, Title will not change.

The WinDbg version number is always displayed in the window title bar, regardless of whether this command is used.


Control Keys

This section of the reference discusses the various control keys which can be used in the debuggers.

These control keys work in KD, and in some cases CDB. Many of them also work in WinDbg (using the CTRL+ALT keys instead of just CTRL).

WinDbg also uses the CTRL key, the ALT key, and the "F" keys as shortcut keys to toggle the menu options. See Shortcut Keys for a list of their meanings.


CTRL+A (Toggle Baud Rate)

Toggles the baud rate used in the kernel debugging connection.

Syntax

KD Syntax

CTRL+A  ENTER

WinDbg Syntax

CTRL+ALT+A

Environment

Debuggers | KD and WinDbg only
Modes | kernel mode only
Targets | live debugging only
Platforms | all

Comments

This will cycle through all available baud rates for the kernel debugging connection.

Supported baud rates are 19200, 38400, 57600, and 115200. Each time this control key is used, the next baud rate will be selected. If the baud rate is already at 115200, it will be reduced to 19200.

In WinDbg, this can also be accomplished by selecting Debug | Kernel Connection | Cycle Baud Rate.

You cannot actually use this control key to change the baud rate at which you are debugging. The baud rate of the host computer and the target computer must match, and the baud rate of the target computer cannot be changed without rebooting. Therefore you only need to toggle through the baud rates if the two computers are attempting to communicate at different rates. In this case, you must change the host computer's baud rate to match that of the target computer.

To change the target computer's baud rate, see Configuring Software on the Target Computer.


CTRL+B (Quit Local Debugger)

Causes the debugger to terminate abruptly. This does not end a remote debugging session.

Syntax

CTRL+B  ENTER

Environment

Debuggers | CDB and KD only
Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

In CDB, the Q (Quit) command should be used to exit. CTRL+B should only be used if the debugger is not responding.

In KD, the Q command will end the debugging session and leave the target computer locked. If you need to preserve the debugging session (so that a new debugger can connect to it), or if you need to leave the target computer running, you should use CTRL+B.

In WinDbg, the equivalent command is File | Exit or ALT+F4.

Additional Information

For other methods of exiting the debugger or detaching from the target, see Ending the Debugging Session.


CTRL+C (Break)

Breaks into the debugger, stopping the target application or target computer. Also cancels debugger commands.

Syntax

CDB Syntax

CTRL+C

KD Syntax

CTRL+C

Target Computer Syntax

SYSRQ
ALT+SYSRQ
F12

Environment

Debuggers | CDB and KD only
Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

When Using CDB

In user mode, the CTRL+C command causes the target application to break into the debugger. The target application freezes, the debugger becomes active, and debugger commands can be entered.

If the debugger is already active, CTRL+C does not affect the target application. It can be, however, used to terminate a debugger command. For instance, if you have requested a long display and do not wish to see any more of it, CTRL+C will end the display and return you to the debugger command prompt.

When performing remote debugging with CDB, CTRL+C can be pressed on the host computer's keyboard. If you wish to issue a break from the target computer's keyboard, use CTRL+C on an x86 machine.

The F12 key can be used to get a command prompt when the application being debugged is busy. Set the focus on one of the target application's windows and press the F12 key on the target computer.

When Using KD

In kernel mode, the CTRL+C command causes the target computer to break into the debugger. This locks the target computer and wakes up the debugger.

When debugging a system that is still running, CTRL+C must be pressed on the host keyboard to get the initial command prompt.

If the debugger is already active, CTRL+C does not affect the target computer. It can be used, however, to terminate a debugger command. For instance, if you have requested a long display and do not wish to see any more of it, CTRL+C will end the display and return you to the debugger command prompt.

CTRL+C can also be used to get a command prompt when a debugger command is generating a long display or when the target computer is busy. When debugging an x86 machine, it can be pressed on either the host or target keyboard.

SYSRQ (or ALT+SYSRQ on an enhanced keyboard) is similar. It works from the host or target keyboard on any processor. However, it only works if the prompt has been acquired by pressing CTRL+C at least once previously.

The SYSRQ key can be disabled by editing the registry. In the registry key

HKEY_LOCAL_MACHINE\System\CurrentControlSet\i8042prt\Parameters

create a value named BreakOnSysRq, and set it equal to DWORD 0x0. Then reboot. Once this is done, pressing the SYSRQ key on the target computer's keyboard will not break into the kernel debugger.

When Debugging KD with CDB

If you are debugging KD with CDB, then CTRL+C will be intercepted by the host debugger (CDB). To break into the target debugger (KD), you should use CTRL+F instead.

Note Note that in WinDbg, CTRL+C is a shortcut key that is used to copy text from a window. To issue a break command in WinDbg, use CTRL+BREAK or select Debug | Break from the menu.

Additional Information

For other methods of issuing this command and an overview of related commands, see Controlling the Target.


CTRL+D (Toggle Debug Info)

Toggles debugger internal information flow on and off. This is used to "test the wire" in cases where the debugger is not communicating properly.

Syntax

KD Syntax

CTRL+D  ENTER

WinDbg Syntax

CTRL+ALT+D

Environment

Debuggers | KD and WinDbg only
Modes | kernel mode only
Targets | live debugging only
Platforms | all

Comments

When this is toggled to "on," the debugger outputs information about the communication between the host computer and the target computer.

This command can be used to test whether the debugger has crashed. If you suspect that either the debugger or the target is hung, use this command. If you see packets being sent, the target is still working. If you see timeout messages, then the target is not responding. If there are no messages at all, the debugger has crashed.

If the target is not repsonding, use CTRL+R ENTER CTRL+C. If timeout messages continue to appear, the target has crashed (or the debugger was misconfigured).

This is also useful for debugging the KD debugger itself.


CTRL+F (Break to KD)

Cancels commands or breaks into the debugger. (This control key is particularly useful when you are using CDB to debug KD itself.)

Syntax

CTRL+F  ENTER

Environment

Debuggers | CDB, KD
Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

Under normal conditions, CTRL+F is identical to the standard break commands (CTRL+C in KD and CDB, and Debug | Break or CTRL+BREAK in WinDbg.)

However, if you are debugging KD with CDB, these two commands will work differently. CTRL+C will be intercepted by the host debugger (CDB), while CTRL+F will be intercepted by the target debugger (KD).

See Also

.breakin (Break to the Kernel Debugger)


CTRL+K (Change Post-Reboot Break State)

Changes the conditions on which the debugger will automatically break into the target computer.

Syntax

KD Syntax

CTRL+K  ENTER

WinDbg Syntax

CTRL+ALT+K

Environment

Debuggers | KD and WinDbg only
Modes | kernel mode only
Targets | live debugging only
Platforms | all

Comments

This control key causes the kernel debugger to cycle through the following three states:

No break
In this state, the debugger will not break into the target computer unless you press CTRL+C.
Break on reboot
In this state, the debugger will break into a rebooted target computer after the kernel initializes. This is equivalent to starting KD or WinDbg with the -b command-line option.
Break on first module load
In this state, the debugger will break into a rebooted target computer once the first kernel module is loaded. (This will cause the break to occur earlier than in the "Break on reboot" option.) This is equivalent to starting KD or WinDbg with the -d command-line option.

When CTRL+K is used, the new break state is displayed.

In WinDbg, this can also be accomplished by selecting Debug | Kernel Connection | Cycle Initial Break.

Additional Information

For an overview of related commands, and an explanation of how the reboot process affects the debugger, see Crashing and Rebooting the Target Computer.


CTRL+P (Debug Current Debugger)

Launches a new user-mode debugger, which debugs the current debugger.

Syntax

CTRL+P  ENTER

Environment

Debuggers | CDB and KD only
Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This is essentially equivalent to launching a new CDB via the remote utility, and using it to debug the debugger which you are already running.


CTRL+R (Re-synchronize)

Synchronizes with the target computer.

Syntax

KD Syntax

CTRL+R  ENTER

WinDbg Syntax

CTRL+ALT+R

Environment

Debuggers | KD and WinDbg only
Modes | kernel mode only
Targets | live debugging only
Platforms | all

Comments

This attempts to synchronize the host computer with the target computer. Use this command if the target is not responding.

Additional Information

For other methods of re-establishing contact with the target, see Synchronizing with the Target Computer.


CTRL+V (Toggle Verbose Mode)

Toggles verbose mode on and off.

Syntax

CDB / KD Syntax

CTRL+V  ENTER

WinDbg Syntax

CTRL+ALT+V

Environment

Debuggers | CDB, KD, WinDbg
Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

When verbose mode is on, some display commands (such as register dumping) produce more detailed output. Every MODULE LOAD operation which is sent to the debugger will be displayed. And every time a driver or DLL is loaded by the operating system, the debugger will be notified.

In WinDbg, this can also be accomplished by selecting View | Verbose Output.


CTRL+W (Show Debugger Version)

Displays version information for the debugger and all loaded extension DLLs.

Syntax

CDB / KD Syntax

CTRL+W  ENTER

WinDbg Syntax

CTRL+ALT+W

Environment

Debuggers | CDB, KD, WinDbg
Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | all

Comments

This has the same effect as the version (Show Debugger Version) command, except that the latter command displays the Windows® operating system version as well.

In WinDbg, this can also be accomplished by selecting View | Show Version.

See Also

version (Show Debugger Version), vertarget (Show Target Computer Version)


Debugger Extension Commands

This section of the reference discusses the various debugger extension commands that can be used in CDB, KD, and WinDbg.

Each extension command (or just extension for short) appears on its own reference page. Characters in bold type represent things which are literally typed, while characters in italic type indicate parameters which are explained in the Parameters section of the reference page. Parameters in brackets are optional: [ xxx ]. Brackets with vertical lines indicate that any one, or none, of the enclosed parameters can be used: [ xxx | yyy ]. Braces with vertical lines indicate that exactly one of the enclosed parameters must be used: { xxx | yyy }.

In general, extension commands do not support the full expression syntax that debugger commands and meta-commands do. See the individual reference pages for clarifications regarding each command's syntax requirements.

The following categories of extensions are discussed in this reference:

General Extensions

Kernel-Mode Extensions

User-Mode Extensions

Specialized Extensions


General Extensions

This section of the reference describes extension commands which are frequently used during both user-mode and kernel-mode debugging.

These extensions are contained in a variety of different extension DLLs. The debugger should automatically load the proper version of the extension commands; you do not normally have to keep track of the DLL versions being used. See Using Debugger Extension Commands for a description of the default module search order.

If you have unloaded the necessary extension DLL, or have changed the default DLL, you may need to specify the correct file. See Loading Debugger Extension DLLs for an explanation of how to load extension modules.

Each extension command reference page lists the DLLs which expose that command. Use the following rules to determine the proper directory from which to load this extension DLL:

  • If your target computer is running the free build of Windows® NT® 4.0, use nt4fre\kdextx86.dll, nt4fre\ntsdexts.dll, winext\ext.dll, or dbghelp.dll.
  • If your target computer is running the checked build of Windows NT 4.0, use nt4chk\kdextx86.dll, nt4chk\ntsdexts.dll, winext\ext.dll, or dbghelp.dll.
  • If your target computer is running the free build of Windows 2000, use w2kfre\kdextx86.dll, w2kfre\ntsdexts.dll, winext\ext.dll, or dbghelp.dll.
  • If your target computer is running the checked build of Windows 2000, use w2kchk\kdextx86.dll, w2kchk\ntsdexts.dll, winext\ext.dll, or dbghelp.dll.
  • If your target computer is running Windows XP or Windows .NET Server 2003, use winxp\kdexts.dll, winxp\ntsdexts.dll, winxp\exts.dll, winext\ext.dll, or dbghelp.dll.


!acl

Formats and displays the contents of an access control list (ACL).

Syntax

Windows NT 4.0 and Windows 2000 Syntax:

!acl Address

Windows XP and Windows .NET Server 2003 Syntax

!acl Address [Flags]

Parameters

Address
Specifies the hexadecimal address of the ACL.
Flags
(Windows XP and Windows .NET Server 2003 only) If this is set to one, the "friendly name" is displayed. This includes the security identifier (SID) type, as well as the domain and user name for the SID.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | exts.dll

Additional Information

For information on access control lists, see the Platform SDK, the Windows DDK, or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich. Also see !sid, !sd, and Determining the ACL of an Object.


!analyze

Displays information about the current exception or bug check.

Syntax

User-Mode Syntax

!analyze [-v] [-f]

Kernel-Mode Syntax

!analyze [-v] [-f] [-D BucketID]
!analyze -show BugCheckCode [BugParameters]

Parameters

-v
Causes verbose output to be displayed.
-f
Forces the debugger to generate !analyze output as if there were an exception. Use this if the debugger does not consider an exception to have occurred, but you wish to see the exception analysis anyway.
-D BucketID
Restricts the display to those items relevant to the specified BucketID.
-show
Causes the debugger to show information about the specified bug check code.
BugCheckCode
Specifies the bug check code to be displayed.
BugParameters
Specifies up to four bug check parameters. Separate these with spaces. This allows you to further refine your inquiry.

DLL

Windows NT 4.0 | ext.dll
Windows 2000 | ext.dll
Windows XP Windows .NET Server 2003 | ext.dll

Comments

In user mode, !analyze and !analyze -v will display information about the current exception.

In kernel mode, it will display information about the most recent bug check. If a bug check occurs, the !analyze display is automatically generated. You can use !analyze -v to show additional information. If you only want to see the basic bug check parameters, you can use the .bugcheck (Display Bug Check Data) command.

The !analyzebugcheck -show extension command can be used to display information about an individual bug check code. This display is unaffected by the current status of the target computer.

The "BUCKET ID" line in the display names the general category of failures that the current failure belongs to. This category helps the debugger determine what other information to display in the analysis output. If you wish to restrict the display to a single "bucket", use the -D parameter.

In both user mode and kernel mode, the "Followup" line in the display will show information about the owner of the current stack frame, if this can be determined. This information is determined in the following manner:

  1. When the !analyze extension is used, the debugger looks at the top frame in the stack and attempts to determine the owner of the module and function in this frame. If the owner can be determined, this information is displayed.
  2. If the owner cannot be determined, the debugger passes to the next stack frame, and so on, until the owner is determined or the stack is completely examined.
  3. If the owner can be determined, their name will be displayed after the word Followup. If the stack is exhausted without any information being found, no name is displayed.

For the Followup field to display useful information, you must first create a triage.ini file containing the names of the module and function owners. For details, see Specifying Module and Function Owners.

The following example shows the results of !analyze after a breakpoint is hit:

0:000> !analyze
Last event: Hit breakpoint 10000

The following example shows a user-mode exception:

0:000> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************

***** OS symbols are WRONG. Please fix symbols to do analysis.

Fault occurred in driver Prymes.exe ( Prymes!dzError+0x5e )
004016fe f77dfc           idiv    dword ptr [ebp-0x4]

Exception Record ffffffff
ExceptionAddress: 004016fe (Prymes!dzError+0x0000005e)
   ExceptionCode: c0000094
  ExceptionFlags: 00000000
NumberParameters: 0

Last Control Transfer from 004012ac to 004016fe

Failure Image Name Prymes

Failure Module Name Prymes

BUCKET ID: WRONG_SYMBOLS

Command to show faulting stack:
-------------------------------
    .ecxr ; kb

Faulting Stack:
---------------
ChildEBP RetAddr
0012fea8 004012ac Prymes!dzError+0x5e
0012ff80 00401f69 Prymes!main+0x26c
0012ffc0 77e992a6 Prymes!mainCRTStartup+0xe9
0012fff0 00000000 KERNEL32!GetCommandLineW+0x929

Probably caused by : Prymes ( Prymes!dzError+5e )

Followup: the person on the fifth floor near the elevator

The following is an example of !analyze after bug check 0xC000021A (STATUS_SYSTEM_PROCESS_TERMINATED):

kd> !analyze
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

BugCheck C000021A, {e1497770, 1, 0, 0}

Followup:  EmployeeNumber47

The following is an example of !analyze -v after this same bug check:

kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

WINLOGON_FATAL_ERROR (c000021a)
The Winlogon Process terminated unexpectdly
Arguments:
Arg1: e1497770
Arg2: 00000001
Arg3: 00000000
Arg4: 00000000

Debugging Details:
------------------

BUCKET ID: 0xC000021A

Command to show faulting stack:
-------------------------------
    kb

Faulting Stack:
---------------
ChildEBP RetAddr
fe252918 805226a5 nt!RtlpBreakWithStatusInstruction
fe252964 80522dea nt!KiBugCheckDebugBreak+0x19
fe252d2c 804fc1bb nt!KeBugCheck2+0x43c
fe252d4c 80636954 nt!KeBugCheckEx+0x19
fe252d74 804ebd08 nt!PopGracefulShutdown+0x15b
fe252dac 80559026 nt!ExpWorkerThread+0xfe
fe252ddc 8050f513 nt!PspSystemThreadStartup+0x34
00000000 00000000 nt!_KiThreadStartup+0x16

Followup: the person just north of the lobby

Additional Information

For more information about bug checks, see Bug Checks (Blue Screens). For a description of individual bug checks, see the Bug Check Code Reference section.


!atom

Displays the formatted atom table for the atom specified, or for all atoms of the current process.

Syntax

!atom [Address]

Parameters

Address
Specifies the hexadecimal virtual address of the atom to be displayed. If this is omitted or zero, the atom table for the current process is displayed; this table lists all atoms for the process.

DLL

Windows NT 4.0 | kdextx86.dll ntsdexts.dll
Windows 2000 | kdextx86.dll ntsdexts.dll
Windows XP Windows .NET Server 2003 | exts.dll

Additional Information

For information on atoms and atom tables, see the Platform SDK.


!cpuid

Displays information about the processors on the system.

Syntax

!cpuid [Processor]

Parameters

Processor
Specifies the processor whose information will be displayed. If this is omitted, all processors will be displayed.

DLL

Windows NT 4.0 | ext.dll
Windows 2000 | ext.dll
Windows XP Windows .NET Server 2003 | ext.dll

Comments

The !cpuid extension works during live user-mode or kernel-mode debugging, local kernel debugging, and debugging of dump files. However, user-mode minidump files only contain information about the active processor.

If you are debugging in user mode, the !cpuid extension describes the computer that the target application is running on. In kernel mode, it describes the target computer.

Here is an example of this extension:

kd> !cpuid
CP  F/M/S  Manufacturer        MHz
 0  6,5,1  GenuineIntel        700
 1  8,1,5  AuthenticAMD        700

The CP column gives the processor number (these are always sequential, beginning with zero). The Manufacturer column specifies the processor manufacturer. The MHz column specifies the processor speed, if it is available.

For an x86 or AMD64 processor, the F column gives the processor family number, the M column gives the processor model number, and the S column gives the stepping size.

For an IA-64 processor, the M column gives the processor model number, the R column gives the processor revision number, the F column gives the processor family number, and the A column gives the architecture revision number.

Additional Information

For more information on debugging multiprocessor computers, see Multiprocessor Syntax.


!cxr

The !cxr extension command is obsolete. Use the .cxr (Display Context Record) command instead.


!dh

Displays the headers for the specified image.

Syntax

!dh [Options] Address
!dh -h

Parameters

Options
Can be any one of the following:
-f
Causes the display to include file headers.
-s
Causes the display to include section headers.
-a
Causes the display to include all header information.
Address
The hexadecimal address of the image.
-h
Displays a short help text for this extension.

DLL

Windows NT 4.0 | dbghelp.dll kdextx86.dll ntsdexts.dll
Windows 2000 | dbghelp.dll kdextx86.dll ntsdexts.dll
Windows XP Windows .NET Server 2003 | dbghelp.dll

Comments

The !lmi extension extracts the most important information from the image header and displays it in a concise summary format. It is often more useful than !dh.


!dlls

Displays the table entries of all loaded modules, or all modules being used by a given thread or process.

Syntax

!dlls [Options] [LoaderEntryAddress]
!dlls -h

Parameters

Options
Specifies the level of output. This can be any of the following:
-f
Causes the display to include file headers.
-s
Causes the display to include section headers.
-a
Causes the display to include complete module information. (This is equivalent to -f -s.)
-c ModuleAddress
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Causes the display to include the module containing ModuleAddress.
-i
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Causes the display to be sorted by initialization order.
-l
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Causes the display to be sorted by load order. This is the default.
-m
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Causes the display to be sorted by memory order.
-v
(Windows XP and Windows .NET Server 2003 only) Causes the display to include version information. This information is taken from the resource section of each module.
LoaderEntryAddress
Specifies the address of the loader entry for a module. If this is included, only this specific module will be displayed.
-h
Causes the debugger to display a short help text for this extension.

DLL

Windows NT 4.0 | kdextx86.dll ntsdexts.dll
Windows 2000 | kdextx86.dll ntsdexts.dll
Windows XP Windows .NET Server 2003 | exts.dll

Comments

The module listing includes all entry points into each module.

This extension only works with live debugging — not with crash dump analysis.

In kernel mode, this extension will display the modules for the current process context. The !dlls extension cannot be used with a system process or the idle process.

Here are some examples:

kd> !dlls -c 77f60000
Dump dll containing 0x77f60000:

0x00091f38: E:\WINDOWS\System32\ntdll.dll
      Base   0x77f60000  EntryPoint  0x00000000  Size        0x00097000
      Flags  0x00004004  LoadCount   0x0000ffff  TlsIndex    0x00000000
             LDRP_IMAGE_DLL
             LDRP_ENTRY_PROCESSED

kd> !dlls -a 91ec0

0x00091ec0: E:\WINDOWS\system32\winmine.exe
      Base   0x01000000  EntryPoint  0x01003e2e  Size        0x00020000
      Flags  0x00005000  LoadCount   0x0000ffff  TlsIndex    0x00000000
             LDRP_LOAD_IN_PROGRESS
             LDRP_ENTRY_PROCESSED

File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
     14C machine (i386)
       3 number of sections
3A98E856 time date stamp Sun Feb 25 03:11:18 2001

       0 file pointer to symbol table
       0 number of symbols
      E0 size of optional header
     10F characteristics
            Relocations stripped
            Executable
            Line numbers stripped
            Symbols stripped
            32 bit word machine

OPTIONAL HEADER VALUES
     10B magic #
    7.00 linker version
    3A00 size of code
   19E00 size of initialized data
       0 size of uninitialized data
    3E2E address of entry point
    1000 base of code
         ----- new -----
01000000 image base
    1000 section alignment
     200 file alignment
       2 subsystem (Windows GUI)
    5.01 operating system version
    5.01 image version
    4.00 subsystem version
   20000 size of image
     400 size of headers
   21970 checksum
00040000 size of stack reserve
00001000 size of stack commit
00100000 size of heap reserve
00001000 size of heap commit
01000100 Opt Hdr
       0 [       0] address [size] of Export Directory
    40B4 [      B4] address [size] of Import Directory
    6000 [   19170] address [size] of Resource Directory
       0 [       0] address [size] of Exception Directory
       0 [       0] address [size] of Security Directory
       0 [       0] address [size] of Base Relocation Directory
    11B0 [      1C] address [size] of Debug Directory
       0 [       0] address [size] of Description Directory
       0 [       0] address [size] of Special Directory
       0 [       0] address [size] of Thread Storage Directory
       0 [       0] address [size] of Load Configuration Directory
     258 [      A8] address [size] of Bound Import Directory
    1000 [     1B0] address [size] of Import Address Table Directory
       0 [       0] address [size] of Reserved Directory
       0 [       0] address [size] of Reserved Directory
       0 [       0] address [size] of Reserved Directory

SECTION HEADER #1
   .text name
    3992 virtual size
    1000 virtual address
    3A00 size of raw data
     400 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60000020 flags
         Code
         (no align specified)
         Execute Read

Debug Directories(1)
        Type       Size     Address  Pointer

        cv           1c        13d0      7d0    Format: NB10, 3a98e856, 1, winmi
ne.pdb

SECTION HEADER #2
   .data name
     BB8 virtual size
    5000 virtual address
     200 size of raw data
    3E00 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0000040 flags
         Initialized Data
         (no align specified)
         Read Write

SECTION HEADER #3
   .rsrc name
   19170 virtual size
    6000 virtual address
   19200 size of raw data
    4000 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         (no align specified)
         Read Only


!elog_str

Adds a string to the event log.

Syntax

!elog_str String

Parameters

String
Specifies the string to add to the event log.

DLL

Windows NT 4.0 | ext.dll
Windows 2000 | ext.dll
Windows XP Windows .NET Server 2003 | ext.dll

Comments

Since String is not being sent by a registered event source, it will appear in the event log with a warning in the event log that no event ID can be determined.


!error

Decodes and displays information about an error value.

Syntax

!error Value

Parameters

Value
Specifies the error code. This can be a Microsoft® Win32® error code, a WinSock error code, an NTSTATUS code, or a NetAPI error code.

DLL

Windows NT 4.0 | ext.dll
Windows 2000 | ext.dll ntsdexts.dll
Windows XP Windows .NET Server 2003 | ext.dll


!exchain

Displays the current exception handler chain.

Syntax

!exchain

DLL

This extension is only available on an x86 processor.

Windows NT 4.0 | ext.dll
Windows 2000 | ext.dll
Windows XP Windows .NET Server 2003 | ext.dll

Comments

The !exchain extension displays the list of exception handlers for the current thread.

The list begins with the first handler on the chain (the one that will be given the first chance to handle an exception), and continues on to the end.

Here is an example:

0:000> !exchain
0012fea8: Prymes!_except_handler3+0 (00407604)
  CRT scope  0, filter: Prymes!dzExcepError+e6 (00401576)
                func:   Prymes!dzExcepError+ec (0040157c)
0012ffb0: Prymes!_except_handler3+0 (00407604)
  CRT scope  0, filter: Prymes!mainCRTStartup+f8 (004021b8)
                func:   Prymes!mainCRTStartup+113 (004021d3)
0012ffe0: KERNEL32!GetThreadContext+1c (77ea1856)


!exr

The !exr extension command is obsolete. Use the .exr (Display Exception Record) command instead.


!gflag

Sets or displays the global flags.

Syntax

!gflag [+|-] Value
!gflag {+|-} Abbreviation
!gflag -?
!gflag

Parameters

Value
Specifies a 32-bit hexadecimal number. If no plus (+) or minus (-) is given, this entire number becomes the new value of the global flag bit field. If preceded by a plus (+), this number specifies one or more global flag bits to set to one. If preceded by a minus (-), this number specifies one or more global flag bits to set to zero.
Abbreviation
Specifies a single global flag. Abbreviation is a three-letter abbreviation for a global flag that will either be set to one (+) or to zero (-).
-?
Causes help for this command to be displayed, including a list of global flag abbreviations.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll ntsdexts.dll
Windows XP Windows .NET Server 2003 | exts.dll

Comments

If no arguments are specified, the current global flag settings are displayed.

The following table contains the valid abbreviations.

Value | Name | Description
0x00000001 | "soe" | Stop on exception
0x00000002 | "sls" | Show loader snaps
0x00000004 | "dic" | Debug initial command
0x00000008 | "shg" | Stop on hung GUI
0x00000010 | "htc" | Enable heap tail checking
0x00000020 | "hfc" | Enable heap free checking
0x00000040 | "hpc" | Enable heap parameter checking
0x00000080 | "hvc" | Enable heap validation on call
0x00000100 | "ptc" | Enable pool tail checking
0x00000200 | "pfc" | Enable pool free checking
0x00000400 | "ptg" | Enable pool tagging
0x00000800 | "htg" | Enable heap tagging
0x00001000 | "ust" | Create user-mode stack trace DB
0x00002000 | "kst" | Create kernel-mode stack trace DB
0x00004000 | "otl" | Maintain a list of objects for each type
0x00008000 | "htd" | Enable heap tagging by DLL
0x00010000 | "idp" | Unused
0x00020000 | "d32" | Enable debugging of Microsoft® Win32® subsystem
0x00040000 | "ksl" | Enable loading of kernel debugger symbols
0x00080000 | "dps" | Disable paging of kernel stacks
0x00100000 | "scb" | Enable critical system breaks
0x00200000 | "dhc" | Disable heap coalesce on free
0x00400000 | "ece" | Enable close exception
0x00800000 | "eel" | Enable exception logging
0x01000000 | "eot" | Enable object handle type tagging
0x02000000 | "hpa" | Place heap allocations at ends of pages
0x04000000 | "dwl" | Debug WINLOGON
0x08000000 | "ddp" | Disable kernel-mode DbgPrint and KdPrint output
0x10000000 | NULL | Unused
0x20000000 | NULL | Unused
0x40000000 | NULL | Unused
0x80000000 | "dpd" | Disable protected DLL verification

Additional Information

These flags can also be set by using the Global Flags utility (gflags.exe).


!gle

Displays the last error value for the current thread.

Syntax

!gle [-all]

Parameters

-all
Causes the display to include the last error for each user-mode thread on the target system. If this is omitted in user mode, the last error for the current thread is displayed. If this is omitted in kernel mode, the last error for the thread specified by the current register context is displayed.

DLL

Windows NT 4.0 | ext.dll ntsdexts.dll
Windows 2000 | ext.dll ntsdexts.dll
Windows XP Windows .NET Server 2003 | ext.dll

Comments

This extension displays the value of GetLastError and attempts to decode this value.

In kernel mode, the !gle extension will only work if the TEB is readable by the debugger.

Additional Information

For information on the GetLastError routine, see the Platform SDK.


!handle

Displays information about a handle or handles owned by one or all processes in the target system.

Syntax

User-Mode Syntax

!handle [Handle [UMFlags [TypeName]]]
!handle -?

Kernel-Mode Syntax

!handle [Handle [KMFlags [Process [TypeName]]]]

Parameters

Handle
Specifies the index of the handle to be displayed. If Handle is zero or omitted, data for all handles will be displayed.
UMFlags
(User mode only) Specifies what the display should contain. This can be a sum of any of the following bit values (the default is 0x1):
Bit 0 (0x1)
Causes the display to include handle type information.
Bit 1 (0x2)
Causes the display to include basic handle information.
Bit 2 (0x4)
Causes the display to include handle name information.
Bit 3 (0x8)
Causes the display to include object-specific handle information, when available.
KMFlags
(Kernel mode only) Specifies what the display should contain. This can be a sum of any of the following bit values (the default is 0x3):
Bit 0 (0x1)
Causes the display to include basic handle information.
Bit 1 (0x2)
Causes the display to include information about objects.
Bit 2 (0x4)
Causes the display to include free handle entries. If this bit is not set and Handle is zero or omitted, the list of handles displayed will not include free handles. If Handle specifies a single free handle, it will be displayed even if this bit is not set.
Bit 4 (0x10)
(Windows XP and Windows .NET Server 2003 only) Displays the handle from the kernel handle table instead of the current process.
Bit 5 (0x20)
(Windows XP and Windows .NET Server 2003 only) Interprets the handle as a thread ID or process ID, and displays information about the corresponding kernel object.
Process
(Kernel-mode only) Specifies a process. Either the process ID or the hexadecimal address of the process object can be used. This must refer to a currently running process on the target system. If this is -1 or omitted, the current process is used.
TypeName
Specifies the type of handle you wish to examine. Only handles matching this type will be displayed. TypeName is case-sensitive. Valid types include: Event, Section, File, Port, Directory, SymbolicLink, Mutant, WindowStation, Semaphore, Key, Token, Process, Thread, Desktop, IoCompletion, Timer, Job, and WaitablePort.
-?
(User mode only) Causes a short help text for this extension to be displayed.

DLL

Windows NT 4.0 | kdextx86.dll uext.dll ntsdexts.dll
Windows 2000 | kdextx86.dll uext.dll ntsdexts.dll
Windows XP Windows .NET Server 2003 | kdexts.dll uext.dll ntsdexts.dll

Comments

The !handle extension can be used during user-mode and kernel-mode live debugging. It can also be used on kernel-mode dump files. However, it cannot be used on user-mode dump files, unless they were specifically created with handle information. (This can be done by using the .dump /mh (Create Dump File) command.)

During live user-mode debugging, you can use the .closehandle (Close Handle) command to close one or more handles.

Here are some user-mode examples. The following command will display a list of all handles:

0:000> !handle
Handle 4
  Type          Section
Handle 8
  Type          Event
Handle c
  Type          Event
Handle 10
  Type          Event
Handle 14
  Type          Directory
Handle 5c
  Type          File
6 Handles
Type            Count
Event           3
Section         1
File            1
Directory       1

The following command will display detailed information about handle 0x8:

0:000> !handle 8 f
Handle 8
  Type          Event
  Attributes    0
  GrantedAccess 0x100003:
         Synch
         QueryState,ModifyState
  HandleCount   2
  PointerCount  3
  Name          <none>
  Object Specific Information
    Event Type Auto Reset
    Event is Waiting

Here are some kernel-mode examples. The following command will list all handles, including free handles:

kd> !handle 0 4
processor number 0
PROCESS 80559800  SessionId: 0  Cid: 0000    Peb: 00000000  ParentCid: 0000
    DirBase: 00039000  ObjectTable: e1000d60  TableSize: 380.
    Image: Idle

New version of handle table at e1002000 with 380 Entries in use

0000: free handle, Entry address e1002000, Next Entry fffffffe
0004: Object: 80ed5238  GrantedAccess: 001f0fff
0008: Object: 80ed46b8  GrantedAccess: 00000000
000c: Object: e1281d00  GrantedAccess: 000f003f
0010: Object: e1013658  GrantedAccess: 00000000
......
0168: Object: ffb6c748  GrantedAccess: 00000003 (Protected)
016c: Object: ff811f90  GrantedAccess: 0012008b
0170: free handle, Entry address e10022e0, Next Entry 00000458
0174: Object: 80dfd5c8  GrantedAccess: 001f01ff
......

The following command will show detailed information about handle 0x14 in the kernel handle table:

kd> !handle 14 13
processor number 0
PROCESS 80559800  SessionId: 0  Cid: 0000    Peb: 00000000  ParentCid: 0000
    DirBase: 00039000  ObjectTable: e1000d60  TableSize: 380.
    Image: Idle

Kernel New version of handle table at e1002000 with 380 Entries in use
0014: Object: e12751d0  GrantedAccess: 0002001f
Object: e12751d0  Type: (80ec8db8) Key
    ObjectHeader: e12751b8
        HandleCount: 1  PointerCount: 1
        Directory Object: 00000000  Name: \REGISTRY\MACHINE\SYSTEM\CONTROLSET001\CONTROL\SESSION MANAGER\EXECUTIVE

Additional Information

For information on handles, see the Platform SDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich. Also see !htrace.


!heap

Displays heap usage information, controls breakpoints in the heap manager, detects leaked heap blocks, searches for heap blocks, or displays page heap information.

Syntax

Windows NT 4.0 Syntax

!heap [HeapOptions] [ValidationOptions] [Heap]
!heap -b [{alloc|realloc|free} [Tag]] [Heap | BreakAddress]
!heap -B {alloc|realloc|free} [Heap | BreakAddress]
!heap -?

Windows 2000 Syntax

!heap [HeapOptions] [ValidationOptions] [Heap]
!heap -b [{alloc|realloc|free} [Tag]] [Heap | BreakAddress]
!heap -B {alloc|realloc|free} [Heap | BreakAddress]
!heap -p PageHeapOptions
!heap [-p] -?

Windows XP and Windows .NET Server 2003 Syntax

!heap [HeapOptions] [ValidationOptions] [Heap]
!heap -b [{alloc|realloc|free} [Tag]] [Heap | BreakAddress]
!heap -B {alloc|realloc|free} [Heap | BreakAddress]
!heap -l
!heap -s [SummaryOptions] [StatHeapAddress]
!heap -x [-v] Address
!heap -p PageHeapOptions
!heap [-p] -?

Parameters

Heap
Specifies either a heap index number or a heap address. One is the default and specifies the process heap. Zero causes the command to display information about all heaps in the process. Omitting Heap gives a concise list of all heaps in the process.
HeapOptions
Can be any combination of the following options. The HeapOptions are case-sensitive.
Option | Effect
-v | Causes the debugger to validate the specified heap.
-a | Causes the display to include all information for the specified heap. (Equivalent to -h -f -m. This can take a long time.)
-h | Causes the display to include all entries for the specified heap.
-f | Causes the display to include all the free list entries for the specified heap.
-m | Causes the display to include all the segment entries for the specified heap.
-t | Causes the display to include the tag information for the specified heap.
-T | Causes the display to include the pseudo-tag entries for the specified heap.
-g | Causes the display to include the global tag information. Global tags are associated with each untagged allocation.
-s | Causes the display to include summary information for the specified heap.
-k | (x86 targets only) Causes the display to include the stack backtrace associated with each entry.
-c | (Windows NT 4.0 only) Causes the display to include the recent API calls made for the specified heap.

ValidationOptions
Can be any single one of the following options. The ValidationOptions are case-sensitive.
Option | Effect
-C | (Windows NT 4.0 only) Toggles API call tracing for the specified heap. Using this option will alternately enable and disable this tracing. The initial state of this tracing depends on whether the flags passed to RtlCreateHeap included HEAP_CREATE_ENABLE_TRACING. This state can also be changed by the global flags.
-D | Disables validate-on-call for the specified heap.
-E | Enables validate-on-call for the specified heap.
-d | Disables heap checking for the specified heap.
-e | Enables heap checking for the specified heap.

BreakAddress
Specifies the address of a block where a breakpoint is to be set or removed.
-b
Causes the debugger to create a conditional breakpoint in the heap manager. The -b option can be followed by alloc, realloc, or free; this specifies whether the breakpoint will be activated by allocating, reallocating, or freeing memory. If BreakAddress is used to specify the address of the block, the breakpoint type can be omitted. If Heap is used to specify the heap address or heap index, the type must be included, as well as the Tag parameter.
Tag
Specifies the tag name within the heap.
-B
Causes the debugger to remove a conditional breakpoint from the heap manager. The breakpoint type (alloc, realloc, or free) must be specified, and must be the same as that used with the -b option.
-l
(Windows XP and Windows .NET Server 2003 only) Causes the debugger to detect leaked heap blocks.
-s
(Windows XP and Windows .NET Server 2003 only) Specifies that summary information is being requested.
SummaryOptions
(Windows XP and Windows .NET Server 2003 only) Can be any combination of the following options. The SummaryOptions are not case-sensitive.
Option | Effect
-v | Verifies all data blocks.
-b BucketSize | Specifies the bucket size.
-d DumpBlockSize | Specifies the bucket size.

StatHeapAddress
(Windows XP and Windows .NET Server 2003 only) Specifies the address of the heap. If this is zero or omittted, all heaps are displayed.
-x [-v]
(Windows XP and Windows .NET Server 2003 only) Causes the debugger to search for the heap block containing the specified address. If -v is added, the command will search the current process' entire virtual memory space for pointers to this heap block.
Address
(Windows XP and Windows .NET Server 2003 only) Specifies the address to search for.
-p
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Specifies that page heap information is being requested. If this is used without any PageHeapOptions, all page heaps will be displayed.
PageHeapOptions
Can be any single one of the following options. The PageHeapOptions are case-sensitive.
Option | Effect
-h Address | Causes the debugger to display detailed information about a page heap at Address.
-a Address | Causes the debugger to find the page heap whose block is at Address. Full details of how this address relates to full page heap blocks will be included: whether or not this address is part of a page heap, its offset inside the block, and whether the block is allocated or was freed.
-t[c|s] [Traces] | Causes the debugger to display the collected traces of the heavy heap users. Traces specifies the number of traces to display; the default is four. If there are more traces than the specified number, the earliest traces are displayed. If -t or -tc is used, the traces are sorted by count usage. If -ts is used, the traces are sorted by size. (The -tc and -ts options are supported in Windows XP and Windows .NET Server 2003 only.)
-fi [Traces] | (Windows XP and Windows .NET Server 2003 only) Causes the debugger to display the most recent fault injection traces. Traces specifies the quantity to be displayed; the default is four.
-? Causes the debugger to display page heap help, including a diagram of heap blocks. (These diagrams can also be seen in the Comments section following.)

Before you can use any !heap -p extension command, the page heap must be enabled for your target process. See details in the Comments section following.

-?
Causes the display to display help for this extension. Use !heap -? for generic help, and !heap -p -? for page heap help. (Page heap help is available in Windows 2000, Windows XP, and Windows .NET Server 2003 only.)

DLL

Windows NT 4.0 | kdextx86.dll ntsdexts.dll
Windows 2000 | kdextx86.dll ntsdexts.dll
Windows XP Windows .NET Server 2003 | exts.dll

Comments

This extension command can be used to perform a variety of tasks.

The standard !heap command is used to display heap information for the current process. (This should be used only for user-mode processes. The !pool extension command should be used for system processes.)

The !heap -b and !heap -B commands are used to create and delete conditional breakpoints in the heap manager.

The !heap -l command detects leaked heap blocks. It uses a "garbage collector" algorithm to detect all busy blocks from the heaps that are not referenced anywhere in the process address space. For huge applications, it can take a few minutes to complete. This command is only available in Windows XP and Windows .NET Server 2003.

The !heap -x command searches for a heap block containing a given address. If the -v option is used, this command will additionally search the current process' entire virtual memory space for pointers to this heap block. This command is only available in Windows XP and Windows .NET Server 2003.

The !heap -p command displays various forms of page heap information. This command is only available in Windows 2000 (Service Pack 1 or later), Windows XP, and Windows .NET Server 2003. If you are debugging Windows NT 4.0, you should use !dphdump, !dphfind, !dphflags, and !dphhogs instead.

Before using !heap -p, you must enable the page heap for the target process. This is done through the Global Flags (gflags.exe) utility. Start this utility, fill in the name of the target application in the Image File Name text box, select Image File Options and Enable page heap, and click Apply. Alternatively, you can start the Global Flags utility from an MS-DOS Command prompt window by typing gflags /i xxx.exe +hpa, where xxx.exe is the name of the target application.

Here is an example of the standard !heap command:

0:000> !ntsdexts.heap -a
Index   Address  Name      Debugging options enabled
  1:   00250000
    Segment at 00250000 to 00350000 (00056000 bytes committed)
    Flags:               50000062
    ForceFlags:          40000060
    Granularity:         8 bytes
    Segment Reserve:     00100000
    Segment Commit:      00004000
    DeCommit Block Thres:00000400
    DeCommit Total Thres:00002000
    Total Free Size:     000003be
    Max. Allocation Size:7ffddfff
    Lock Variable at:    00250b54
    Next TagIndex:       0012
    Maximum TagIndex:    07ff
    Tag Entries:         00350000
    PsuedoTag Entries:   00250548
    Virtual Alloc List:  00250050
    UCR FreeList:        002504d8
    128-bit bitmap of free lists
    FreeList Usage:      00000014 00000000 00000000 00000000
              Free    Free
              List    List
              #       Head      Blink      Flink
    FreeList[ 00 ] at 002500b8: 002a4378 . 002a4378
                                0x02 - HEAP_ENTRY_EXTRA_PRESENT
                                0x04 - HEAP_ENTRY_FILL_PATTERN
        Entry     Prev    Cur   0x10 - HEAP_ENTRY_LAST_ENTRY

Address   Size    Size  flags
002a4370: 00098 . 01c90 [14] - free
    FreeList[ 02 ] at 002500c8: 0025cb30 . 002527b8
002527b0: 00058 . 00010 [04] - free
0025cb28: 00088 . 00010 [04] - free
    FreeList[ 04 ] at 002500d8: 00269a08 . 0026e530
0026e528: 00038 . 00020 [04] - free
0026a4d0: 00038 . 00020 [06] - free
0026f9b8: 00038 . 00020 [04] - free
0025cda0: 00030 . 00020 [06] - free
00272660: 00038 . 00020 [04] - free
0026ab60: 00038 . 00020 [06] - free
00269f20: 00038 . 00020 [06] - free
00299818: 00038 . 00020 [04] - free
0026c028: 00038 . 00020 [06] - free
00269a00: 00038 . 00020 [46] - free

    Segment00 at 00250b90:
Flags:           00000000
Base:            00250000
First Entry:     00250bc8
Last Entry:      00350000
Total Pages:     00000080
Total UnCommit:  00000055
Largest UnCommit:000aa000
UnCommitted Ranges: (1)
    002a6000: 000aa000

    Heap entries for Segment00 in Heap 250000
                        0x01 - HEAP_ENTRY_BUSY
                        0x02 - HEAP_ENTRY_EXTRA_PRESENT
                        0x04 - HEAP_ENTRY_FILL_PATTERN
                        0x08 - HEAP_ENTRY_VIRTUAL_ALLOC
                        0x10 - HEAP_ENTRY_LAST_ENTRY
                        0x20 - HEAP_ENTRY_SETTABLE_FLAG1
                        0x40 - HEAP_ENTRY_SETTABLE_FLAG2
Entry     Prev    Cur   0x80 - HEAP_ENTRY_SETTABLE_FLAG3

Address   Size    Size  flags       (Bytes used)    (Tag name)
00250000: 00000 . 00b90 [01] - busy (b90)
00250b90: 00b90 . 00038 [01] - busy (38)
00250bc8: 00038 . 00040 [07] - busy (24), tail fill (NTDLL!LDR Database)
00250c08: 00040 . 00060 [07] - busy (48), tail fill (NTDLL!LDR Database)
00250c68: 00060 . 00028 [07] - busy (10), tail fill (NTDLL!LDR Database)
00250c90: 00028 . 00060 [07] - busy (48), tail fill (NTDLL!LDR Database)
00250cf0: 00060 . 00050 [07] - busy (38), tail fill (Objects=  80)
00250d40: 00050 . 00048 [07] - busy (2e), tail fill (NTDLL!LDR Database)
00250d88: 00048 . 00c10 [07] - busy (bf4), tail fill (Objects>1024)
00251998: 00c10 . 00030 [07] - busy (12), tail fill (NTDLL!LDR Database)
...
002525c0: 00030 . 00060 [07] - busy (48), tail fill (NTDLL!LDR Database)
00252620: 00060 . 00050 [07] - busy (38), tail fill (NTDLL!LDR Database)
00252670: 00050 . 00040 [07] - busy (22), tail fill (NTDLL!CSRSS Client)
002526b0: 00040 . 00040 [07] - busy (24), tail fill (Objects=  64)
002526f0: 00040 . 00040 [07] - busy (24), tail fill (Objects=  64)
00252730: 00040 . 00028 [07] - busy (10), tail fill (Objects=  40)
00252758: 00028 . 00058 [07] - busy (3c), tail fill (Objects=  88)
002527b0: 00058 . 00010 [04] free fill
002527c0: 00010 . 00058 [07] - busy (3c), tail fill (NTDLL!LDR Database)
00252818: 00058 . 002d0 [07] - busy (2b8), tail fill (Objects= 720)
00252ae8: 002d0 . 00330 [07] - busy (314), tail fill (Objects= 816)
00252e18: 00330 . 00330 [07] - busy (314), tail fill (Objects= 816)
00253148: 00330 . 002a8 [07] - busy (28c), tail fill (NTDLL!LocalAtom)
002533f0: 002a8 . 00030 [07] - busy (18), tail fill (NTDLL!LocalAtom)
00253420: 00030 . 00030 [07] - busy (18), tail fill (NTDLL!LocalAtom)
00253450: 00030 . 00098 [07] - busy (7c), tail fill (BASEDLL!LMEM)
002534e8: 00098 . 00060 [07] - busy (44), tail fill (BASEDLL!TMP)
00253548: 00060 . 00020 [07] - busy (1), tail fill (Objects=  32)
00253568: 00020 . 00028 [07] - busy (10), tail fill (Objects=  40)
00253590: 00028 . 00030 [07] - busy (16), tail fill (Objects=  48)
...
0025ccb8: 00038 . 00060 [07] - busy (48), tail fill (NTDLL!LDR Database)
0025cd18: 00060 . 00058 [07] - busy (3c), tail fill (NTDLL!LDR Database)
0025cd70: 00058 . 00030 [07] - busy (18), tail fill (NTDLL!LDR Database)
0025cda0: 00030 . 00020 [06] free fill (NTDLL!Temporary)
0025cdc0: 00020 . 00258 [07] - busy (23c), tail fill (Objects= 600)
0025d018: 00258 . 01018 [07] - busy (1000), tail fill (Objects>1024)
0025e030: 01018 . 00060 [07] - busy (48), tail fill (NTDLL!LDR Database)
...
002a4190: 00028 . 00118 [07] - busy (100), tail fill (BASEDLL!GMEM)
002a42a8: 00118 . 00030 [07] - busy (18), tail fill (Objects=  48)
002a42d8: 00030 . 00098 [07] - busy (7c), tail fill (Objects= 152)
002a4370: 00098 . 01c90 [14] free fill
002a6000:      000aa000      - uncommitted bytes.

Here is an example of the !heap -l command:

1:0:011> !heap -l
1:Heap 00170000
Heap 00280000
Heap 00520000
Heap 00b50000
Heap 00c60000
Heap 01420000
Heap 01550000
Heap 016d0000
Heap 019b0000
Heap 01b40000
Scanning VM ...
Entry     User      Heap      Segment       Size  PrevSize  Flags
----------------------------------------------------------------------
001b2958  001b2960  00170000  00000000        40        18  busy extra
001b9cb0  001b9cb8  00170000  00000000        80       300  busy extra
001ba208  001ba210  00170000  00000000        80        78  busy extra
001cbc90  001cbc98  00170000  00000000        e0        48  busy extra
001cbd70  001cbd78  00170000  00000000        d8        e0  busy extra
001cbe90  001cbe98  00170000  00000000        68        48  busy extra
001cbef8  001cbf00  00170000  00000000        58        68  busy extra
001cc078  001cc080  00170000  00000000        f8       128  busy extra
001cc360  001cc368  00170000  00000000        80        50  busy extra
001cc3e0  001cc3e8  00170000  00000000        58        80  busy extra
001fe550  001fe558  00170000  00000000       150       278  busy extra
001fe6e8  001fe6f0  00170000  00000000        48        48  busy extra
002057a8  002057b0  00170000  00000000        58        58  busy extra
00205800  00205808  00170000  00000000        48        58  busy extra
002058b8  002058c0  00170000  00000000        58        70  busy extra
00205910  00205918  00170000  00000000        48        58  busy extra
00205958  00205960  00170000  00000000        90        48  busy extra
00246970  00246978  00170000  00000000        60        88  busy extra
00251168  00251170  00170000  00000000        78        d0  busy extra user_flag
00527730  00527738  00520000  00000000        40        40  busy extra
00527920  00527928  00520000  00000000        40        80  busy extra
21 leaks detected.

The table in this example contains all 21 leaks found.

Here is an example of the !heap -x command:

0:011> !heap 002057b8 -x
Entry     User      Heap      Segment       Size  PrevSize  Flags
----------------------------------------------------------------------
002057a8  002057b0  00170000  00170640        58        58  busy extra

Here is an example of the !heap -x -v command:

1:0:011> !heap 002057b8 -x -v
1:Entry     User      Heap      Segment       Size  PrevSize  Flags
----------------------------------------------------------------------
002057a8  002057b0  00170000  00170640        58        58  busy extra

Search VM for address range 002057a8 - 002057ff : 00205990 (002057d0),

In this example, there is a pointer to this heap block at address 0x00205990.

The following diagrams show the arrangement of heap blocks. These are valid in Windows 2000 (Service Pack 1 and later), Windows XP, and Windows .NET Server 2003.

Light page heap block — allocated:

 +-----+---------------+---+
 |     |               |   |
 +-----+---------------+---+
    ^         ^          ^
    |         |          8 suffix bytes (filled with 0xA0)
    |         User allocation (filled with E0 if zeroing not requested)
    Block header (starts with 0xABCDAAAA and ends with 0xDCBAAAAA)

Light page heap block — freed:

 +-----+---------------+---+
 |     |               |   |
 +-----+---------------+---+
    ^         ^          ^
    |         |          8 suffix bytes (filled with 0xA0)
    |         User allocation (filled with F0 bytes)
    Block header (starts with 0xABCDAAA9 and ends with 0xDCBAAA9)

Full page heap block — allocated:

 +-----+---------+---+-------
 |     |         |   |  ... N/A page
 +-----+---------+---+-------
    ^       ^      ^
    |       |      0-7 suffix bytes (filled with 0xD0)
    |       User allocation (if zeroing not requested, filled
            with E0 in Windows 2000 and C0 in Windows XP)
    Block header (starts with 0xABCDBBBB and ends with 0xDCBABBBB)

Full page heap block — freed:

 +-----+---------+---+-------
 |     |         |   |  ... N/A page
 +-----+---------+---+-------
    ^       ^      ^
    |       |      0-7 suffix bytes (filled with 0xD0)
    |       User allocation (filled with F0 bytes)
    Block header (starts with 0xABCDBBA and ends with 0xDCBABBBA)

To see the stack trace of the allocation or freeing of a heap block or full page heap block in Windows 2000, use dds (Display Words and Symbols) with the header address.

To see the stack trace of the allocation or freeing of a heap block or full page heap block in Windows XP or Windows .NET Server 2003, use dt DPH_BLOCK_INFORMATION with the header address, followed by dds with the block's StackTrace field.

Full page heap blocks in Windows 2000 reside at the beginning of the page containing the user allocation, or at the previous page.

Additional Information

For information on heaps, see the Platform SDK, the Windows DDK, or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!help

Displays a help text which briefly describes the extension commands exported from the extension DLL.

This extension command should not be confused with the ? (Command Help) or .help (Meta-Command Help) commands.

Syntax

![ExtensionDLL.]help [-v] [CommandName]

Parameters

ExtensionDLL
Specifies the extension DLL whose help text is to be displayed.
-v
Causes verbose output to be displayed. Not available in all DLLs.
CommandName
Specifies a single command whose help text is desired. This is only supported for certain commands, in a few DLLs.

DLL

This extension is available in most extension DLLs.

Comments

Some individual commands will also display a help text if you use a /? or -? parameter with the command name.


!htrace

Displays stack trace information for one or more handles.

Syntax

User-Mode Syntax

!htrace [Handle]
!htrace -?

Kernel-Mode Syntax

!htrace [Handle [Process]]
!htrace -?

Parameters

Handle
Specifies the handle whose stack trace is to be displayed. If Handle is zero or omitted, stack traces for all handles in the process will be displayed.
Process
(Kernel mode only) Specifies the process whose handles are to be displayed. In user mode, the current process' handles are displayed.
-?
Causes a short help text for this extension to be displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll ntsdexts.dll

Comments

Before !htrace can be used, Application Verifier must be activated for the target process, and the Detect invalid handle usage option must be selected. This causes stack trace information to be saved each time the process opens a handle, closes a handle, or references an invalid handle. For more information, see Application Verifier.

The following example will display information about all handles in process 0x815328B0:

kd> !htrace 0 81400300
Process 0x81400300
ObjectTable 0xE10CCF60

--------------------------------------
Handle 0x7CC - CLOSE:
0x8018FCB9: ntoskrnl!ExDestroyHandle+0x103
0x801E1D12: ntoskrnl!ObpCloseHandleTableEntry+0xE4
0x801E1DD9: ntoskrnl!ObpCloseHandle+0x85
0x801E1EDD: ntoskrnl!NtClose+0x19
0x010012C1: badhandle!mainCRTStartup+0xE3
0x77DE0B2F: KERNEL32!BaseProcessStart+0x3D
--------------------------------------
Handle 0x7CC - OPEN:
0x8018F44A: ntoskrnl!ExCreateHandle+0x94
0x801E3390: ntoskrnl!ObpCreateUnnamedHandle+0x10C
0x801E7317: ntoskrnl!ObInsertObject+0xC3
0x77DE23B2: KERNEL32!CreateSemaphoreA+0x66
0x010011C5: badhandle!main+0x45
0x010012C1: badhandle!mainCRTStartup+0xE3
0x77DE0B2F: KERNEL32!BaseProcessStart+0x3D
--------------------------------------
Handle 0x7DC - BAD REFERENCE:
0x8018F709: ntoskrnl!ExMapHandleToPointerEx+0xEA
0x801E10F2: ntoskrnl!ObReferenceObjectByHandle+0x12C
0x801902BE: ntoskrnl!NtSetEvent+0x6C
0x80154965: ntoskrnl!_KiSystemService+0xC4
0x010012C1: badhandle!mainCRTStartup+0xE3
0x77DE0B2F: KERNEL32!BaseProcessStart+0x3D
--------------------------------------
Handle 0x7DC - CLOSE:
0x8018FCB9: ntoskrnl!ExDestroyHandle+0x103
0x801E1D12: ntoskrnl!ObpCloseHandleTableEntry+0xE4
0x801E1DD9: ntoskrnl!ObpCloseHandle+0x85
0x801E1EDD: ntoskrnl!NtClose+0x19
0x010012C1: badhandle!mainCRTStartup+0xE3
0x77DE0B2F: KERNEL32!BaseProcessStart+0x3D
--------------------------------------
Handle 0x7DC - OPEN:
0x8018F44A: ntoskrnl!ExCreateHandle+0x94
0x801E3390: ntoskrnl!ObpCreateUnnamedHandle+0x10C
0x801E7317: ntoskrnl!ObInsertObject+0xC3
0x77DE265C: KERNEL32!CreateEventA+0x66
0x010011A0: badhandle!main+0x20
0x010012C1: badhandle!mainCRTStartup+0xE3
0x77DE0B2F: KERNEL32!BaseProcessStart+0x3D

--------------------------------------
Parsed 0x6 stack traces.
Dumped 0x5 stack traces.

Additional Information

For information on handles, see the Platform SDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich. Also see !handle.


!imggp

Displays the global pointer (GP) directory entry value for a 64-bit image.

Syntax

!imggp Address

Parameters

Address
Specifies the base address of the image.

DLL

Windows NT 4.0 | ext.dll
Windows 2000 | ext.dll
Windows XP Windows .NET Server 2003 | ext.dll


!imgreloc

Displays the addresses of each loaded module, and indicates their former addresses before they were relocated.

Syntax

!imgreloc Address

Parameters

Address
Specifies the base address of the image.

DLL

Windows NT 4.0 | ext.dll
Windows 2000 | ext.dll
Windows XP Windows .NET Server 2003 | ext.dll

Comments

Here is an example:

0:000> !imgreloc 00400000
00400000 Prymes - at preferred address
010e0000 appvcore - RELOCATED from 00400000
5b2f0000 verifier - at preferred address
5d160000 ShimEng - at preferred address


!kuser

Displays the shared user-mode page (KUSER_SHARED_DATA).

Syntax

!kuser

DLL

Windows NT 4.0 | kdextx86.dll ntsdexts.dll
Windows 2000 | kdextx86.dll ntsdexts.dll
Windows XP Windows .NET Server 2003 | exts.dll

Comments

The KUSER_SHARED_DATA page gives resource and other information about the user who is currently logged on.

Here is an example:

kd> !kuser
_KUSER_SHARED_DATA at 7ffe0000
TickCount:    a03afb7 * 00016554
TimeZone Id: 2
ImageNumber Range: [14c .. 14c]
Crypto Exponent: 0
SystemRoot: 'C:\WINDOWS'


!list

Executes a debugger command repeatedly, once for every element in a linked list.

Syntax

!list -t [Module!]Type.Field -x "Command" -a "Arguments" StartAddress
!list -h

Parameters

Module
An optional parameter specifying the module which defines this structure. If there is a chance that Type may be match a valid symbol in a different module, you should include Module to eliminate the ambiguity.
Type
Specifies the name of a data structure.
Field
Specifies the field containing the list link. This can actually be a sequence of fields separated by periods (in other words, Type.Field.Subfield.Subsubfield, and so on).
Command
Specifies the command to execute. This can be any debugger command. It must be enclosed in quotation marks. If Command is omitted, the default is DP (Display Memory).
Arguments
Specifies the arguments to pass to the Command. This must be enclosed in quotation marks. Arguments can be any valid argument string that would normally follow this command, with the restriction that Arguments cannot itself contain quotation marks.
StartAddress
Specifies the address of the first data structure. This is the address at the top of the structure, not necessarily the address of the link field.
-h
Displays a brief help text for this command.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | exts.dll

Comments

The !list extension will go through the linked list and issue the specified command once for each list element.

This command sequence will run until the list terminates in a null pointer, or terminates by looping back onto the first element. If the list loops back onto a later element, this command will not stop. However, you can stop this command at any time by using CTRL+C in KD and CDB, or Debug | Break or CTRL+BREAK in WinDbg.

Each time a command is executed, the address of the current structure will be used as the default address if the command being used has optional address parameters.

Here is an example of how to use this command. Suppose you have a structure whose type name is MYTYPE, and which has links within its .links.Flink and .links.Blink fields. You have a linked list that begins with the structure at 0x6BC000. The following extension command will go through the list, and for each element will execute a dd L2 command. Since no address is being specified to the dd command, it will take the address of the list head as the desired address. This causes the first two DWORDs in each structure to be displayed.

0:000> !list -t MYTYPE.links.Flink -x "dd" -a "L2" 0x6bc00


!lmi

Displays detailed information about a module.

Syntax

!lmi Module

Parameters

Module
Specifies a loaded module, either by name or by base address.

DLL

Windows NT 4.0 | dbghelp.dll
Windows 2000 | dbghelp.dll
Windows XP Windows .NET Server 2003 | dbghelp.dll

Comments

Module addresses can be determined by using the LM (List Loaded Modules) command.

The !lmi extension analyzes the module headers and displays a formatted summary of the information therein. If the module headers are paged out, an error message is displayed.

To see a more extensive display of header information, use the !dh extension command.

Here is an example:

0:000> lm
start    end        module name
00400000 0042d000   Prymes     C (pdb symbols)              Prymes.pdb
77e80000 77f35000   KERNEL32     (export symbols)           C:\WINNT\system32\KERNEL32.dll
77f80000 77ffb000   ntdll        (export symbols)           ntdll.dll

0:000> !lmi 00400000
Loaded Module Info: [00400000]
         Module: Prymes
   Base Address: 00400000
     Image Name: Prymes.exe
   Machine Type: 332 (I386)
     Time Stamp: 3c76c346 Fri Feb 22 14:16:38 2002
           Size: 2d000
       CheckSum: 0
Characteristics: 230e stripped
Debug Data Dirs: Type Size     VA  Pointer
                 MISC  110,     0,   77a00 [Data not mapped]
    Symbol Type: EXPORT   - PDB not found
    Load Report: export symbols

For an explanation of the abbreviations shown in the Characteristics section, see Symbol Status Abbreviations.


!net_send

Sends a message over a local network.

Syntax

!net_send TargetServer TargetUser Sender Message

Parameters

TargetServer
Specifies the computer that will process the command. This should be the name of the computer that the debugger is running on.
TargetUser
Specifies the computer to which the message will be sent.
Sender
Specifies the sender of the message. This can actually be any string. When the message is displayed, this string will be identified as the "sender" of the message.
Message
Specifies the message itself.

DLL

Windows NT 4.0 | ext.dll
Windows 2000 | ext.dll
Windows XP Windows .NET Server 2003 | ext.dll


!obja

Displays the attributes of an object in the object manager.

Syntax

!obja Address

Parameters

Address
Specifies the hexadecimal address of the object header you wish to examine.

DLL

Windows NT 4.0 | ext.dll kdextx86.dll
Windows 2000 | ext.dll kdextx86.dll
Windows XP Windows .NET Server 2003 | ext.dll

Comments

The attributes pertaining to the specified object are listed. Valid attributes are:

#define OBJ_INHERIT             0x00000002L
#define OBJ_PERMANENT           0x00000010L
#define OBJ_EXCLUSIVE           0x00000020L
#define OBJ_CASE_INSENSITIVE    0x00000040L
#define OBJ_OPENIF              0x00000080L
#define OBJ_OPENLINK            0x00000100L
#define OBJ_VALID_ATTRIBUTES    0x000001F2L

Here is an example:

kd> !obja 80967768
Obja +80967768 at 80967768:
        OBJ_INHERIT
        OBJ_PERMANENT
        OBJ_EXCLUSIVE

Additional Information

For information on objects and the object manager, see the Platform SDK, the Windows DDK, or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!owner

Displays the owner of a module or function.

Syntax

!owner [Module[!Symbol]]

Parameters

Module
Specifies the module whose owner is desired. An asterisk (*) at the end of Module represents any number of additional characters.
Symbol
Specifies the symbol within Module whose owner is desired. An asterisk (*) at the end of Symbol represents any number of additional characters. If Symbol is omitted, the owner of the entire module is displayed.

DLL

Windows NT 4.0 | ext.dll
Windows 2000 | ext.dll
Windows XP Windows .NET Server 2003 | ext.dll

Comments

If no parameters are used and a fault has occurred, !owner will display the name of the owner of the faulting module or function.

When you pass a module or function name to the !owner extension, the debugger displays the word Followup followed by the name of owner of the specified module or function.

For this extension to display useful information, you must first create a triage.ini file containing the names of the module and function owners.

For details on the triage.ini file and an example of the !owner extension, see Specifying Module and Function Owners.


!peb

Displays a formatted view of the information in the process environment block (PEB).

Syntax

!peb [PEB-Address]

Parameters

PEB-Address
The hexadecimal address of the process whose PEB you wish to examine. (This is not the address of the PEB as derived from the kernel process block for the process.) If PEB-Address is omitted in user mode, the PEB for the current process is used. If it is omitted in kernel mode, the PEB corresponding to the current process context is displayed.

DLL

Windows NT 4.0 | kdextx86.dll ntsdexts.dll
Windows 2000 | kdextx86.dll ntsdexts.dll
Windows XP Windows .NET Server 2003 | exts.dll

Comments

The PEB is the user-mode portion of Microsoft® Windows process control structures.

If the !peb extension with no argument gives you an error in kernel mode, you should use the !process extension to determine the PEB address for the desired process. Make sure your process context is set to the desired process, and then use the PEB address as the argument for !peb.

The exact output displayed depends on the Windows version and on whether the debugger is kernel-mode or user-mode. The following example is taken from a kernel debugger attached to a Windows .NET Server 2003 target:

kd> !peb
PEB at 7ffdf000
    InheritedAddressSpace:    No
    ReadImageFileExecOptions: No
    BeingDebugged:            No
    ImageBaseAddress:         4ad00000
    Ldr                       77fbe900
    Ldr.Initialized:          Yes
    Ldr.InInitializationOrderModuleList: 00241ef8 . 00242360
    Ldr.InLoadOrderModuleList:           00241e90 . 00242350
    Ldr.InMemoryOrderModuleList:         00241e98 . 00242358
            Base TimeStamp                     Module
        4ad00000 3d34633c Jul 16 11:17:32 2002 D:\WINDOWS\system32\cmd.exe
        77f40000 3d346214 Jul 16 11:12:36 2002 D:\WINDOWS\system32\ntdll.dll
        77e50000 3d3484ef Jul 16 13:41:19 2002 D:\WINDOWS\system32\kernel32.dll
....
    SubSystemData:     00000000
    ProcessHeap:       00140000
    ProcessParameters: 00020000
    WindowTitle:  'D:\Documents and Settings\Administrator\Desktop\Debuggers.lnk'
    ImageFile:    'D:\WINDOWS\system32\cmd.exe'
    CommandLine:  '"D:\WINDOWS\system32\cmd.exe" '
    DllPath:      'D:\WINDOWS\system32;D:\WINDOWS\system32;....
    Environment:  00010000
        ALLUSERSPROFILE=D:\Documents and Settings\All Users
        APPDATA=D:\Documents and Settings\UserTwo\Application Data
        CLIENTNAME=Console
....
        windir=D:\WINDOWS

The similar !teb extension displays the thread environment block.

Additional Information

For information on process environment blocks, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!psr

Displays an IA-64 processor status word (PSR).

Syntax

!psr PSR [DisplayLevel]
!psr @ipsr [DisplayLevel]

Parameters

PSR
Specifies the hexadecimal address of the PSR to be displayed.
@ipsr
Causes the ipsr register to be displayed.
DisplayLevel
Specifies the level of detail to be displayed. 0 indicates the least detail, 1 indicates medium detail, and 2 indicates the most detail. The default is 0.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | exts.dll

This extension command can only be used with an IA-64 target computer.

Additional Information

For more information, see The IA-64 Architecture, or consult an Intel architecture manual.


!sd

Displays the security descriptor at the specified address.

Syntax

Windows NT 4.0 and Windows 2000 Syntax:

!sd Address

Windows XP and Windows .NET Server 2003 Syntax

!sd Address [Flags]

Parameters

Address
Specifies the hexadecimal address of the SECURITY_DESCRIPTOR structure.
Flags
(Windows XP and Windows .NET Server 2003 only) If this is set to one, the "friendly name" is displayed. This includes the security identifier (SID) type, as well as the domain and user name for the SID.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | exts.dll

Additional Information

For an application and an example of this command, see Determining the ACL of an Object. For information on security descriptors, see the Platform SDK, the Windows DDK, or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich. Also see !sid and !acl.


!sid

Displays the security identifier (SID) at the specified address.

Syntax

Windows NT 4.0 and Windows 2000 Syntax:

!sid Address

Windows XP and Windows .NET Server 2003 Syntax

!sid Address [Flags]

Parameters

Address
Specifies the address of the SID structure.
Flags
(Windows XP and Windows .NET Server 2003 only) If this is set to one, the SID type, domain, and user name for the SID is displayed.

(Windows XP and Windows .NET Server 2003 only) If this is set to one, the "friendly name" is displayed. This includes the SID type, as well as the domain and user name for the SID.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | exts.dll

Additional Information

For information on SIDs, see the Platform SDK, the Windows DDK, or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich. Also see !sd and !acl.


!slist

Displays a singly-linked list (SList).

Syntax

!slist Address [ Symbol [Offset] ]
!slist -?

Parameters

Address
Specifies the address of the SLIST_HEADER.
Symbol
Specifies the data type to use for display. If Symbol is specified, the debugger will assume that each node of the SList is an instance of this data type when displaying it.
Offset
Specifies the byte offset of the SList pointer within the structure.
-?
Displays a brief help text for this extension.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | exts.dll

Comments

If you know the nature of the linked structures, the Symbol and Offset parameters are very useful. For example:

0:000> !slist myprog!SlistHeader myprog!MYTYPE 16


!str

Displays an ANSI_STRING or OEM_STRING structure.

Syntax

!str Address

Parameters

Address
Specifies the hexadecimal address of the ANSI_STRING or OEM_STRING structure.

DLL

Windows NT 4.0 | ext.dll
Windows 2000 | ext.dll
Windows XP Windows .NET Server 2003 | ext.dll

Comments

ANSI strings are counted 8-bit character strings, as defined in the following structure:

typedef struct _STRING {
    USHORT Length;
    USHORT MaximumLength;
    PCHAR Buffer;
} STRING;
typedef STRING ANSI_STRING;
typedef STRING OEM_STRING;

If the string is NULL-terminated, Length does not include the trailing NULL.

Additional Information

For more information on ANSI_STRING structures, see the Platform SDK.


!sym

Controls noisy symbol loading and symbol prompts.

Syntax

!sym
!sym noisy
!sym quiet
!sym prompts
!sym prompts off

Parameters

noisy
Activates noisy symbol loading.
quiet
Deactivates noisy symbol loading.
prompts
Allows authentication dialog boxes to appear when SymSrv receives an authentication request.
prompts off
Suppresses all authentication dialog boxes when SymSrv receives an authentication request. This may result in SymSrv being unable to access symbols over the internet.

DLL

Windows NT 4.0 | dbghelp.dll
Windows 2000 | dbghelp.dll
Windows XP Windows .NET Server 2003 | dbghelp.dll

Comments

If the !sym extension is used with no arguments, the current state of noisy symbol loading and symbol prompting is displayed.

The !sym noisy and !sym quiet extensions control noisy symbol loading. For details and for other methods of displaying and changing this option, see SYMOPT_DEBUG.

The !sym prompts and !sym prompts off extensions control whether authentication dialogs are displayed when SymSrv encounters an authentication request. These commands must be followed by .reload (Reload Module) for them to take effect. Authentication requests may be sent by proxy servers, internet firewalls, smart card readers, and secure websites. For details and for other methods of changing this option, see Firewalls and Proxy Servers.


!symsrv

Closes the symbol server client.

Syntax

!symsrv close

DLL

Windows NT 4.0 | dbghelp.dll
Windows 2000 | dbghelp.dll
Windows XP Windows .NET Server 2003 | dbghelp.dll

Comments

The !symsrv close extension will close any active symbol server client.

This can be useful if you need to re-synchronize your connection.

If you have previously refused an internet authentication request, you will need to use !symsrv close to reconnect to the symbol store. See Firewalls and Proxy Servers for details.


!teb

Displays a formatted view of the information in the thread environment block (TEB).

Syntax

!teb [TEB-Address]

Parameters

TEB-Address
The hexadecimal address of the thread whose TEB you wish to examine. (This is not the address of the TEB as derived from the kernel thread block for the thread.) If TEB-Address is omitted in user mode, the TEB for the current process is used. If it is omitted in kernel mode, the TEB corresponding to the current register context is displayed.

DLL

Windows NT 4.0 | kdextx86.dll ntsdexts.dll
Windows 2000 | kdextx86.dll ntsdexts.dll
Windows XP Windows .NET Server 2003 | exts.dll

Comments

The TEB is the user-mode portion of Microsoft® Windows thread control structures.

If the !teb extension with no argument gives you an error in kernel mode, you should use the !process extension to determine the TEB address for the desired thread. Make sure your register context is set to the desired thread, and then use the TEB address as the argument for !teb.

Here is an example of this command's output in user mode:

0:001> ~
   0  id: 324.458   Suspend: 1 Teb 7ffde000 Unfrozen
.  1  id: 324.48c   Suspend: 1 Teb 7ffdd000 Unfrozen

0:001> !teb
TEB at 7FFDD000
    ExceptionList:    76ffdc
    Stack Base:       770000
    Stack Limit:      76f000
    SubSystemTib:     0
    FiberData:        1e00
    ArbitraryUser:    0
    Self:             7ffdd000
    EnvironmentPtr:   0
    ClientId:         324.48c
    Real ClientId:    324.48c
    RpcHandle:        0
    Tls Storage:      0
    PEB Address:      7ffdf000
    LastErrorValue:   0
    LastStatusValue:  0
    Count Owned Locks:0
    HardErrorsMode:   0

The similar !peb extension displays the process environment block.

Additional Information

For information on thread environment blocks, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!tls

Displays a thread local storage (TLS) slot.

Syntax

!tls Slot [TEB]

Parameters

Slot
Specifies the TLS slot. This can be any value between 0 and 1088 (decimal). If Slot is -1, all slots are displayed.
TEB
Specifies the thread environment block (TEB). If this is zero or omitted, the current thread is used.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | exts.dll


!token

Displays a formatted view of a security token object.

Syntax

Windows NT 4.0 and Windows 2000 Syntax (kernel mode only)

!token [Address]

Windows XP and Windows .NET Server 2003 Kernel-Mode Syntax

!token [-n] [Address]
!token -?

Windows XP and Windows .NET Server 2003 User-Mode Syntax

!token [-n] [Handle]
!token -?

Parameters

Address
(Kernel mode only) Specifies the address of the token to be displayed. If this is omitted or zero, the token for the active thread is displayed.
Handle
(User mode only) Specifies the handle of the token to be displayed. If this is omitted or zero, the token associated with the target thread is displayed.
-n
(Windows XP and Windows .NET Server 2003 only) Causes the display to include the "friendly name". This includes the security identifier (SID) type, as well as the domain and user name for the SID. This option cannot be used when you are debugging LSASS.
-?
(Windows XP and Windows .NET Server 2003 only) Displays a short help text for this extension.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | exts.dll

In Windows NT 4.0 and Windows 2000, !token is only available in kernel-mode debugging. In Windows XP and later operating systems, !token is available in kernel-mode and live user-mode debugging. It cannot be used on user-mode dump files.

Comments

The TOKEN structure is a security object type that represents an authenticated user process. Every process has an assigned token, which becomes the default token for each of that process's threads. However, an individual thread can be assigned a token that overrides this default.

You can get the token address from the output of !process. To display a list of the individual fields of the TOKEN structure, use the !tokenfields extension in Windows NT 4.0 or Windows 2000, or use the dt nt!_TOKEN command in Windows XP or Windows .NET Server 2003.

Here is an example:

kd> !process 0n216 1
Searching for Process with Cid == d8
PROCESS 824e7bd0  SessionId: 0  Cid: 00d8    Peb: 7ffdf000  ParentCid: 04b4
    DirBase: 00692000  ObjectTable: 8251f198  TableSize:  24.
    Image: winmine.exe
    VadRoot 82505e78 Vads 39 Clone 0 Private 60. Modified 0. Locked 0.
    DeviceMap e128b478
    Token                             e1659d70
    ElapsedTime                       15:20:59.0879
......

kd> !token e1659d70
TOKEN e1659d70  Flags: 9  Source User32    AuthentId (b4, b486)
    Type:                    Primary (IN USE)
    Token ID:                193ee
    ParentToken ID:          0
    Modified ID:             (0, 193f0)
    TokenFlags:              0x9
    SidCount:                9
    Sids:                    e1659ed0
    RestrictedSidCount:      0
    RestrictedSids:          00000000
    PrivilegeCount:          18
    Privileges:              e1659df8

Additional Information

For information on the kernel-mode TOKEN structure, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich. For information on the user-mode TOKEN structure, see the Platform SDK.


!triage

The !triage extension command is obsolete. Use !analyze instead.


!ustr

Displays a UNICODE_STRING structure.

Syntax

!ustr Address

Parameters

Address
Specifies the hexadecimal address of the UNICODE_STRING structure.

DLL

Windows NT 4.0 | ext.dll
Windows 2000 | ext.dll
Windows XP Windows .NET Server 2003 | ext.dll

Comments

Unicode strings are counted 16-bit character strings, as defined in the following structure:

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING;

If the string is NULL-terminated, Length does not include the trailing NULL.

Most Win32® character string arguments are converted to Unicode strings before any real work is done.

Additional Information

For more information on UNICODE_STRING structures, see the Platform SDK.


!version

Displays the version information for the extension DLL.

This extension command should not be confused with the version (Show Debugger Version) command.

Syntax

![ExtensionDLL.]version

Parameters

ExtensionDLL
Specifies the extension DLL whose version number is to be displayed.

DLL

This extension is available in most extension DLLs.

Comments

If the extension DLL version does not match the debugger version, error messages will be displayed.


Kernel-Mode Extensions

This section of the reference describes extension commands that are primarily used during kernel-mode debugging.

The debugger should automatically load the proper version of the extension commands; you do not normally have to keep track of the DLL versions being used. See Using Debugger Extension Commands for a description of the default module search order.

If you have unloaded the necessary extension DLL, or have changed the default DLL, you may need to specify the correct file. See Loading Debugger Extension DLLs for an explanation of how to load extension modules.

Each extension command reference page lists the DLLs that expose that command. Use the following rules to determine the proper directory from which to load this extension DLL:

  • If your target computer is running the free build of Windows® NT® 4.0 on an x86 processor, use nt4fre\kdextx86.dll.
  • If your target computer is running the checked build of Windows NT 4.0 on an x86 processor, use nt4chk\kdextx86.dll.
  • If your target computer is running the free build of Windows 2000, use w2kfre\kdextx86.dll.
  • If your target computer is running the checked build of Windows 2000, use w2kchk\kdextx86.dll.
  • If your target computer is running Windows XP or Windows .NET Server 2003, use winxp\kdexts.dll.

In addition, kernel-mode extensions that are not specific to any single operating system can be found in winext\kext.dll.


!ahcache

Displays the application compatibility cache.

Syntax

!ahcache [Flags]

Parameters

Flags
Specifies the information to include in the display. This can be any combination of the following bits. The default is zero.
Bit 0 (0x1)
Displays the RTL_GENERIC_TABLE list instead of the LRU list.
Bit 4 (0x10)
Verbose display: includes all entry details, not just the names.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll


!analyzebugcheck

The !analyzebugcheck extension command is obsolete. Use !analyze instead.


!apc

Formats and displays the contents of one or more asynchronous procedure calls (APCs).

Syntax

!apc
!apc proc Process
!apc thre Thread
!apc KAPC

Parameters

Process
Specifies the address of the process whose APCs are to be displayed.
Thread
Specifies the address of the thread whose APCs are to be displayed.
KAPC
Specifies the address of the kernel APC to be displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Without any parameters, !apc displays all APCs.

Additional Information

For information on APCs, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!arbiter

Displays the current system resource arbiters and arbitrated ranges.

Syntax

!arbiter [Flags]

Parameters

Flags
Specifies which classes of arbiters are displayed. If omitted, all arbiters are displayed. These bits can be combined freely.
Bit 0 (0x1)
I/O arbiters.
Bit 1 (0x2)
Memory arbiters.
Bit 2 (0x4)
IRQ arbiters.
Bit 3 (0x8)
DMA arbiters.
Bit 4 (0x10)
Bus Number arbiters.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

For each arbiter, !arbiter displays each allocated range of system resources, some optional flags, the PDO attached to that range (in other words, the range's owner), and the service name of this owner (if known).

The flags have the following meanings:

Flag | Meaning
S | Range is shared
C | Range in conflict
B | Range is boot-allocated
D | Range is driver-exclusive
A | Range alias
P | Range positive decode

Here is an example:

kd> !arbiter 4

DEVNODE 80e203b8 (HTREE\ROOT\0)
  Interrupt Arbiter "" at 80167140
    Allocated ranges:
      0000000000000000 - 0000000000000000   B   80e1d3d8
      0000000000000001 - 0000000000000001   B   80e1d3d8
      .....
      00000000000001a2 - 00000000000001a2
        00000000000001a2 - 00000000000001a2  CB   80e1d3d8
        00000000000001a2 - 00000000000001a2  CB   80e52538  (Serial)
      00000000000001a3 - 00000000000001a3       80e52778  (i8042prt)
      00000000000001b3 - 00000000000001b3       80e1b618  (i8042prt)
    Possible allocation:
      < none >

In this example, the next-to-last line shows the resource range (which consists of 0x1A3 alone), the PDO of 0x80E52778, and the service of i8042prt.sys. No flags are listed on this line.

You can now use !devobj with this PDO address to find the device extension and device node addresses:

kd> !devobj 80e52778
Device object (80e52778) is for:
 00000034 \Driver\PnpManager DriverObject 80e20610
Current Irp 00000000 RefCount 1 Type 00000004 Flags 00001040
DevExt 80e52830 DevObjExt 80e52838 DevNode 80e52628
ExtensionFlags (0000000000)
AttachedDevice (Upper) 80d78b28 \Driver\i8042prt
Device queue is not busy.

Additional Information

See Plug and Play Debugging for applications of this extension command.


!blockeddrv

Displays the list of blocked drivers on the target computer.

Syntax

!blockeddrv

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Here is an example:

kd> !blockeddrv
Driver:      Status    GUID
afd.sys      0:        {00000008-0206-0001-0000-000030C964E1}
agp440.sys   0:        {0000005C-175A-E12D-5000-010020885580}
atapi.sys    0:        {0000005C-B04A-E12E-5600-000020885580}
audstub.sys  0:        {0000005C-B04A-E12E-5600-000020885580}
Beep.SYS     0:        {0000005C-B04A-E12E-5600-000020885580}
Cdfs.SYS     0:        {00000008-0206-0001-0000-000008F036E1}
.....


!bpid

Causes a process on the target computer to break into the debugger.

Syntax

!bpid [Options] PID

Parameters

Options
Controls the additional activities of this command. Any combination of the following options can be used:
-s
Adds an extra breakpoint. This break will occur in the WinLogon process, immediately prior to the break in the user-mode process.
-w
Causes the breakpoint to be written permanently. Each time WinLogon goes through a refresh cycle, this break will appear again.
PID
Specifies the process ID of the desired process on the target computer. If you are using this to control a user-mode debugger on the target computer, PID should be the process ID of the target application, not of the user-mode debugger. (Since process IDs are usually listed in decimal format, you may need to prefix this with 0n, or convert it to hexadecimal format.)

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll

This extension command can only be used with an x86 or IA-64 target computer.

Comments

This command is especially useful when redirecting input and output from a user-mode debugger to the kernel debugger. It causes the user-mode target application to break into the user-mode debugger, which in turn requests input from the kernel debugger. See Controlling the User-Mode Debugger from the Kernel Debugger for details.

If this command is used in another situation, the user-mode process will call DbgBreakPoint. This will usually break directly into the kernel debugger.

The -s option causes a break in WinLogon just before the break in the specified process occurs. This is useful if you wish to perform some debugging actions within WinLogon's process context. The G (Go) command can then be used to move on to the second break.


!bugdump

Formats and displays the information contained in the bug check callback buffers.

Syntax

!bugdump [Component]

Parameters

Component
Specifies the component whose callback data is to be examined. If omitted, all bug check callback data is displayed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This extension can only be used after a bug check has occurred, or when you are debugging a kernel-mode crash dump file.

The Component parameter corresponds to the final parameter used in KeRegisterBugCheckCallback.

The buffers that hold callback data are not available in a Small Memory Dump. These buffers are present in Kernel Memory Dumps and Full Memory Dumps. However, in Windows XP SP1, Windows .NET Server 2003, and later versions of Windows, the dump file is created before the drivers' BugCheckCallback routines are called, and therefore these buffers will not contain the data written by these routines.

If you are performing live debugging of a crashed system, all callback data will be present.

Additional Information

For more information, see Reading Bug Check Callback Data.


!bushnd

Displays a HAL BUS_HANDLER structure.

Syntax

!bushnd [Address]

Parameters

Address
Specifies the hexadecimal address of the HAL BUS_HANDLER structure. If omitted, !bushnd displays a list of buses and the base address of the handler.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll


!ca

Displays the control area for the specified section.

Syntax

!ca Address

Parameters

Address
Specifies the hexadecimal address of the section.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

To get a list of the control areas of all mapped files, use the !memusage extension.

Here is an example:

kd> !memusage
 loading PFN database
loading (99% complete)
             Zeroed:     16 (    64 kb)
               Free:      0 (     0 kb)
            Standby:   2642 ( 10568 kb)
           Modified:    720 (  2880 kb)
    ModifiedNoWrite:      0 (     0 kb)
       Active/Valid:  13005 ( 52020 kb)
         Transition:      0 (     0 kb)
            Unknown:      0 (     0 kb)
              TOTAL:  16383 ( 65532 kb)
  Building kernel map
  Finished building kernel map

  Usage Summary (in Kb):
Control Valid Standby Dirty Shared Locked PageTables  name
ff8636e8    56    376     0     0     0     0  mapped_file( browseui.dll )
ff8cf388    24      0     0     0     0     0  mapped_file( AVH32DLL.DLL )
ff8d62c8    12      0     0     0     0     0  mapped_file( PSAPI.DLL )
ff8dd468   156     28     0     0     0     0  mapped_file( INOJOBSV.EXE )
fe424808   136     88     0    52     0     0  mapped_file( oleaut32.dll )
fe4228a8   152     44     0   116     0     0  mapped_file( MSVCRT.DLL )
ff8ec848     4      0     0     0     0     0    No Name for File
ff859de8     0     32     0     0     0     0  mapped_file( timedate.cpl )
. . . . .

kd> !ca ff8636e8

ControlArea @ff8636e8
  Segment:    e1b74548    Flink              0   Blink:               0
  Section Ref        0    Pfn Ref           6c   Mapped Views:        1
  User Ref           1    Subsections        5   Flush Count:         0
  File Object ff86df88    ModWriteCount      0   System Views:        0
  WaitForDel         0    Paged Usage      380   NonPaged Usage       e0
  Flags (10000a0) Image File HadUserReference

   File: \WINNT\System32\browseui.dll

Segment @ e1b74548:
   Base address        0  Total Ptes        c8  NonExtendPtes:       c8
   Image commit        1  ControlArea ff8636e8  SizeOfSegment: c8000
   Image Base          0  Committed          0  PTE Template:   31b8438
   Based Addr   76e10000  ProtoPtes   e1b74580  Image Info:    e1b748a4

Subsection 1. @ ff863720
   ControlArea: ff8636e8  Starting Sector 0 Number Of Sectors 2
   Base Pte     e1b74580  Ptes In subsect        1 Unused Ptes          0
   Flags              15  Sector Offset          0 Protection           1
    ReadOnly CopyOnWrite

Subsection 2. @ ff863740
   ControlArea: ff8636e8  Starting Sector 2 Number Of Sectors 3d0
   Base Pte     e1b74584  Ptes In subsect       7a Unused Ptes          0
   Flags              35  Sector Offset          0 Protection           3
    ReadOnly CopyOnWrite

Subsection 3. @ ff863760
   ControlArea: ff8636e8  Starting Sector 3D2 Number Of Sectors 7
   Base Pte     e1b7476c  Ptes In subsect        1 Unused Ptes          0
   Flags              55  Sector Offset          0 Protection           5
    ReadOnly CopyOnWrite

Subsection 4. @ ff863780
   ControlArea: ff8636e8  Starting Sector 3D9 Number Of Sectors 21f
   Base Pte     e1b74770  Ptes In subsect       44 Unused Ptes          0
   Flags              15  Sector Offset          0 Protection           1
    ReadOnly CopyOnWrite

Subsection 5. @ ff8637a0
   ControlArea: ff8636e8  Starting Sector 5F8 Number Of Sectors 3a
   Base Pte     e1b74880  Ptes In subsect        8 Unused Ptes          0
   Flags              15  Sector Offset          0 Protection           1
    ReadOnly CopyOnWrite

Additional Information

For information on control areas, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!callback

Displays the callback data related to the trap for the specified thread.

Syntax

!callback Address [Number]

Parameters

Address
Specifies the hexadecimal address of the thread. If this is omitted (or equal to -1), the current thread is used.
Number
Specifies the number of the desired callback frame. This frame will be noted in the display.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

This extension command can only be used with an x86 target computer.

Comments

If the system has not experienced a system trap, this extension will not produce useful data.

Additional Information

For information on system traps, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!calldata

Displays performance information in the form of procedure call statistics from the named table.

Syntax

!calldata Table

Parameters

Table
Name of the table that collects the call data.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Call data was used to measure call performance in older versions of Windows NT.


!cmreslist

Displays the CM_RESOURCE_LIST structure for the specified device object.

Syntax

!cmreslist Address

Parameters

Address
Specifies the hexadecimal address of the CM_RESOURCE_LIST structure.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

See Plug and Play Debugging for applications of this extension command. For information on the CM_RESOURCE_LIST structure, see the Windows DDK.


!cbreg

Displays CardBus Socket registers and CardBus Exchangable Card Architecture (ExCA)registers.

Syntax

!cbreg [%%]Address

Parameters

%%
Indicates that Address is a physical address rather than a virtual address.
Address
Specifies the address of the register to be displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kext.dll kdextx86.dll
Windows XP Windows .NET Server 2003 | kext.dll

The !cbreg extension is only available for an x86 target computer.

Additional Information

The !exca extension can be used to display ExCA registers by socket number.


!cpuinfo

Displays detailed information about the target computer's CPU.

Syntax

Windows 2000 Syntax

!cpuinfo

Windows XP and Windows .NET Server 2003 Syntax

!cpuinfo Processor
!cpuinfo

Parameters

Processor
(Windows XP and Windows .NET Server 2003 only) Specifies the processor to be displayed. If this is omitted, all processors are displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The !cpuinfo extension command can be used when performing local kernel debugging. When this extension is used on a Windows 2000 target computer, it will always display information about all processors.

Here is an example:

kd> !cpuinfo
CP F/M/S Manufacturer  MHz Update Signature Features
 0 6,1,9 GenuineIntel  198 000000d200000000 000000ff

The first number is the processor number.

Additional Information

For more information on debugging multiprocessor computers, see Multiprocessor Syntax.


!db, !dc, !dd, !dp, !du, !dw

Displays data at the specified physical address on the target computer.

The !d* extension commands should not be confused with the D* (Display Memory) command, or with the !ntsdexts.dp extension command.

Syntax

!db [Caching] [-m] [PhysicalAddress] [L Size]
!dc [Caching] [-m] [PhysicalAddress] [L Size]
!dd [Caching] [-m] [PhysicalAddress] [L Size]
!dp [Caching] [-m] [PhysicalAddress] [L Size]
!du [Caching] [-m] [PhysicalAddress] [L Size]
!dw [Caching] [-m] [PhysicalAddress] [L Size]

Parameters

Caching
Can be any one of the following values. The Caching value must be surrounded by square brackets:
[c]
Causes this extension to read from cached memory.
[uc]
Causes this extension to read from uncached memory.
[wc]
Causes this extension to read from write-combined memory.
-m
Causes memory to be read one unit at a time. For example, !db -m will read memory in eight-bit chunks and !d2 -m will read memory in sixteen-bit chunks. If your hardware does not support 32-bit physical memory reads, it may be necessary to use the -m option. This option does not affect the length or appearance of the display — it only affects how the memory is accessed.
PhysicalAddress
Specifies the first physical address to be displayed, in hexadecimal format. If this is omitted the first time this command is used, the address defaults to zero. If this is omitted on a subsequent use, the display will begin where the last display ended.

DLL

Windows NT 4.0 | kext.dll kdextx86.dll
Windows 2000 | kext.dll kdextx86.dll
Windows XP Windows .NET Server 2003 | kext.dll

Comments

These extensions each display physical memory, but their display formats and default length differ:

  • The !db extension displays hexadecimal bytes and their ASCII character equivalents. The default length is 128 bytes.
  • The !dc extension displays DWORD values and their ASCII character equivalents. The default length is 32 DWORDs (128 total bytes).
  • The !dd extension displays DWORD values. The default length is 32 DWORDs (128 total bytes).
  • The !dp extension displays ULONG_PTR values — these are either 32-bit or 64-bit words, depending on the instruction size. The default length is 128 total bytes.
  • The !du extension displays UNICODE characters. The default length is 16 characters (32 total bytes), or until a NULL character is encountered.
  • The !dw extension displays WORD values. The default length is 64 DWORDs (128 total bytes).

Here is an example where the caching attribute flag is needed:

kd> !dc e9000
physical memory read at e9000 failed
If you know the caching attributes used for the memory,
try specifying [c], [uc] or [wc], as in !dd [c] <params>.
WARNING: Incorrect use of these flags will cause unpredictable
processor corruption.  This may immediately (or at any time in
the future until reboot) result in a system hang, incorrect data
being displayed or other strange crashes and corruption.

kd> !dc [c] e9000
#   e9000 000ea002 000ea002 000ea002 000ea002 ................
#   e9010 000ea002 000ea002 000ea002 000ea002 ................

Additional Information

To write to physical memory, use the !e* extensions. For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


!dbgprint

Displays a string that was previously sent to the DbgPrint buffer.

Syntax

!dbgprint

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The kernel-mode routines DbgPrint, KdPrint, DbgPrintEx, and KdPrintEx send a formatted string to a buffer on the host computer. The string is displayed in the Debugger Command window unless such printing has been disabled.

Normally, messages sent to this buffer are displayed automatically in the Debugger Command window. However, this display can be disabled through the Global Flags (gflags.exe) Utility. To disable this display, run the Global Flags utility, select Kernel Mode (to disable printing until the next boot) or System Registry (to disable printing after the next boot), select Buffer DbgPrint output, and click Apply. Alternatively, you can start this utility from an MS-DOS Command prompt window by typing gflags /k +ddp to disable printing until the next boot, or gflags /r +ddp to disable printing after the next boot.

The !dbgprint extension causes the contents of this buffer to be displayed (regardless of whether automatic printing has been disabled). It will not show messages that have been filtered out by DbgPrintEx or KdPrintEx.

Additional Information

For information on DbgPrint, KdPrint, DbgPrintEx, and KdPrintEx, see the Windows DDK. For more information on controlling the DbgPrint buffer in Windows .NET Server 2003, see Using KDbgCtrl.


!dblink

Displays a linked list in the backward direction.

Syntax

Windows NT 4.0 Syntax

!dblink Address [Count]

Windows XP and Windows .NET Server 2003 Syntax

!dblink Address [Count] [Bias]

Parameters

Address
Specifies the address of a LIST_ENTRY structure. The display will begin with this node.
Count
Specifies the maximum number of list entries to display. If this is omitted, the default is 24 in Windows NT 4.0, and 32 in Windows 2000 and later versions of Windows.
Bias
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Specifies a mask of bits to ignore in each pointer. Each Blink address is ANDed with (NOT Bias) before following it to the next location. The default is zero (in other words, don't ignore any bits).

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The !dblink extension traverses the Blink fields of the LIST_ENTRY structure, and displays up to four ULONGs at each address. To go in the other direction, use !dflink.

The DL (Display Linked List) command is more versatile than !dblink and !dflink.


!dcs

The !dcs extension is obsolete. To display the PCI configuration space, use !pci 100 Bus Device Function.


!deadlock

Displays information about deadlocks collected by the Deadlock Detection option of Driver Verifier.

Syntax

!deadlock
!deadlock 1

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This extension will only provide useful information if Driver Verifier's Deadlock Detection option has detected a lock hierarchy violation and issued bug check 0xC4 (DRIVER_VERIFIER_DETECTED_VIOLATION).

Without any arguments, the !deadlock extension causes the basic lock hierarchy topology to be displayed. If the problem is not a simple cyclical deadlock, this command will describe the situation that has occurred.

The !deadlock 1 extension causes stack traces to be displayed. The stacks displayed will be the ones active at the time the locks were acquired.

Here is an example:

0:kd> !deadlock

Deadlock detected (2 resources in 2 threads):

Thread 0: A B
Thread 1: B A

Where:
Thread 0 = 8d3ba030
Thread 1 = 8d15c030
Lock A =   bba2af30 Type 'Spinlock'
Lock B =   dummy!GlobalLock Type 'Spinlock'

This tells you which threads and which locks are involved. However, it is intended to be a summary and may not be enough information to adequately debug the situation.

Use !deadlock 1 to print out the contents of the call stacks at the time that each lock participating in the deadlock was acquired. Since these are run-time stack traces, they will be more complete if a checked build is being used. On a free build they may be truncated after as little as one line.

0:kd> !deadlock 1

Deadlock detected (2 resources in 2 threads):

Thread 0 (8D14F750) took locks in the following order:

    Lock A -- b7906f30 (Spinlock)
    Stack:   dummy!DummyActivateVcComplete+0x63
             dummy!dummyOpenVcChannels+0x2E1
             dummy!DummyAllocateRecvBufferComplete+0x436
             dummy!DummyAllocateComplete+0x55
             NDIS!ndisMQueuedAllocateSharedHandler+0xC9
             NDIS!ndisWorkerThread+0xEE

    Lock B -- dummy!GlobalLock (Spinlock)
    Stack:   dummy!dummyQueueRecvBuffers+0x2D
             dummy!DummyActivateVcComplete+0x90
             dummy!dummyOpenVcChannels+0x2E1
             dummy!DummyAllocateRecvBufferComplete+0x436
             dummy!DummyAllocateComplete+0x55

Thread 1 (8D903030) took locks in the following order:

    Lock B -- dummy!GlobalLock (Spinlock)
    Stack:   dummy!dummyRxInterruptOnCompletion+0x25D
             dummy!DummyHandleInterrupt+0x32F
             NDIS!ndisMDpcX+0x3C
             ntkrnlpa!KiRetireDpcList+0x5D

    Lock A -- b7906f30 (Spinlock)
    Stack:   << Current stack >>

With this information, you have almost everything you need except the current stack:

0: kd> k
ChildEBP RetAddr
f78aae6c 80664c58 ntkrnlpa!DbgBreakPoint
f78aae74 8066523f ntkrnlpa!ViDeadlockReportIssue+0x2f
f78aae9c 806665df ntkrnlpa!ViDeadlockAnalyze+0x253
f78aaee8 8065d944 ntkrnlpa!VfDeadlockAcquireResource+0x20b
f78aaf08 bfd6df46 ntkrnlpa!VerifierKeAcquireSpinLockAtDpcLevel+0x44
f78aafa4 b1bf2d2d dummy!dummyRxInterruptOnCompletion+0x2b5
f78aafc4 bfde9d8c dummy!DummyHandleInterrupt+0x32f
f78aafd8 804b393b NDIS!ndisMDpcX+0x3c
f78aaff4 804b922b ntkrnlpa!KiRetireDpcList+0x5d

From this you can see which locks were involved, and where they were acquired. This should be enough information for you to debug the deadlock. If the source code is available, you can use the debugger to see exactly where the problem occurred:

0: kd> .lines
Line number information will be loaded

0: kd> u dummy!DummyActivateVcComplete+0x63 l1
dummy!DummyActivateVcComplete+63 [d:\nt\drivers\dummy\vc.c @ 2711]:
b1bfe6c9 837d0c00         cmp     dword ptr [ebp+0xc],0x0

0: kd> u dummy!dummyQueueRecvBuffers+0x2D l1
dummy!dummyQueueRecvBuffers+2d [d:\nt\drivers\dummy\receive.c @ 2894]:
b1bf4e39 807d0c01         cmp     byte ptr [ebp+0xc],0x1

0: kd> u dummy!dummyRxInterruptOnCompletion+0x25D l1
dummy!dummyRxInterruptOnCompletion+25d [d:\nt\drivers\dummy\receive.c @ 1424]:
b1bf5d05 85f6             test    esi,esi

0: kd> u dummy!dummyRxInterruptOnCompletion+0x2b5 l1
dummy!dummyRxInterruptOnCompletion+2b5 [d:\nt\drivers\dummy\receive.c @ 1441]:
b1bf5d5d 8b4648           mov     eax,[esi+0x48]

Now you know the name of the source file and the line number where the acquisition took place. In this case, the source files will show that the threads behaved as follows:

  • Thread 1: DummyActivateVcComplete took the dummy miniport lock. It then called dummyQueueRecvBuffers, which took the dummy global lock.
  • Thread 2: dummyRxInterruptOnCompletion took the global lock. Then, a few lines later, it took the miniport lock.

At this point, the deadlock becomes entirely clear.

Additional Information

For information on Driver Verifier, see the Windows DDK.


!defwrites

Displays the values of the kernel variables used by the cache manager.

Syntax

!defwrites

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

When the number of deferred writes ("dirty pages") becomes too large, page writing will be throttled. This extension allows you to see whether your system has reached this point.

Here is an example:

kd> !defwrites
*** Cache Write Throttle Analysis ***

        CcTotalDirtyPages:                   0 (       0 Kb)
        CcDirtyPageThreshold:             1538 (    6152 Kb)
        MmAvailablePages:                 2598 (   10392 Kb)
        MmThrottleTop:                     250 (    1000 Kb)
        MmThrottleBottom:                   30 (     120 Kb)
        MmModifiedPageListHead.Total:      699 (    2796 Kb)

Write throttles not engaged

In this case, there are no dirty pages. If CcTotalDirtyPages reaches 1538 (the value of CcDirtyPageThreshold), writing will be delayed until the number of dirty pages is reduced.

Additional Information

For information on write throttling, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!devext

Displays bus-specific device extension information for devices on a variety of buses.

Syntax

!devext Address TypeCode

Parameters

Address
Specifies the hexadecimal address of device extension to be displayed.
TypeCode
Specifies the type of object which owns the device extension that is to be displayed. Type codes are not case-sensitive. Valid type codes are:
TypeCode | Object
PCI | PCI device extension
ISAPNP | ISA PnP device extension
PCMCIA | PCMCIA device extension
HID | HID device extension
USBD | (Windows 2000 only) USB bus driver extension
UHCD | (Windows 2000 only) UHCD host controller extension
OpenHCI | (Windows 2000 only) Open HCI host controller extension
USBHUB | (Windows 2000 only) USB hub extension
MF | (Windows 2000 only) MF device extension

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The !usbhub, !hidfdo, and !hidpdo extensions are obsolete; their functionality has been integrated into !devext.

Additional Information

See Plug and Play Debugging for applications of this extension command. For more information on device extensions, see the Windows DDK.


!devnode

Displays information about a node in the device tree.

Syntax

!devnode Address [Flags] [Service]
!devnode 1
!devnode 2

Parameters

Address
Specifies the hexadecimal address of the device extension whose node is to be displayed. If this is zero, the root of the main device tree is displayed.
Flags
Specifies the level of output to be displayed. This can be any combination of the following bits:
Bit 0 (0x1)
Causes the display to include all children of the device node.
Bit 1 (0x2)
Causes the display to include resources used (CM_RESOURCE_LIST). These include the boot configuration reported by IRP_MN_QUERY_RESOURCES, as well as the resources allocated to the device in the AllocatedResources parameter of IRP_MN_START_DEVICE.
Bit 2 (0x4)
Causes the display to include resources required (IO_RESOURCE_REQUIREMENTS_LIST) as reported by IRP_MN_FILTER_RESOURCE_REQUIREMENTS.
Bit 3 (0x8)
Causes the display to include a list of translated resources as allocated to the device in the AllocatedResourcesTranslated parameter of IRP_MN_START_DEVICE.
Bit 4 (0x10)
Specifies that only device nodes that aren't started should be displayed.
Bit 5 (0x20)
Specifies that only device nodes with problems should be displayed. (These are nodes which contain the flag bits DNF_HAS_PROBLEM or DNF_HAS_PRIVATE_PROBLEM.)
Service
Specifies the name of a service. If this is included, only those device nodes driven by this service will be displayed. (If Flags includes bit 0x1, device nodes driven by this service and all of their children will be displayed.)

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The !devnode 1 command lists all pending removals of device objects.

The !devnode 2 command lists all pending ejects of device objects.

You can use !devnode 0 1 to see the entire device tree.

Additional Information

See Plug and Play Debugging for applications of this extension command. For information on device trees, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!devobj

Displays detailed information about a DEVICE_OBJECT structure.

Syntax

!devobj DeviceObject

Parameters

DeviceObject
Specifies the device object. In Windows NT 4.0, this must be the hexadecimal address of the DEVICE_OBJECT structure. In Windows 2000, Windows XP, and Windows .NET Server 2003, this can be the hexadecimal address of this structure or the name of the device.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

If DeviceObject specifies the name of the device but supplies no prefix, the prefix \Device\ is assumed. Note that this command will check to see if DeviceObject is a valid address or device name before using the expression evaluator.

The information displayed includes the device name of the object, information about the device's current IRP, and a list of addresses of any pending IRPs in the device's queue. It also includes information about device objects layered on top of this object (listed as "AttachedDevice") and those layered under this object (listed as "AttachedTo").

The address of a device object can be obtained using the !drvobj or !devnode extensions.

Here is one example:

kd> !devnode
Dumping IopRootDeviceNode (= 0x80e203b8)
DevNode 0x80e203b8 for PDO 0x80e204f8
  Parent 0000000000   Sibling 0000000000   Child 0x80e56dc8
  InstancePath is "HTREE\ROOT\0"
  State = DeviceNodeStarted (0x308)
  Previous State = DeviceNodeEnumerateCompletion (0x30d)
  StateHistory[04] = DeviceNodeEnumerateCompletion (0x30d)
  StateHistory[03] = DeviceNodeStarted (0x308)
  StateHistory[02] = DeviceNodeEnumerateCompletion (0x30d)
  StateHistory[01] = DeviceNodeStarted (0x308)
  StateHistory[00] = DeviceNodeUninitialized (0x301)
  StateHistory[19] = Unknown State (0x0)
  .....
  StateHistory[05] = Unknown State (0x0)
  Flags (0x00000131)  DNF_MADEUP, DNF_ENUMERATED,
                      DNF_IDS_QUERIED, DNF_NO_RESOURCE_REQUIRED
  DisableableDepends = 11 (from children)

kd> !devobj 80e204f8
Device object (80e204f8) is for:
  \Driver\PnpManager DriverObject 80e20610
Current Irp 00000000 RefCount 0 Type 00000004 Flags 00001000
DevExt 80e205b0 DevObjExt 80e205b8 DevNode 80e203b8
ExtensionFlags (0000000000)
Device queue is not busy.

Additional Information

See Plug and Play Debugging for examples and applications of this extension command. For information on device objects, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!devstack

Displays a formatted view of the device stack associated with a device object.

Syntax

!devstack DeviceObject

Parameters

DeviceObject
Specifies the device object. This can be the hexadecimal address of the DEVICE_OBJECT structure or the name of the device.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

If DeviceObject specifies the name of the device but supplies no prefix, the prefix \Device\ is assumed. Note that this command will check to see if DeviceObject is a valid address or device name before using the expression evaluator.

Additional Information

For information on device stacks, see the Windows DDK.


!dflink

Displays a linked list in the forward direction.

Syntax

!dflink Address [Count] [Bias]

Parameters

Address
Specifies the address of a LIST_ENTRY structure. The display will begin with this node.
Count
Specifies the maximum number of list entries to display. If this is omitted, the default is 32.
Bias
Specifies a mask of bits to ignore in each pointer. Each Flink address is ANDed with (NOT Bias) before following it to the next location. The default is zero (in other words, don't ignore any bits).

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The !dflink extension traverses the Flink fields of the LIST_ENTRY structure, and displays up to four ULONGs at each address. To go in the other direction, use !dblink.

The DL (Display Linked List) command is more versatile than !dblink and !dflink.


!diskspace

Displays the amount of free space on a hard disk of the target computer.

Syntax

!diskspace Drive:

Parameters

Drive
Specifies the drive letter of the disk. The colon (:) after Drive is optional.

DLL

Windows NT 4.0 | kext.dll
Windows 2000 | kext.dll
Windows XP Windows .NET Server 2003 | kext.dll

Comments

Here is an example:

kd> !diskspace c:
Checking Free Space for c: ..........
   Cluster Size 0 KB
 Total Clusters 4192901 KB
  Free Clusters 1350795 KB
    Total Space 1 GB (2096450 KB)
     Free Space 659.567871 MB (675397 KB)

kd> !diskspace f:
Checking Free Space for f:
f: is a CDROM drive.  This function is not supported!


!dma

Displays information about the Direct Memory Access (DMA) subsystem, and the DMA Verifier option of Driver Verifier.

Syntax

!dma
!dma Adapter [Flags]

Parameters

Adapter
Specifies the hexadecimal address of the DMA adapter to be displayed. If this is zero, all DMA adapters will be displayed.
Flags
Specifies the information to include in the display. This can be any combination of the following bits. The default is 0x1.
Bit 0 (0x1)
Causes the display to include generic adapter information.
Bit 1 (0x2)
Causes the display to include map register information. (Only when DMA Verification is active.)
Bit 2 (0x4)
Causes the display to include common buffer information. (Only when DMA Verification is active.)
Bit 3 (0x8)
Causes the display to include scatter-gather list information. (Only when DMA Verification is active.)
Bit 4 (0x10)
Causes the display to include the device description for the hardware device. (Only when DMA Verification is active.)
Bit 5 (0x20)
Causes the display to include Wait context block information.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Invalid arguments (for example, !dma 1) generate a brief help text.

When the !dma extension is used with no parameters, it displays a concise list of all DMA adapters and their addresses. This can be used to obtain the address of an adapter for use in the longer versions of this command.

Here is an example of how this extension can be used when the Driver Verifier's DMA Verification option is active:

0:kd> !dma

Dumping all DMA adapters...

Adapter: 82faebd0     Owner: SCSIPORT!ScsiPortGetUncachedExtension
Adapter: 82f88930     Owner: SCSIPORT!ScsiPortGetUncachedExtension
Adapter: 82f06cd0     Owner: NDIS!NdisMAllocateMapRegisters
Master adapter: 80076800

From this output you can see that there are three DMA adapters in the system. SCSIPORT owns two and NDIS owns the third. To examine the NDIS adapter in detail, use the !dma extension with its address:

0:kd> !dma  82f06cd0
Adapter: 82f06cd0     Owner: NDIS!NdisMAllocateMapRegisters (0x9fe24351)
   MasterAdapter:       00000000
   Adapter base Va      00000000
   Map register base:   00000000
   WCB:                 82f2b604
   Map registers: 00000000 mapped, 00000000 allocated, 00000002 max

   Dma verifier additional information:
   DeviceObject: 82f98690
   Map registers:        00000840 allocated, 00000000 freed
   Scatter-gather lists: 00000000 allocated, 00000000 freed
   Common buffers:       00000004 allocated, 00000000 freed
   Adapter channels:     00000420 allocated, 00000420 freed
   Bytes mapped since last flush: 000000f2

The first block of data is specific information a HAL developer can use to debug the problem. For your purposes, the data below "Dma verifier additional information" is what is interesting. Here you see that NDIS has allocated 0x840 map registers. This is a huge number, especially since NDIS had indicated that it planned to use a maximum of two map registers. This adapter apparently does not use scatter-gather lists, and has put away all of its adapter channels. Look at the map registers in more detail:

0:kd> !dma  82f06cd0 2
Adapter: 82f06cd0     Owner: NDIS!NdisMAllocateMapRegisters
...

  Map register file 82f06c58 (0/2 mapped)
     Double buffer mdl: 82f2c188
     Map registers:
        82f06c80: Not mapped
        82f06c8c: Not mapped

  Map register file 82f06228 (1/2 mapped)
     Double buffer mdl: 82f1b678
     Map registers:
        82f06250: 00bc bytes mapped to f83c003c
        82f0625c: Not mapped

  Map register file 82fa5ad8 (1/2 mapped)
     Double buffer mdl: 82f1b048
     Map registers:
        82fa5b00: 0036 bytes mapped to 82d17102
        82fa5b0c: Not mapped
...

Here you see that certain map registers have been mapped. Each map register file is an allocation of map registers by the driver; in other words, it represents a single call to AllocateAdapterChannel. NDIS collects a large number of these map register files, while some drivers create them one at a time and dispose of them when they are finished.

The map register files are also the addresses that are returned to the device under the name "MapRegisterBase". Note that DMA verifier only hooks the first 64 map registers for each driver. The rest are ignored for reasons of space (each map register represents three physical pages).

In this example, two map register files are in use. This means that the driver has mapped a buffer so that it is visible to the hardware. In the first case, 0xBC bytes are mapped to the system virtual address 0xF83C003C.

An examination of the common buffers reveals:

0:kd> !dma  82f06cd0 4
Adapter: 82f06cd0     Owner: NDIS!NdisMAllocateMapRegisters
...
   Common buffer allocated by NDIS!NdisMAllocateSharedMemory:
      Length:           1000
      Virtual address:  82e77000
      Physical address: 2a77000

   Common buffer allocated by NDIS!NdisMAllocateSharedMemory:
      Length:           12010
      Virtual address:  82e817f8
      Physical address: 2a817f8

   Common buffer allocated by NDIS!NdisMAllocateSharedMemory:
      Length:           4300
      Virtual address:  82e95680
      Physical address: 2a95680

   Common buffer allocated by NDIS!NdisMAllocateSharedMemory:
      Length:           4800
      Virtual address:  82e9d400
      Physical address: 2a9d400

This is pretty straightforward: there are four common buffers of varying lengths. The physical and virtual addresses are all given.

Additional Information

For information on Driver Verifier, see the Windows DDK. For information on DMA, see the Windows DDK or Inside Microsoft Windows NT by David Solomon.


!drivers

Displays a list of all drivers loaded on the target computer, along with summary information about their memory use.

Syntax

!drivers [Flags]

Parameters

Flags
Can be any combination of the following values. (The default is 0x0.)
Bit 0 (0x1)
Causes the display to include information about resident and standby memory.
Bit 1 (0x2)
In Windows NT 4.0, this causes the display to be a much longer and more detailed list of the driver image. Information about headers is included. If bit 2 (0x4) is set, this will also include section information.

In Windows 2000, if this bit is set and bit 2 (0x4) is not set, the display will include information about resident, standby, and locked memory, as well as the loader entry address. If bit 2 is set, this functions as in Windows NT 4.0.

In Windows XP and Windows .NET Server 2003, this causes the display to include information about resident, standby, and locked memory, as well as the loader entry address.

Bit 2 (0x4)
(Windows NT 4.0 and Windows 2000 only) Causes the display to be a much longer and more detailed list of the driver image. Information about each section is included. If bit 1 (0x2) is set, this will also include header information.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

An explanation of this command's display is given in the following table:

Column | Meaning
Base | The starting address of the device driver code, in hexadecimal. When the memory address used by the code that causes a stop falls between the base address for a driver and the base address for the next driver in the list, that driver is frequently the cause of the fault. For instance, the base for Ncrc810.sys is 0x80654000. Any address between that and 0x8065a000 belongs to this driver.
Code Size | The size, in kilobytes, of the driver code, in both hexadecimal and decimal.
Data Size | The amount of space, in kilobytes, allocated to the driver for data, in both hexadecimal and decimal.
Locked | (Only when Flag 0x2 is used) The amount of memory locked by the driver.
Resident | (Only when Flag 0x1 or 0x2 is used) The amount of the driver's memory which actually resides in physical memory.
Standby | (Only when Flag 0x1 or 0x2 is used) The amount of the driver's memory which is on standby.
Loader Entry | (Only when Flag 0x2 is used) The loader entry address.
Driver Name | The driver filename.
Creation Time | The link date of the driver. Do not confuse this with the file date of the driver, which can be set by external tools. The link date is set by the compiler when a driver or executable file is compiled. It should be close to the file date, but it is not always the same.

The following is a truncated example of this command:

kd> !drivers
Loaded System Driver Summary
Base     Code Size      Data Size      Driver Name  Creation Time
80080000 f76c0 (989 kb) 1f100 (124 kb) ntoskrnl.exe Fri May 26 15:13:00
80400000 d980  ( 54 kb) 4040  ( 16 kb) hal.dll      Tue May 16 16:50:34
80654000 3f00  ( 15 kb) 1060   ( 4 kb) ncrc810.sys  Fri May 05 20:07:04
8065a000 a460  ( 41 kb) 1e80   ( 7 kb) SCSIPORT.SYS Fri May 05 20:08:05

You can also get information about a driver's image by using the LMV or .reload /l commands.

Additional Information

See Plug and Play Debugging for applications of this extension command. For information on drivers and their memory use, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!drvobj

Displays detailed information about a DRIVER_OBJECT.

Syntax

Windows NT 4.0 Syntax

!drvobj DriverObject

Windows 2000, Windows XP, and Windows .NET Server 2003 Syntax

!drvobj DriverObject [Flags]

Parameters

DriverObject
Specifies the device object. In Windows NT 4.0, this must be the hexadecimal address of the DRIVER_OBJECT structure. In Windows 2000, Windows XP, and Windows .NET Server 2003, this can be the hexadecimal address of the DRIVER_OBJECT structure or the name of the device.
Flags
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Can be any combination of the following bits. (The default is 0x01.)
Bit 0 (0x1)
Causes the display to include device objects owned by the driver.
Bit 1 (0x2)
Causes the display to include entry points for the driver's dispatch routines.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

If DriverObject specifies the name of the device but supplies no prefix, the prefix \Driver\ is assumed. Note that this command will check to see if DriverObject is a valid address or device name before using the expression evaluator.

If DriverObject is an address, it must be the address of the DRIVER_OBJECT structure. This can be obtained by examining the arguments passed to the driver's DriverEntry routine.

This extension command will display a list of all device objects created by a specified driver. It wil also display all fast I/O routines registered with this driver object.

The following is an example for the Symbios Logic 810 SCSI miniport driver:

kd> bp DriverEntry          //  breakpoint at DriverEntry

kd> g
symc810!DriverEntry+0x40:
80006a20: b07e0050 stl     t2,50(sp)

kd> r a0        //address of DevObj (the first parameter)
a0=809d5550

kd> !drvobj 809d5550      //  display the driver object
Driver object is for:
\Driver\symc810
Device Object list:
809d50d0

You can also use !devobj 809d50d0 to get information about the device object.

Additional Information

See Plug and Play Debugging for examples and applications of this extension command. For information on driver objects, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!eb, !ed

Writes a sequence of values into a specified physical address.

The !e* extension commands should not be confused with the E* (Enter Values) command.

Syntax

!eb [Flag] PhysicalAddress Data [ ... ]
!ed [Flag] PhysicalAddress Data [ ... ]

Parameters

Flag
Can be any one of the following values. The Flag value must be surrounded by square brackets:
[c]
Causes this extension to write to cached memory.
[uc]
Causes this extension to write to uncached memory.
[wc]
Causes this extension to write to write-combined memory.
PhysicalAddress
Specifies the first physical address on the target computer to which the data will be written, in hexadecimal.
Data
Specifies one or more values to be written sequentially into physical memory. These values must be entered in hexadecimal format. For the !eb extension, each value must be one byte (two hexadecimal digits). For the !ed extension, each value must be one DWORD (eight hexadecimal digits). You can include any number of Data values on one line — separate multiple values by commas or by spaces.

DLL

Windows NT 4.0 | kext.dll kdextx86.dll
Windows 2000 | kext.dll kdextx86.dll
Windows XP Windows .NET Server 2003 | kext.dll

Additional Information

To read physical memory, use the !d* extensions. For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


!ecb, !ecd, !ecw

Writes to the the PCI configuration space.

Syntax

!ec Bus.Device.Function Offset Data

Parameters

Bus
Specifies the bus. Bus can range from 0 to 0xFF.
Device
Specifies the slot device number for the device.
Function
Specifies the slot function number for the device.
Offset
Specifies the address at which to write.
Data
Specifies the value to be written. For the !ecb extension, Data must be one byte (two hexadecimal digits). For the !ecw extension, Data must be one WORD (four hexadecimal digits). For the !ecd extension, Data must be one DWORD (eight hexadecimal digits).

DLL

Windows NT 4.0 | kext.dll
Windows 2000 | kext.dll
Windows XP Windows .NET Server 2003 | kext.dll

These extension commands can only be used with an x86 target computer.

Comments

You cannot use these extension commands to write a sequence of Data values. This can only be done by repeated use of this extension.

To display the PCI configuration space, use !pci 100 Bus Device Function.

Additional Information

See Plug and Play Debugging for applications of this extension command, and some additional examples. For information on PCI buses, see the Windows DDK.


!ecs

The !ecs extension is obsolete. To edit the PCI configuration space, use !ecb, !ecd, or !ecw.


!errlog

Displays the contents of any pending error log entries.

Syntax

!errlog

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This command displays information about any pending events in the I/O system's error log. These are events queued by calls to the IoWriteErrorLogEntry function, to be written to the system's event log for subsequent viewing by the Event Viewer.

Only entries that were queued by IoWriteErrorLogEntry, but have not been committed to the error log, will be displayed.

This command can be used as a diagnostic aid after a system crash because it reveals pending error information that was unable to be committed to the error log before the system halted.

Additional Information

For information on IoWriteErrorLogEntry, see the Windows DDK.


!exca

Displays CardBus Exchangable Card Architecture (ExCA) registers.

Syntax

!exca BasePort.SocketNumber

Parameters

BasePort
Specifies the base port of the CardBus.
SocketNumber
Specifies the socket number of the ExCA register on the CardBus.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kext.dll kdextx86.dll
Windows XP Windows .NET Server 2003 | kext.dll

The !exca extension is only available for an x86 target computer.

Additional Information

The !cbreg extension can be used to display CardBus Socket registers and CardBus ExCA registers by address.


!exqueue

Displays a list of items currently queued in the ExWorkerQueue work queues.

Syntax

!exqueue [Flags]

Parameters

Flags
Can be any combination of the following values. (The default is 0x0.)
Bit 0 (0x1)
Causes the display to include time and priority statistics.
Bit 1 (0x2)
Causes the display to include a list of threads and events associated with the work queue, and their wait states.
Bit 2 (0x4)
Causes the display to include a list of threads associated with the work queue. If this is included without Bit 1 (0x2), each thread will be displayed on a single line. If this is included along with Bit 1, each thread will be displayed with a stack trace.
Bit 4 (0x10)
Specifies that the display should include only the critical work queue.
Bit 5 (0x20)
Specifies that the display should include only the delayed work queue.
Bit 6 (0x40)
Specifies that the display should include only the hypercritical work queue.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

If Flags does not includes bits 4, 5, or 6, the display will include the critical work queue, the delayed work queue, and the hypercritical work queue.

Here is an example:

kd> !exqueue
Dumping ExWorkerQueue: 8046A5C0

**** Critical WorkQueue( current = 0 maximum = 1 )
THREAD fe502940  Cid 8.c  Teb: 00000000  Win32Thread: 00000000 WAIT
THREAD fe5026c0  Cid 8.10  Teb: 00000000  Win32Thread: 00000000 WAIT
THREAD fe502440  Cid 8.14  Teb: 00000000  Win32Thread: 00000000 WAIT
THREAD fe5021c0  Cid 8.18  Teb: 00000000  Win32Thread: 00000000 WAIT
THREAD fe501020  Cid 8.1c  Teb: 00000000  Win32Thread: 00000000 WAIT

**** Delayed WorkQueue( current = 0 maximum = 1 )
THREAD fe501da0  Cid 8.20  Teb: 00000000  Win32Thread: 00000000 WAIT
THREAD fe501b20  Cid 8.24  Teb: 00000000  Win32Thread: 00000000 WAIT
THREAD fe5018a0  Cid 8.28  Teb: 00000000  Win32Thread: 00000000 WAIT

**** HyperCritical WorkQueue( current = 0 maximum = 1 )
THREAD fe501620  Cid 8.2c  Teb: 00000000  Win32Thread: 00000000 WAIT

Additional Information

For information on worker threads, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!filecache

Displays information regarding the system file cache memory and PTE use.

Syntax

!filecache

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Each line of this extension's output represents a virtual address control block (VACB). When named files are mapped into the VACB, the names of these files are displayed. If "no name for file" is specified, this means that this VACB is being used to cache metadata.

Here is an example from a Windows 2000 system:

kd> !filecache
***** Dump file cache******
File Cache Information
  Current size 7088 kb
  Peak size    11376 kb
 loading file cache database...
  File cache has 129 valid pages
Usage Summary in KiloBytes (Kb):
Control Valid Standby Dirty Shared Locked PageTables  name
80994c08   248      0     0     0     0     0    No Name for File
80995c88   528      0     0     0     0     0    No Name for File
80992a28   120      0     0     0     0     0    No Name for File
80993d28    32      0     0     0     0     0    No Name for File
8098c1e8     8      0     0     0     0     0    mapped_file( SysEvent.Evt )
8091a908     8      0     0     0     0     0    No Name for File
8091d708    16      0     0     0     0     0    No Name for File
80992f08     8      0     0     0     0     0    No Name for File
8098ca48     8      0     0     0     0     0    No Name for File
80949ea8     8      0     0     0     0     0    No Name for File
80992828    16      0     0     0     0     0    No Name for File
8155c688     8      0     0     0     0     0    mapped_file( cmd.exe )

Here is an example from a Windows XP system:

kd> !filecache
***** Dump file cache******
File Cache Information
  Current size 2364 kb
  Peak size    11704 kb
  Loading file cache database (99% of 131072 PTEs)
  File cache PTEs loaded, loading PFNs...
  File cache has 22 valid pages
  File cache PFN data extracted
  Building kernel map
  Finished building kernel map
Scanning PFN database - (95% complete)

  Usage Summary (in Kb):
Control Valid Standby Dirty Shared Locked PageTables  name
82539708     0      4     0     0     0     0  mapped_file( fastprox.dll )
825cf218     4      0     0     4     0     0  mapped_file( ntmarta.dll )
82775d08     0      4     0     0     0     0  mapped_file( urlmon.dll )
827d8c98     0      4     0     0     0     0  mapped_file( kernel32.dll )
82651c98     4      0     0     0     0     0  mapped_file( crypt32.dll )
8264f568     4      0     0     4     0     0  mapped_file( netapi32.dll )
8250ad08     0      4     0     0     0     0  mapped_file( gdiplus.dll )
826da9a8     4      0     0     4     0     0  mapped_file( oleaut32.dll )
82760d18     4      0     0     4     0     0  mapped_file( ole32.dll )
827def98     0      4     0     0     0     0  mapped_file( $LogFile )
825894a8     4      0     0     0     0     0  mapped_file( clbcatq.dll )
827dc5a8     0      4     0     0     0     0  mapped_file( $Directory )
--------     4      0     0 ----- -----     0  pagefile section (3b)
--------     8      0     0 ----- -----     0  pagefile section (1f4f)
--------     0      4     0 ----- -----     0  pagefile section (402)
--------     4      0     0 ----- -----     4  process ( webclnt.exe )
--------     0      0     8 ----- -----     0  pagefile section (3d1f)
--------     8      0     0 ----- -----     8  process ( services.exe )
--------     4      0     0 ----- -----     0  pagefile section (1e)

Additional Information

For information on file system drivers, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!filelock

Displays a file lock structure.

Syntax

Windows NT 4.0 and Windows 2000 Syntax

!filelock FileLockAddress

Windows XP and Windows .NET Server 2003 Syntax

!filelock FileLockAddress
!filelock ObjectAddress

Parameters

FileLockAddress
Specifies the hexadecimal address of the file lock structure.
ObjectAddress
(Windows XP and Windows .NET Server 2003 only) Specifies the hexadecimal address of a file object that owns the file lock.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

For information on file objects, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!frag

Displays fragmentation information about pool memory on the target system.

Syntax

!frag [Flags]

Parameters

Flags
Specifies the level of output. Can be any combination of the following bits. The default is zero:
Bit 0 (0x1)
Causes the display to include the number and size of the fragments for each index.
Bit 1 (0x2)
Causes the display to include allocation information.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Extremely fragmented pools can decrease performance.

Here is an example of this extension's output:

kd> !frag 1
  NonPaged Pool Fragmentation
index:  0 number of fragments:     4  bytes:    128
index:  1 number of fragments:     0  bytes:      0
index:  2 number of fragments:     2  bytes:    192
index:  3 number of fragments:     0  bytes:      0
…
index: 20 number of fragments:     0  bytes:      0
index: 21 number of fragments:     0  bytes:      0
index: 22 number of fragments:     1  bytes:   7232
index: 23 number of fragments:     0  bytes:      0
index: 24 number of fragments:     0  bytes:      0
 Number of fragments:      11 consuming    9344 bytes
 NonPagedPool Usage:  1105920 bytes

kd> !frag 2
  NonPaged Pool Fragmentation
818718a0 size:   20 previous size:   a0  Cc
81870720 size:   20 previous size:   60  Cc
80d1ae80 size:   20 previous size:   a0  Cc
818703c0 size:   20 previous size:   60  Cc
80962600 size:   60 previous size:   a0  ScsD
8098c180 size:   60 previous size:  100  ScsD
81937680 size:  160 previous size:   40  Lric
81870e00 size:  120 previous size:   20  None
81937d80 size:  260 previous size:   20  Thre
81936000 size:  220 previous size:    0  Proc
81610260 size: 1c40 previous size:  260  à
Number of fragments:      11 consuming    9344 bytes
NonPagedPool Usage:  1105920 bytes

Additional Information

For information on memory management, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!fwver

Displays the IA-64 firmware version.

Syntax

!fwver

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll

This extension command can only be used with an IA-64 target computer.

Additional Information

For more information, consult an Intel architecture manual.


!gentable

Displays an RTL_GENERIC_TABLE.

Syntax

Windows 2000 Syntax

!gentable Address

Windows XP and Windows .NET Server 2003 Syntax

!gentable Address [Flag]

Parameters

Address
Specifies the address of the RTL_GENERIC_TABLE.
Flag
(Windows XP, and Windows .NET Server 2003 only) Specifies the table source. If Flag is one, the AVL table is used. If Flag is zero or omitted, the non-AVL table is used. In Windows 2000, the non-AVL table is always used.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll


!hidppd

Displays the contents of the HIDP_PREPARSED_DATA structure.

Syntax

!hidppd Address

Parameters

Address
Specifies the hexadecimal address of the HIDP_PREPARSED_DATA structure.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

For information on human input devices (HID), see the Windows DDK.


!ib, !id, !iw

The !ib, !id, and !iw extension commands are obsolete. Use the IB, ID, and IW (Input from Port) commands instead.


!ioresdes

Displays the IO_RESOURCE_DESCRIPTOR structure at the specified address.

Syntax

!ioresdes Address

Parameters

Address
Specifies the hexadecimal address of the IO_RESOURCE_DESCRIPTOR structure.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

See Plug and Play Debugging for applications of this extension command. For information on the IO_RESOURCE_DESCRIPTOR structure, see the Windows DDK.


!ioreslist

Displays an IO_RESOURCE_REQUIREMENTS_LIST structure.

Syntax

!ioreslist Address

Parameters

Address
Specifies the hexadecimal address of the IO_RESOURCE_REQUIREMENTS_LIST structure.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Here is an example:

kd> !ioreslist 0xe122b768

IoResList at 0xe122b768 : Interface 0x5  Bus 0  Slot 0xe
  Alternative 0 (Version 1.1)
    Preferred Descriptor 0 - Port (0x1) Device Exclusive (0x1)
      Flags (0x01) - PORT_IO
      0x000100 byte range with alignment 0x000100
      1000 - 0x10ff
    Alternative Descriptor 1 - Port (0x1) Device Exclusive (0x1)
      Flags (0x01) - PORT_IO
      0x000100 byte range with alignment 0x000100
      0 - 0xffffffff
    Descriptor 2 - DevicePrivate (0x81) Device Exclusive (0x1)
      Flags (0000) -
      Data:              : 0x1 0x0 0x0
    Preferred Descriptor 3 - Memory (0x3) Device Exclusive (0x1)
      Flags (0000) - READ_WRITE
      0x001000 byte range with alignment 0x001000
      40080000 - 0x40080fff
    Alternative Descriptor 4 - Memory (0x3) Device Exclusive (0x1)
      Flags (0000) - READ_WRITE
      0x001000 byte range with alignment 0x001000
      0 - 0xffffffff
    Descriptor 5 - DevicePrivate (0x81) Device Exclusive (0x1)
      Flags (0000) -
      Data:              : 0x1 0x1 0x0
    Descriptor 6 - Interrupt (0x2) Shared (0x3)
      Flags (0000) - LEVEL_SENSITIVE
      0xb - 0xb

The IO_RESOURCE_REQUIREMENTS_LIST contains information about:

  • Resource types

    There are four types of resources: I/O, Memory, IRQ, DMA.

  • Descriptors

    Each preferred setting has a "Preferred" and a number of "Alternative" descriptors.

This resource list contains the following requests:

  • I/O Ranges

    Prefers a range of 0x1000 - 0x10FF inclusive, but can use any 0x100 range between 0 and 0xFFFFFFFF, provided it is 0x100-aligned. (For example, 0x1100-0x11FF is acceptable.)

  • Memory

    Prefers a range of 0x40080000 - 0x40080FFF, but can use any range that is of size 0x1000, is 0x1000-aligned, and is located between 0 and 0xFFFFFFFF.

  • IRQ

    Must use IRQ 0xB.

Interrupts and DMA channels are represented as ranges with the same beginning and end.

Additional Information

See Plug and Play Debugging for applications of this extension command. For information on the IO_RESOURCE_REQUIREMENTS_LIST structure, see the Windows DDK.


!irp

Displays information about an I/O request packet (IRP).

Syntax

Windows NT 4.0 Syntax

!irp [Address]

Windows 2000, Windows XP, and Windows .NET Server 2003 Syntax

!irp [Address [Detail]]

Parameters

Address
Specifies the hexadecimal address of the IRP. If this is omitted, the last IRP displayed is used. If the target computer is running a checked build, and Address is zero, all active IRPs are displayed.
Detail
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Specifies the level of detail. Possible values are:
0
Causes the display to include basic stack information. (This is the default.)
1
Causes the display to include full field information.
2
(Checked build only) Causes the display to include tracking information.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Regardless of what Detail is requested, the output of this extension always includes the status of the IRP, the address of its memory descriptor list (MDL), its owning thread, and stack information of all its I/O stacks.

Here is an example:

kd> !irp 80993b28
Irp is active with 3 stacks 1 is current
 Mdl = 809d45c8 Associated Irp = 80988e68 Thread 80987da0:  Irp stack trace.
 cmd flg cl Device   File     Completion-Context
>  f   0 e1 809d50d0 00000000 8005b180-809904c8 Success Error Cancel pending
             \Driver\symc810    CLASS2!ScsiClassIoComplete
                        Args: 809904c8 00000000 00000000 00000000
   3   0 e1 809c74d0 00000000 8065ca50-faa09b10 Success Error Cancel pending
             \Driver\Disk       Ntfs!NtfsMultiSyncCompletionRoutine
                        Args: 00001000 00000000 2f695000 00000004
   3   0  0 00000000 00000000 00000000-00000000
                        Args: 00001000 00000000 00065c00 00000000

Additional Information

See Plug and Play Debugging for applications of this extension command. For information on IRPs, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!irpfind

Displays information about all I/O request packets (IRP) currently allocated in the target system, or about those IRPs matching the specified search criteria.

Syntax

Windows NT 4.0 Syntax

!irpfind [PoolType]

Windows 2000 Syntax

!irpfind [PoolType [RestartAddress [Criteria Data]]]

Windows XP and Windows .NET Server 2003 Syntax

!irpfind [-v] [PoolType [RestartAddress [Criteria Data]]]

Parameters

-v
(Windows XP and Windows .NET Server 2003 only) Displays verbose information.
PoolType
Specifies the type of pool to be searched. The following values are permitted:
0
Specifies nonpaged memory pool. (This is the default.)
1
Specifies paged memory pool.
2
Specifies the special pool.
4
(Windows XP and Windows .NET Server 2003 only) Specifies the session pool.
4, 5, 6
(Windows NT 4.0 only) Same as 0, 1, 2, but displays verbose information.
RestartAddress
Specifies the hexadecimal address at which to begin the search. This is useful if the previous search was terminated prematurely. The default is zero.
Criteria
Specifies the criteria for the search. Only those IRPs that satisfy the given match will be displayed.
Criteria | Match
arg | Finds all IRPs with a stack location where one of the arguments equals Data.
device | Finds all IRPs with a stack location where DeviceObject equals Data.
fileobject | Finds all IRPs whose Irp.Tail.Overlay.OriginalFileObject equals Data.
mdlprocess | Finds all IRPs whose Irp.MdlAddress.Process equals Data.
thread | Finds all IRPs whose Irp.Tail.Overlay.Thread equals Data.
userevent | Finds all IRPs whose Irp.UserEvent equals Data.

Data
Specifies the data to be matched in the search.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The example would find the IRP in nonpaged pool that is going to set user event FF9E4F48 upon completion:

kd> !irpfind 0 0 userevent ff9e4f48

The following example produces a full listing of all IRPs in the nonpaged pool:

kd> !irpfind
Searching NonPaged pool (8090c000 : 8131e000) for Tag: Irp
8097c008 Thread 8094d900 current stack belongs to  \Driver\symc810
8097dec8 Thread 8094dda0 current stack belongs to  \FileSystem\Ntfs
809861a8 Thread 8094dda0 current stack belongs to  \Driver\symc810
809864e8 Thread 80951ba0 current stack belongs to  \Driver\Mouclass
80986608 Thread 80951ba0 current stack belongs to  \Driver\Kbdclass
80986728 Thread 8094dda0 current stack belongs to  \Driver\symc810

Additional Information

See Plug and Play Debugging for applications of this extension command. For information on IRPs, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!irpzone

The !irpzone extension command is obsolete. Use !irpfind instead.


!job

Displays a job object.

Syntax

!job [Process [Flags]]

Parameters

Process
Specifies the hexadecimal address of a process or a thread whose associated job object is to be examined. If this is omitted, or equal to -1 (in Windows 2000), or equal to zero (in Windows XP or Windows .NET Server 2003), the job associated with the current process is displayed.
Flags
Specifies what the display should contain. This can be a sum of any of the following bit values. The default is 0x1:
Bit 0 (0x1)
Causes the display to include job settings and statistics.
Bit 1 (0x2)
Causes the display to include a list of all processes in the job.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Here is an example of this extension:

kd> !process 52c
Searching for Process with Cid == 52c
PROCESS 8276c550  SessionId: 0  Cid: 052c    Peb: 7ffdf000  ParentCid: 0060
    DirBase: 01289000  ObjectTable: 825f0368  TableSize:  24.
    Image: cmd.exe
    VadRoot 825609e8 Vads 30 Clone 0 Private 77. Modified 0. Locked 0.
    DeviceMap e1733f38
    Token                             e1681610
    ElapsedTime                       0:00:12.0949
    UserTime                          0:00:00.0359
    .....
    CommitCharge                      109
    Job                               8256e1f0

kd> !job 8256e1f0
Job at ffffffff8256e1f0
  TotalPageFaultCount      0
  TotalProcesses           1
  ActiveProcesses          1
  TotalTerminatedProcesses 0
  LimitFlags               0
  MinimumWorkingSetSize    0
  MaximumWorkingSetSize    0
  ActiveProcessLimit       0
  PriorityClass            0
  UIRestrictionsClass      0
  SecurityLimitFlags       0
  Token                    00000000

Additional Information

For information on job objects, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!kb

The !kb extension command is obsolete. Use the KB (Display Stack Backtrace) command instead.


!kv

The !kv extension command is obsolete. Use the KV (Display Stack Backtrace) command instead.


!locks (!kdext*.locks)

Displays information about kernel ERESOURCE locks.

This extension command should not be confused with the !ntsdexts.locks extension command.

Syntax

!locks [Options] [Address]

Parameters

Options
Specifies the amount of information to be diplayed. Any combination of the following options can be used:
-v
Causes the display to include longer, more detailed output about each lock.
-p
Causes the display to include maximum output for the locks, along with performance statistics.
-d
Causes the display to include all locks. (Normally only locks with contention are displayed.)
Address
Specifies the hexadecimal address of the ERESOURCE lock to be displayed. If Address is zero or omitted, information about all ERESOURCE locks in the system will be displayed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The !locks extension displays all locks held on resources by threads. A lock can be shared or exclusive, which means no other threads can gain access to that resource. This information is useful when a deadlock occurs on a system. A deadlock is caused by one non-executing thread holding an exclusive lock on a resource needed by an executing thread.

You can usually pinpoint a deadlock in Microsoft® Windows® 2000 by finding one non-executing thread that holds an exclusive lock on a resource required by an executing thread. Most of the locks are shared.

Here is an example of the basic !locks output:

kd> !locks
**** DUMP OF ALL RESOURCE OBJECTS ****
KD: Scanning for held locks......

Resource @ 0x80e97620    Shared 4 owning threads
     Threads: ff688da0-01<*> ff687da0-01<*> ff686da0-01<*> ff685da0-01<*>
KD: Scanning for held locks.......................................................

Resource @ 0x80e23f38    Shared 1 owning threads
     Threads: 80ed0023-01<*> *** Actual Thread 80ed0020
KD: Scanning for held locks.

Resource @ 0x80d8b0b0    Shared 1 owning threads
     Threads: 80ed0023-01<*> *** Actual Thread 80ed0020
2263 total locks, 3 locks currently held

If you wish to find more information about one of these resource objects, use the address which follows "Resource @" as an argument for future commands. After the example above, you could use !thread 80d8b0b0 or dt ERESOURCE 80d8b0b0 for more details on this resource. Or you could use the !locks extension again with the -v option:

kd> !locks -v 80d8b0b0

Resource @ 0x80d8b0b0    Shared 1 owning threads
     Threads: 80ed0023-01<*> *** Actual Thread 80ed0020

     THREAD 80ed0020  Cid 4.2c  Teb: 00000000 Win32Thread: 00000000 WAIT: (WrQueue) KernelMode Non-Alertable
         8055e100  Unknown
     Not impersonating
GetUlongFromAddress: unable to read from 00000000
     Owning Process 80ed5238
     WaitTime (ticks)          44294977
     Context Switch Count      147830
     UserTime                  0:00:00.0000
     KernelTime                0:00:02.0143
     Start Address nt!ExpWorkerThread (0x80506aa2)
     Stack Init fafa4000 Current fafa3d18 Base fafa4000 Limit fafa1000 Call 0
     Priority 13 BasePriority 13 PriorityDecrement 0
ChildEBP RetAddr
fafa3d30 804fe997 nt!KiSwapContext+0x25 (FPO: [EBP 0xfafa3d48] [0,0,4]) [D:\NT\base\ntos\ke\i386\ctxswap.asm @ 139]
fafa3d48 80506a17 nt!KiSwapThread+0x85 (FPO: [Non-Fpo]) (CONV: fastcall) [d:\nt\base\ntos\ke\thredsup.c @ 1960]
fafa3d78 80506b36 nt!KeRemoveQueue+0x24c (FPO: [Non-Fpo]) (CONV: stdcall) [d:\nt\base\ntos\ke\queueobj.c @ 542]
fafa3dac 805ad8bb nt!ExpWorkerThread+0xc6 (FPO: [Non-Fpo]) (CONV: stdcall) [d:\nt\base\ntos\ex\worker.c @ 1130]
fafa3ddc 8050ec72 nt!PspSystemThreadStartup+0x2e (FPO: [Non-Fpo]) (CONV: stdcall) [d:\nt\base\ntos\ps\create.c @ 2164]
00000000 00000000 nt!KiThreadStartup+0x16 [D:\NT\base\ntos\ke\i386\threadbg.asm @ 81]

1 total locks, 1 locks currently held


!lookaside

Displays information about lookaside lists, resets the counters of lookaside lists, or modifies the depth of a lookaside list.

Syntax

!lookaside [Address [Options [Depth]]]

Parameters

Address
Specifies the hexadecimal address of a lookaside list to be used. If Address is omitted or zero, this specifies all system lookaside lists.
Options
Controls what operation will be taken. The following possible Options are supported. The default is zero:
0
Displays information about the specified lookaside list. (If Address is zero, information about all system lookaside lists will be displayed.)
1
Resets the counters of the specified lookaside list. (If Address is zero, the counters of all system lookaside lists will be reset.)
2
Modifies the depth of the specified lookaside list. This option can only be used if Address is nonzero.
Depth
Specifies the new depth of the specified lookaside list. This parameter is permitted only if Address is nonzero and Options is not two.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Lookaside lists are multiprocessor-safe mechanisms for managing pools of fixed-size entries from either paged or nonpaged memory.

Lookaside lists are efficient because the routines do not use spin locks on most platforms.

Additional Information

For information on lookaside lists, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!lpc

Displays information about all local procedure call (LPC) ports and messages in the target system.

Syntax

Windows NT 4.0 Syntax

!lpc

Windows 2000 Syntax

!lpc message MessageID
!lpc port Port
!lpc scan Port
!lpc thread Thread
!lpc

Windows XP and Windows .NET Server 2003 Syntax

!lpc message MessageID
!lpc port Port
!lpc scan Port
!lpc thread Thread
!lpc PoolSearch
!lpc

Parameters

message
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Causes information about a message to be displayed, including information about the server port that contains it in the queue, and all threads that are using this message.
MessageID
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Specifies the message ID of the message to be displayed. If this is omitted or zero, the !lpc message command displays a summary list of messages. (In Windows 2000 prior to Service Pack 1, this includes all messages in the LPC zone. In Windows 2000 Service Pack 2, Windows XP, and Windows .NET Server 2003, this includes all messages in the kernel pool. Paged-out messages will not be included.)
port
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Causes port information to be displayed. This information includes the name of the port, its semaphore state, messages in its queues, threads in its rundown queue, its handle count, its references and related ports.
scan
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Causes summary information about the specified port, and all ports that are connected to it, to be displayed.
Port
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Specifies the hexadecimal address of the port to be displayed. If the !lpc port command is used and Port is omitted or zero, a summary list of all LPC ports is displayed. If the !lpc scan command is used, Port must specify the address of an actual port.
thread
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Causes port information to be displayed for all ports that contain the specified thread in their rundown port queues.
Thread
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Specifies the hexadecimal address of the thread. If this is omitted or zero, the !lpc thread command displays a summary list of all threads that are performing any LPC operations.
PoolSearch
(Windows XP and Windows .NET Server 2003 only) Controls whether the !lpc message command searches for messages in the kernel pool. Each time !lpc PoolSearch is used, this setting toggles on or off (the initial setting is to not search the kernel pool). This only affects !lpc message commands that specify a nonzero value for MessageID.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

In Windows NT 4.0, using !lpc with no arguments displays all LPC ports and messages on the target computer, much like !lpc port followed by !lpc message in Windows 2000, Windows XP, and Windows .NET Server 2003.

In Windows 2000, Windows XP, and Windows .NET Server 2003, using !lpc with no arguments causes a short help text to be displayed.

If you have a thread that is marked as waiting for a reply to a message, use the !lpc message command with the ID of the delayed message. This will display the specified message, the port containing it, and all related threads.

If the message isn't found, and there were no read errors (such as "Unable to access zone segment"), the server received the message.

In this case, the server port can usually be found by using the !lpc thread command. Threads that are waiting for replies are linked into a server communication queue. This command will display all ports that contain the specified thread.

Once you know the port address, use the !lpc port command.

Here is an example from a Windows NT 4.0 system:

kd> !lpc
Scanning 2 objects of type 'Port'
Connection Port Object at e11b8bc0 - Name='\SmApiPort' created by smss.exe
Connection Port Object at e11ba040 - Name='\SeRmCommandPort' created by System

Here is an example from a Windows XP system:

kd> !lpc port
Scanning 225 objects
       1  Port: 0xe1405650 Connection: 0xe1405650  Communication: 0x00000000  'SeRmCommandPort'
       1  Port: 0xe141ef50 Connection: 0xe141ef50  Communication: 0x00000000  'SmApiPort'
       1  Port: 0xe13c5740 Connection: 0xe13c5740  Communication: 0x00000000  'ApiPort'
       1  Port: 0xe13d9550 Connection: 0xe13d9550  Communication: 0x00000000  'SbApiPort'
       3  Port: 0xe13d8830 Connection: 0xe141ef50  Communication: 0xe13d8910  ''
80000004  Port: 0xe13d8910 Connection: 0xe141ef50  Communication: 0xe13d8830  ''
       3  Port: 0xe13d8750 Connection: 0xe13d9550  Communication: 0xe13a4030  ''
       .....

kd> !lpc port e13d8830

Server communication port 0xe13d8830
    Handles: 1   References: 1
    The LpcDataInfoChainHead queue is empty
        Connected port: 0xe13d8910      Server connection port: 0xe141ef50

Client communication port 0xe13d8910
    Handles: 1   References: 1
    The LpcDataInfoChainHead queue is empty

Server connection port e141ef50  Name: SmApiPort
    Handles: 1   References: 12
    Server process  : 82736030 (smss.exe)
    Queue semaphore : 826a6d88
    Semaphore state 0 (0x0)
    The message queue is empty
    The LpcDataInfoChainHead queue is empty

kd> !lpc scan e13d8830
Scanning 225 objects
       3  Port: 0xe13d8830 Connection: 0xe141ef50  Communication: 0xe13d8910  ''
80000004  Port: 0xe13d8910 Connection: 0xe141ef50  Communication: 0xe13d8830  ''
Scanning 3 objects

Additional Information

For information on LPCs, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!memusage

Displays summary statistics about physical memory use.

Syntax

!memusage

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Physical memory statistics are collected from the Memory Manager's page frame number (PFN) database table.

This command takes a long time to run, especially with an IA-64 target computer. While it is loading the PFN database, a counter will show its progress. To speed up this loading, increase the COM port speed with the CTRL+A (Toggle Baud Rate) key, or use the .cache (Set Cache Size) command to increase the cache size (perhaps to around 10 MB).

The !memusage command can also be used while performing local kernel debugging.

Here is an example of this command's output:

kd> !memusage
 loading PFN database
loading (98% complete)

Compiling memory usage data (100% Complete).
             Zeroed:     49 (   196 kb)
               Free:      5 (    20 kb)
            Standby:   5489 ( 21956 kb)
           Modified:    714 (  2856 kb)
    ModifiedNoWrite:      1 (     4 kb)
       Active/Valid:  10119 ( 40476 kb)
         Transition:      6 (    24 kb)
            Unknown:      0 (     0 kb)
              TOTAL:  16383 ( 65532 kb)

  Building kernel map
  Finished building kernel map
Scanning PFN database - (99% complete)

  Usage Summary (in Kb):

unable to get subsection va ffa0b200 1d4e080
unable to get subsection va ffbe0000 80
......
unable to get subsection va ffacc000 11400c0
unable to get subsection va ff937200 2a8e080

Control Valid Standby Dirty Shared Locked PageTables  name

8251a258    12    108     0     0     0     0  mapped_file( cscui.dll )
827ab1b8     8   1708     0     0     0     0  mapped_file( $Mft )
8263c408   908     48     0     0     0     0  mapped_file( win32k.sys )
8252dda8     0    324     0     0     0     0  mapped_file( ShellIconCache )
8272f638   128    112     0   116     0     0  mapped_file( advapi32.dll )
......
82755958     0      4     0     0     0     0  mapped_file( $Directory )
8250b518     0      4     0     0     0     0    No Name for File
8254d8d8     0      4     0     0     0     0  mapped_file( $Directory )
82537be8     0      4     0     0     0     0  mapped_file( Windows Explorer.lnk )

--------  1348      0     0 ----- -----   904  process ( System )
--------   492      0     0 ----- -----    72  process ( winmine.exe )
--------  3364   1384  1396 ----- -----   188  process ( explorer.exe )
--------   972      0     0 ----- -----    88  process ( services.exe )
--------   496   1456   384 ----- -----   164  process ( winmgmt.exe )
--------  1144      0     0 ----- -----   120  process ( svchost.exe )
--------   944      0     0 ----- -----   156  process ( winlogon.exe )
--------   412      0     0 ----- -----    64  process ( csrss.exe )
......
--------    12      0     0 ----- -----     8  process ( wmiadap.exe )

--------   316      0     0 ----- -----     0  pagefile section (346e)
--------  4096      0     0 ----- -----     0  pagefile section (9ad)

--------   884    280    36 -----     0 -----  driver ( ntoskrnl.exe )
--------    88      8     0 -----     0 -----  driver ( hal.dll )
--------     8      0     0 -----     0 -----  driver ( kdcom.dll )
--------    12      0     0 -----     0 -----  driver ( BOOTVID.dll )
......
--------     8      0     0 -----     0 -----  driver ( ndisuio.sys )
--------    16      0     0 -----     0 -----  driver ( dump_scsiport.sys )
--------    56      0     0 -----     0 -----  driver ( dump_aic78xx.sys )
--------  2756   1060   876 -----     0 -----  driver ( Paged Pool )
--------  1936    128   148 -----     0 -----  driver ( Kernel Stacks )
--------     0      0     0 -----     0 -----  driver ( NonPaged Pool )

The first column gives the control area structure that describes each mapped structure. Use the !ca extension command to display these control areas.

Additional Information

The !vm extension command can be used to analyze virtual memory usage. For more information on memory management, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!mps

Displays BIOS information for the Intel® Multiprocessor Specification (MPS) of the target computer.

Syntax

!mps [Address]

Parameters

Address
Specifies the hexadecimal address of the MPS table in the BIOS. If this is omitted, the information is obtained from the HAL — this will require HAL symbols.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

This extension command can only be used with an x86 target computer.

Additional Information

For more information on BIOS debugging, see Debugging BIOS Code. For more information on the MPS, refer to the appropriate version of the Intel MultiProcessor Specification.


!mtrr

Displays the contents of the MTRR register.

Syntax

!mtrr

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

This extension command can only be used with an x86 target computer.


!npx

Displays the contents of the floating-point register save area.

Syntax

!npx Address

Parameters

Address
Specifies the hexadecimal address of the FLOATING_SAVE_AREA structure.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

This extension command can only be used with an x86 target computer.


!ob, !od, !ow

The !ob, !od, and !ow extension commands are obsolete. Use the OB, OD, and OW (Output to Port) commands instead.


!object

Displays information about a system object.

Syntax

Windows NT 4.0 Syntax

!object Address
!object 0 Name
!object \

Windows 2000, Windows XP, and Windows .NET Server 2003 Syntax

!object Address
!object 0 Name
!object Path
!object -r

Parameters

Address
If the first argument is a nonzero hexadecimal number, it specifies the hexadecimal address of the system object for which to display information.
Name
If the first argument is zero, the second argument is interpreted as the name of a class of system object for which to display all instances.
Path
If the first argument begins with a backslash (\), !object interprets it as an object path name. When this option is used, the display will be arranged according to the directory structure used by the Object Manager.
\
(Windows NT 4.0 only) Specifies the root directory object.
-r
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Causes cached values of global variables to be refreshed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The !object extension caches certain global variables, whose values can change. If the set of kernel symbols you are using has become stale, use !object -r to refresh the cached values.

The following example obtains an object pointer by executing the !handle extension:

kd> !handle
processor number 0
PROCESS 80a02920  Cid: 0002    Peb: 00000000  ParentCid: 0000
    DirBase: 0006c805  ObjectTable: 80a03788  TableSize:  54.
    Image: System
006c: Object: 80967768  GrantedAccess: 00100003
Object: 80967768  Type: (809d5c20) File
    ObjectHeader: 80967750
        HandleCount: 1  PointerCount: 1
        Directory Object: 00000000  Name: \WINNT\system32\config\software {Partition1}

kd> !object 80967768
Object: 80967768  Type: (809d5c20) File
    ObjectHeader: 80967750
    HandleCount: 1  PointerCount: 1
    Directory Object: 00000000  Name: \WINNT\system32\config\software {Partition1}

Additional Information

For information on objects and the object manager, see the Platform SDK, the Windows DDK, or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!pci

Displays the current status of the peripheral component interconnect (PCI) buses, as well as any devices attached to those buses.

Syntax

!pci [Flags [Bus [Device [Function [MinAddress MaxAddress]]]]]

Parameters

Flags
Specifies the level of output. Can be any combination of the following bits:
Bit 0 (0x1)
Causes a verbose display.
Bit 1 (0x2)
Causes the display to include all buses in the range from bus 0 to the specified Bus.
Bit 2 (0x4)
Causes the display to include information in raw byte format. If MinAddress, MaxAddress, or flag bit 0x8 are set, this bit is automatically set as well.
Bit 3 (0x8)
Causes the display to include information in raw DWORD format.
Bit 4 (0x10)
Causes the display to include invalid device numbers. If Device is specified, this flag is ignored.
Bit 5 (0x20)
Causes the display to include invalid function numbers.
Bit 6 (0x40)
Causes the display to include capabilities.
Bit 7 (0x80)
Causes the display to include Intel 8086 device-specific information.
Bit 8 (0x100)
Causes the display to include the PCI configuration space.
Bus
Specifies the bus to be displayed. Bus can range from 0 to 0xFF. If it is omitted, information on the primary bus (bus 0) will be displayed. If Flags includes bit 1 (0x2), Bus specifies the highest bus number to be displayed.
Device
Specifies the slot device number for the device. If this is omitted, information on all devices is printed.
Function
Specifies the slot function number for the device. If this is omitted, all information on all device functions is printed.
MinAddress
Specifies the first address from which raw bytes or DWORDs are to be displayed. This must be between 0 and 0xFF.
MaxAddress
Specifies the last address from which raw bytes or DWORDs are to be displayed. This must be between 0 and 0xFF, and not less than MinAddress.

DLL

Windows NT 4.0 | kext.dll kdextx86.dll
Windows 2000 | kext.dll kdextx86.dll
Windows XP Windows .NET Server 2003 | kext.dll

This extension command can only be used with an x86 target computer.

Comments

To edit the PCI configuration space, use !ecb, !ecd, or !ecw.

The following example displays a list of all buses and their devices. This command will take a long time to execute. You will see a moving counter at the bottom of the display while the debugger scans the target system for PCI buses:

kd> !pci 2 ff
PCI Bus 0
00:0  8086:1237.02  Cmd[0106:.mb..s]  Sts[2280:.....]  Device  Host bridge
0d:0  8086:7000.01  Cmd[0007:imb...]  Sts[0280:.....]  Device  ISA bridge
0d:1  8086:7010.00  Cmd[0005:i.b...]  Sts[0280:.....]  Device  IDE controller
0e:0  1011:0021.02  Cmd[0107:imb..s]  Sts[0280:.....]  PciBridge 0->1-1  PCI-PCI bridge
10:0  102b:0519.01  Cmd[0083:im....]  Sts[0280:.....]  Device  VGA compatible controller
PCI Bus 1
08:0  10b7:9050.00  Cmd[0107:imb..s]  Sts[0200:.....]  Device  Ethernet
09:0  9004:8178.00  Cmd[0117:imb..s]  Sts[0280:.....]  Device  SCSI controller

This example will display verbose information about the devices on the primary bus. The two-digit number at the beginning of each line is the device number; the one-digit number following it is the function number:

kd> !pci 1 0
PCI Bus 0
00:0  8086:1237.02  Cmd[0106:.mb..s]  Sts[2280:.....]  Device  Host bridge
      cf8:80000000  IntPin:0  IntLine:0  Rom:0  cis:0  cap:0

0d:0  8086:7000.01  Cmd[0007:imb...]  Sts[0280:.....]  Device  ISA bridge
      cf8:80006800  IntPin:0  IntLine:0  Rom:0  cis:0  cap:0

0d:1  8086:7010.00  Cmd[0005:i.b...]  Sts[0280:.....]  Device  IDE controller
      cf8:80006900  IntPin:0  IntLine:0  Rom:0  cis:0  cap:0
      IO[4]:fff1

0e:0  1011:0021.02  Cmd[0107:imb..s]  Sts[0280:.....]  PciBridge 0->1-1  PCI-PCI bridge
      cf8:80007000  IntPin:0  IntLine:0  Rom:0  cap:0  2sts:2280  BCtrl:6 ISA
      IO:f000-ffff  Mem:fc000000-fdffffff  PMem:fff00000-fffff

10:0  102b:0519.01  Cmd[0083:im....]  Sts[0280:.....]  Device  VGA compatible controller
      cf8:80008000  IntPin:1  IntLine:9  Rom:80000000  cis:0  cap:0
      MEM[0]:fe800000  MPF[1]:fe000008

This example shows even more detailed information about bus 0, device 0x0D, function 0x1, including the raw DWORDS from addresses between 0x00 and 0x3F:

kd> !pci f 0 d 1 0 3f
PCI Bus 0
0d:1  8086:7010.00  Cmd[0005:i.b...]  Sts[0280:.....]  Device  IDE controller
      cf8:80006900  IntPin:0  IntLine:0  Rom:0  cis:0  cap:0
      IO[4]:fff1
      00000000:  70108086 02800005 01018000 00002000
      00000010:  00000000 00000000 00000000 00000000
      00000020:  0000fff1 00000000 00000000 00000000
      00000030:  00000000 00000000 00000000 00000000

Additional Information

See Plug and Play Debugging for applications of this extension command, and some additional examples. For information on PCI buses, see the Windows DDK.


!pcitree

Displays information on PCI device objects, including child PCI buses and CardBus buses and the devices attached to them.

Syntax

!pcitree

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Here is an example:

kd> !pcitree

Bus 0x0 (FDO Ext fe517338)
  0600 12378086 (d=0,  f=0) devext fe4f4ee8 Bridge/HOST to PCI
  0601 70008086 (d=d,  f=0) devext fe4f4ce8 Bridge/PCI to ISA
  0101 70108086 (d=d,  f=1) devext fe4f4ae8 Mass Storage Controller/IDE
  0604 00211011 (d=e,  f=0) devext fe4f4788 Bridge/PCI to PCI

Bus 0x1 (FDO Ext fe516998)
  0200 905010b7 (d=8,  f=0) devext fe515ee8 Network Controller/Ethernet
  0100 81789004 (d=9,  f=0) devext fe515ce8 Mass Storage Controller/SCSI
  0300 0519102b (d=10, f=0) devext fe4f4428 Display Controller/VGA

Total PCI Root busses processed = 1

To understand this display, consider the final device shown. Its base class is 03, its subclass is 00, its Device ID is 0x0519, and its Vendor ID is 0x102B. These values are all intrinsic to the device itself.

The number after "d=" is the device number; the number after "f=" is the function number. After "devext" appears the device extension address, 0xFE4F4428. Finally, the base class name and the subclass name appear.

To obtain more information on a device, use the !devext extension command with the device extension address as the argument. For this particular device, the command to use would be:

kd> !devext fe4f4428 pci

If the !pcitree extension generates an error, this often means that your PCI symbols were not loaded properly. Use .reload pci.sys to fix this problem.

Additional Information

See Plug and Play Debugging for applications of this extension command. For information on PCI buses and PCI device objects, see the Windows DDK.


!pcr

Displays the current status of the Processor Control Region (PCR) on a specific processor.

Syntax

!pcr [Processor]

Parameters

Processor
Specifies the processor to retrieve the PCR information from. If Processor is omitted, processor zero will be used.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The processor control block (PRCB) is an extension of the PCR. It can be displayed with the !prcb extension.

Here is an example of the !pcr extension on an x86 target computer:

kd> !pcr 0
KPCR for Processor 0 at ffdff000:
    Major 1 Minor 1
      NtTib.ExceptionList: 801626e0
          NtTib.StackBase: 801628f0
         NtTib.StackLimit: 8015fb00
       NtTib.SubSystemTib: 00000000
            NtTib.Version: 00000000
        NtTib.UserPointer: 00000000
            NtTib.SelfTib: 00000000

                  SelfPcr: ffdff000
                     Prcb: ffdff120
                     Irql: 00000000
                      IRR: 00000000
                      IDR: ffffffff
            InterruptMode: 00000000
                      IDT: 80043400
                      GDT: 80043000
                      TSS: 803cc000

            CurrentThread: 8015e8a0
               NextThread: 00000000
               IdleThread: 8015e8a0

                DpcQueue:  0x80168ee0 0x80100d04 ntoskrnl!KiTimerExpiration

Additional Information

For information on the PCR and the PRCB, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!pfn

Displays information about a specific page frame or the whole page frame database.

Syntax

!pfn PageFrame

Parameters

PageFrame
Specifies the hexadecimal number of the page frame to be displayed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The page frame number for a virtual address can be obtained by using the !pte extension.

Here is an example:

kd> !pte 801544f4
801544F4  - PDE at C0300800        PTE at C0200550
          contains 0003B163      contains 00154121
        pfn 3b G-DA--KWV    pfn 154 G--A--KRV

kd> !pfn 3b
    PFN 0000003B at address 82350588
    flink       00000000  blink / share count 00000221  pteaddress C0300800
    reference count 0001                                 color 0
    restore pte 00000000  containing page        000039  Active

kd> !pfn 154
    PFN 00000154 at address 82351FE0
    flink       00000000  blink / share count 00000001  pteaddress C0200550
    reference count 0001                                 color 0
    restore pte 00000060  containing page        00003B  Active     M
    Modified

Additional Information

For information on page tables, page directories, and page frames, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!pnpevent

Displays the Plug and Play device event queue.

Syntax

!pnpevent [DeviceEvent]

Parameters

DeviceEvent
Specifies the address of a device event to display. If this is zero or omitted, the tree of all device events in the queue is displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

See Plug and Play Debugging for applications of this extension command. For information on Plug and Play drivers, see the Windows DDK.


!pocaps

Displays the power capabilities of the target computer.

Syntax

!pocaps

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Here is an example of this command's output:

kd> !pocaps
PopCapabilities @ 0x8016b100
  Misc Supported Features:  S4 FullWake
  Processor Features:
  Disk Features:            SpinDown
  Battery Features:
  Wake Caps
    Ac OnLine Wake:         Sx
    Soft Lid Wake:          Sx
    RTC Wake:               Sx
    Min Device Wake:        Sx
    Default Wake:           Sx

Additional Information

To view the system's power policy, use the !popolicy extension command. For information on power cababilities and power policy, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!pool

Displays information about a specific pool allocation, or about the entire system-wide pool.

Syntax

!pool [Address [Flags]]

Parameters

Address
Specifies the pool entry to be displayed. If Address is -1, this command displays information about all heaps in the process. If Address is omitted or equal to zero, this command displays information about the process heap.
Flags
Specifies the level of detail to be used. This can be any combination of the following bit values; the default is zero:
Bit 0 (0x1)
Causes the display to include the pool contents, not just the pool headers.
Bit 1 (0x2)
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Causes the display to suppress pool header information for all pools except the one that actually contains the specified Address.
Bit 31 (0x80000000)
(Windows XP and Windows .NET Server 2003 only) Suppresses the description of the pool type and pool tag in the display.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

In Windows XP and later versions of Windows, the !pool extension displays the pool tag associated with each allocation. The owner of that pool tag is also displayed. This display is based on the contents of the pooltag.txt file. This file is located in the triage subdirectory of your Debugging Tools for Windows installation. If you wish, you can edit this file to add additional pool tags germane to your project.

Warning If you install an updated version of Debugging Tools for Windows in the same directory as the current version, it will overwrite all the files in that directory — including pooltag.txt! If you modify or replace the sample pooltag.txt file, be sure to save a copy of it to a different directory. After reinstalling the debuggers, you can copy the saved pooltag.txt over the default version.

If the !pool extension reports pool corruption, you should use !poolval to investigate.

Here is an example. If Address specifies 0xE1001050, the headers of all pools in this block are displayed, and 0xE1001050 itself is marked with an asterisk (*).

kd> !pool e1001050
 e1001000 size:   40 previous size:    0  (Allocated)  MmDT
 e1001040 size:   10 previous size:   40  (Free)       Mm
*e1001050 size:   10 previous size:   10  (Allocated) *ObDi
 e1001060 size:   10 previous size:   10  (Allocated)  ObDi
 e1001070 size:   10 previous size:   10  (Allocated)  Symt
 e1001080 size:   40 previous size:   10  (Allocated)  ObDm
 e10010c0 size:   10 previous size:   40  (Allocated)  ObDi
.....

In this example, the right-most column shows the pool tag. The column prior to this shows whether the pool is free or allocated.

The following command shows the pool headers and pool contents:

kd> !pool e1001050 1
 e1001000 size:   40 previous size:    0  (Allocated)  MmDT
    e1001008  ffffffff 0057005c 004e0049 004f0044
    e1001018  ffffffff 0053005c 00730079 00650074

 e1001040 size:   10 previous size:   40  (Free)       Mm
    e1001048  ffffffff e1007ba8 e1501a58 01028101
    e1001058  ffffffff 00000000 e1000240 01028101

*e1001050 size:   10 previous size:   10  (Allocated) *ObDi
    e1001058  ffffffff 00000000 e1000240 01028101
    e1001068  ffffffff 00000000 e10009c0 01028101

 e1001060 size:   10 previous size:   10  (Allocated)  ObDi
    e1001068  ffffffff 00000000 e10009c0 01028101
    e1001078  ffffffff 00000000 00000000 04028101

......

Additional Information

For information on memory pools, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!poolfind

Finds all instances of a specific pool tag in either nonpaged or paged memory pools.

Syntax

Windows NT 4.0 Syntax

!poolfind TagString [PoolType]

Windows 2000, Windows XP, and Windows .NET Server 2003 Syntax

!poolfind TagString [PoolType]
!poolfind TagValue [PoolType]

Parameters

TagString
Specifies the pool tag. TagString is a case-sensitive ASCII string. The asterisk (*) can be used to represent any number of characters; the question mark (?) can be used to represent exactly one character. Unless an asterisk is used, TagString must be exactly four characters in length.
TagValue
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Specifies the pool tag. TagValue must begin with "0x", even if the default radix is 16. If this parameter begins with any other value (including "0X") it will be interepreted as an ASCII tag string.
PoolType
Specifies the type of pool to be searched. The following values are permitted:
0
Specifies nonpaged memory pool. (This is the default.)
1
Specifies paged memory pool.
2
Specifies the special pool.
4
(Windows XP and Windows .NET Server 2003 only) Specifies the session pool.
4, 5, 6
(Windows NT 4.0 only) Same as 0, 1, 2, but displays verbose information.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This command can take a significant amount of time to execute, depending on the size of pool memory that must be searched. To speed up this execution, increase the COM port speed with the CTRL+A (Toggle Baud Rate) key, or use the .cache (Set Cache Size) command to increase the cache size (perhaps to around 10 MB).

The pool tag is the same tag passed to the ExAllocateXxx family of routines.

Here is an example. The entire nonpaged pool is searched, and then the paged pool is searched, but the command is terminated before completion (after an hour of operation):

kd> !poolfind SeSd 0

Scanning large pool allocation table for Tag: SeSd (827d1000 : 827e9000)

Searching NonPaged pool (823b1000 : 82800000) for Tag: SeSd

826fa130 size:   c0 previous size:   40  (Allocated) SeSd
82712000 size:   c0 previous size:    0  (Allocated) SeSd
82715940 size:   a0 previous size:   60  (Allocated) SeSd
8271da30 size:   c0 previous size:   10  (Allocated) SeSd
82721c00 size:   10 previous size:   30  (Free)      SeSd
8272b3f0 size:   60 previous size:   30  (Allocated) SeSd
8272d770 size:   60 previous size:   40  (Allocated) SeSd
8272d7d0 size:   a0 previous size:   60  (Allocated) SeSd
8272d960 size:   a0 previous size:   70  (Allocated) SeSd
82736f30 size:   a0 previous size:   10  (Allocated) SeSd
82763840 size:   a0 previous size:   10  (Allocated) SeSd
8278b730 size:  100 previous size:  290  (Allocated) SeSd
8278b830 size:   10 previous size:  100  (Free)      SeSd
82790130 size:   a0 previous size:   20  (Allocated) SeSd
82799180 size:   a0 previous size:   10  (Allocated) SeSd
827c00e0 size:   a0 previous size:   30  (Allocated) SeSd
827c8320 size:   a0 previous size:   60  (Allocated) SeSd
827ca180 size:   a0 previous size:   50  (Allocated) SeSd
827ec140 size:   a0 previous size:   10  (Allocated) SeSd

Searching NonPaged pool (fe7c3000 : ffbe0000) for Tag: SeSd

kd> !poolfind SeSd 1

Scanning large pool allocation table for Tag: SeSd (827d1000 : 827e9000)

Searching Paged pool (e1000000 : e4400000) for Tag: SeSd

e10000b0 size:   d0 previous size:   20  (Allocated) SeSd
e1000260 size:   d0 previous size:   60  (Allocated) SeSd
......
e1221dc0 size:   a0 previous size:   60  (Allocated) SeSd
e1224250 size:   a0 previous size:   30  (Allocated) SeSd

...terminating - searched pool to e1224000
kd>

Additional Information

For information on memory pools and pool tags, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!poolused

Displays memory use summaries, based on the tag used for each pool allocation.

Syntax

Windows NT 4.0 Syntax

!poolused [Flags]

Windows 2000, Windows XP, and Windows .NET Server 2003 Syntax

!poolused [Flags [TagString]]

Parameters

Flags
Specifies the amount of output to be displayed, and the method of sorting the output. This can be any combination of the following bit values, except that bits 1 (0x) and 2 (0x4) cannot be used together. The default is 0x0, which produces summary information, sorted by pool tag.
Bit 0 (0x1)
Causes the display to show more detailed (verbose) information.
Bit 1 (0x2)
Causes the display to be sorted by the amount of nonpaged memory use.
Bit 2 (0x4)
Causes the display to be sorted by the amount of paged memory use.
Bit 3 (0x8)
(Windows XP and Windows .NET Server 2003 only) Displays the session pool instead of the standard pool.
TagString
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Specifies the pool tag. TagString is a case-sensitive ASCII string. The asterisk (*) can be used to represent any number of characters; the question mark (?) can be used to represent exactly one character. Unless an asterisk is used, TagString must be exactly four characters in length.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This command can take a long time. If it is cut off before completion, the partial results will be displayed, sorted according to the order specified by the Flags parameter.

Additional Information

For information on memory pools and pool tags, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!poolval

Analyzes the headers for a pool page and diagnoses any possible corruption.

Syntax

!poolval Address [DisplayLevel]

Parameters

Address
Specifies the address of the pool whose header is to be analyzed.
DisplayLevel
Specifies the information to include in the display. This can be any of the following values. The default is zero:
0
Causes basic information to be displayed.
1
Causes basic information and linked header lists to be displayed.
2
Causes basic information, linked header lists, and basic header information to be displayed.
3
Causes basic information, linked header lists, and full header information to be displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

For information on memory pools, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!popolicy

Displays the power policy of the target computer.

Syntax

!popolicy

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Here is an example of this command's output:

kd> !popolicy
SYSTEM_POWER_POLICY (R.1) @ 0x80164d58
  PowerButton:      Shutdown  Flags: 00000003   Event: 00000000   Query UI
  SleepButton:          None  Flags: 00000003   Event: 00000000   Query UI
  LidClose:             None  Flags: 00000001   Event: 00000000   Query
  Idle:                 None  Flags: 00000001   Event: 00000000   Query
  OverThrottled:        None  Flags: c0000004   Event: 00000000   Override NoWakes Critical
  IdleTimeout:             0  IdleSensitivity:        50%
  MinSleep:               S0  MaxSleep:               S0
  LidOpenWake:            S0  FastSleep:              S0
  WinLogonFlags:           1  S4Timeout:               0
  VideoTimeout:            0  VideoDim:               209
  SpinTimeout:             0  OptForPower:             1
  FanTolerance:            0% ForcedThrottle:          0%
  MinThrottle:             0%

Additional Information

To view the system's power capabilities, use the !pocaps extension command. For information on power cababilities and power policy, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!prcb

Displays the processor control block (PRCB).

Syntax

!prcb [Processor]

Parameters

Processor
Specifies the processor to retrieve the PRCB information from. If Processor is omitted, processor zero will be used.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The PRCB is an extension of the processor control region (PCR). To display the PCR, use the !pcr extension.

Additional Information

For information on the PCR and the PRCB, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!process

Displays information about the specified process, or about all processes.

Syntax

Windows NT 4.0 Syntax

!process [/s Session] [Process [Flags]]

Windows 2000, Windows XP, and Windows .NET Server 2003 Syntax

!process [/s Session] [Process [Flags]]
!process [/s Session] 0 Flags ImageName

Parameters

/s Session
Specifies the session that owns the desired process.
Process
Specifies the hexadecimal address or the process ID of the process on the target computer. The !process extension will correctly understand whether Process specifies a process address or a process ID based on the value of Process. If Process is -1 or omitted, it indicates the current process. If Process is 0 and ImageName is omitted, information is displayed for all processes.
Flags
Specifies the level of detail to display. Flags can be any combination of the following bits. If Flags is 0, only a minimal amount of information is displayed. The default is 0x7.
Bit 0 (0x1)
Causes the display to include time and priority statistics.
Bit 1 (0x2)
Causes the display to include a list of threads and events associated with the process, and their wait states.
Bit 2 (0x4)
Causes the display to include a list of threads associated with the process. If this is included without Bit 1 (0x2), each thread will be displayed on a single line. If this is included along with Bit 1, each thread will be displayed with a stack trace.
Bit 3 (0x8)
(Windows XP and Windows .NET Server 2003 only) Causes the display of each function to include the return address, the stack pointer, and (on IA-64 systems) the bsp register value. The display of function arguments is suppressed.
Bit 4 (0x10)
(Windows XP and Windows .NET Server 2003 only) Causes the display of each function to include only the return address; arguments and stack pointers are suppressed.
ImageName
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Specifies the name of the process to be displayed. All processes whose executable image names match ImageName will be displayed. The image name must match that in the EPROCESS block — in general this is the executable name that was invoked to start the process, including the file extension (usually .exe), and truncated after the 15th character. There is no way to specify an image name that contains a space. When ImageName is specified, Process must be zero.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This command can only be used during kernel-mode debugging. It shows the contents of an EPROCESS block.

An example of a !process 0 0 display:

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 80a02a60  Cid: 0002    Peb: 00000000  ParentCid: 0000
    DirBase: 00006e05  ObjectTable: 80a03788  TableSize: 150.
    Image: System
PROCESS 80986f40  Cid: 0012    Peb: 7ffde000  ParentCid: 0002
    DirBase: 000bd605  ObjectTable: 8098fce8  TableSize:  38.
    Image: smss.exe
PROCESS 80958020  Cid: 001a    Peb: 7ffde000  ParentCid: 0012
    DirBase: 0008b205  ObjectTable: 809782a8  TableSize: 150.
    Image: csrss.exe
PROCESS 80955040  Cid: 0020    Peb: 7ffde000  ParentCid: 0012
    DirBase: 00112005  ObjectTable: 80955ce8  TableSize:  54.
    Image: winlogon.exe
PROCESS 8094fce0  Cid: 0026    Peb: 7ffde000  ParentCid: 0020
    DirBase: 00055005  ObjectTable: 80950cc8  TableSize: 222.
    Image: services.exe
PROCESS 8094c020  Cid: 0029    Peb: 7ffde000  ParentCid: 0020
    DirBase: 000c4605  ObjectTable: 80990fe8  TableSize: 110.
    Image: lsass.exe
PROCESS 809258e0  Cid: 0044    Peb: 7ffde000  ParentCid: 0026
    DirBase: 001e5405  ObjectTable: 80925c68  TableSize:  70.
    Image: SPOOLSS.EXE

The important information in the !process 0 0 display is:

Parameter | Meaning
Process address | The 8-character hexadecimal number after the word PROCESS is the address of the EPROCESS block. In the final entry in the preceding example, the process address is 0x809258E0.
Process ID (PID) | The hexadecimal number after the word Cid is the process ID. In the final entry in the preceding example, the PID is 0x44, or decimal 68.
Process Environment Block (PEB) | The hexadecimal number after the word Peb is the address of the process environment block. In the final entry in the preceding example, the PEB is located at address 0x7FFDE000.
Parent process | The hexadecimal number after the word ParentCid is the PID of the parent process. In the final entry in the preceding example, the parent PID is 0x26, or decimal 38.
Image | The name of the module that owns the process. In the final entry in the preceding example, the owner is spoolss.exe. In the first entry, the owner is the operating system itself.

To display full details on one process, set Flags to 7. The process itself can be specified by setting Process equal to the process address, setting Process equal to the process ID, or setting ImageName equal to the executable image name. Here is an example:

kd> !process fb667a00 7
PROCESS fb667a00 Cid: 0002  Peb: 00000000 ParentCid: 0000
  DirBase: 00030000 ObjectTable: e1000f88 TableSize: 112.
  Image: System
  VadRoot fb666388 Clone 0 Private 4. Modified 9850. Locked 0.
  FB667BBC MutantState Signalled OwningThread 0
  Token               e10008f0
  ElapsedTime            15:06:36.0338
  UserTime             0:00:00.0000
  KernelTime            0:00:54.0818
  QuotaPoolUsage[PagedPool]     1480
Working Set Sizes (now,min,max) (3, 50, 345)
  PeakWorkingSetSize        118
  VirtualSize            1 Mb
  PeakVirtualSize          1 Mb
  PageFaultCount          992
  MemoryPriority          BACKGROUND
  BasePriority           8
  CommitCharge           8

    THREAD fb667780 Cid 2.1 Teb: 00000000 Win32Thread: 80144900 WAIT: (WrFreePage) KernelMode Non-Alertable
    80144fc0 SynchronizationEvent
    Not impersonating
    Owning Process fb667a00
    WaitTime (seconds)   32278
    Context Switch Count  787
    UserTime         0:00:00.0000
    KernelTime        0:00:21.0821
    Start Address Phase1Initialization (0x801aab44)
    Initial Sp fb26f000 Current Sp fb26ed00
    Priority 0 BasePriority 0 PriorityDecrement 0 DecrementCount 0

    ChildEBP RetAddr Args to Child
    fb26ed18 80118efc c0502000 804044b0 00000000 KiSwapThread+0xb5
    fb26ed3c 801289d9 80144fc0 00000008 00000000 KeWaitForSingleObject+0x1c2

The following entries in the process information can be important:

Parameter | Meaning
ElapsedTime | Lists the amount of time that has elapsed since the process was created. This is displayed in units of Hours : Minutes : Seconds . Milliseconds.
UserTime | Lists the amount of time the process has been running in user mode. If the value for UserTime is exceptionally high, it might identify a process that is depleting system resources. Units are the same as those of ElapsedTime.
KernelTime | Lists the amount of time the process has been running in kernel mode. If the value for KernelTime is exceptionally high, it might identify a process that is depleting system resources. Units are the same as those of ElapsedTime.
Working Set sizes | Lists the current, minimum, and maximum working set size for the process, in pages. An exceptionally large working set size can also be a sign of a process that is leaking memory or depleting system resources..
QuotaPoolUsage entries | Lists the paged and nonpaged pool used by the process. On a system with a memory leak, looking for excessive nonpaged pool usage on all the processes can tell you which process has the memory leak.

In addition to the process list information, the thread information also contains a list of the resources on which the thread has locks. This information is listed right after the thread header. In this example, the thread has a lock on one resource, a SynchronizationEvent with an address of 80144fc0. By comparing this address to the list of locks shown by the !kdext*.locks extension, you can determine which threads have exclusive locks on resources.

The !stacks extension gives a brief summary of the state of every thread. This can be used instead of the !process extension to get a quick overview of the system, especially when debugging multi-thread issues such as resource conflicts or deadlocks.

Additional Information

For information on processes in kernel mode, see Changing Contexts. For more information on analyzing processes and threads, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!processfields

Displays the names and offsets of the fields within the executive process (EPROCESS) block.

Syntax

!processfields

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | Not available (see the Comments section)

Comments

This extension command is not available in Windows XP or Windows .NET Server 2003. Instead, use the DT (Display Type) command to show the EPROCESS structure directly:

kd> dt nt!_EPROCESS

Here is an example of !processfields from a Windows 2000 system:

kd> !processfields
 EPROCESS structure offsets:

    Pcb:                               0x0
    ExitStatus:                        0x6c
    LockEvent:                         0x70
    LockCount:                         0x80
    CreateTime:                        0x88
    ExitTime:                          0x90
    LockOwner:                         0x98
    UniqueProcessId:                   0x9c
    ActiveProcessLinks:                0xa0
    QuotaPeakPoolUsage[0]:             0xa8
    QuotaPoolUsage[0]:                 0xb0
    PagefileUsage:                     0xb8
    CommitCharge:                      0xbc
    PeakPagefileUsage:                 0xc0
    PeakVirtualSize:                   0xc4
    VirtualSize:                       0xc8
    Vm:                                0xd0
    DebugPort:                         0x120
    ExceptionPort:                     0x124
    ObjectTable:                       0x128
    Token:                             0x12c
    WorkingSetLock:                    0x130
    WorkingSetPage:                    0x150
    ProcessOutswapEnabled:             0x154
    ProcessOutswapped:                 0x155
    AddressSpaceInitialized:           0x156
    AddressSpaceDeleted:               0x157
    AddressCreationLock:               0x158
    ForkInProgress:                    0x17c
    VmOperation:                       0x180
    VmOperationEvent:                  0x184
    PageDirectoryPte:                  0x1f0
    LastFaultCount:                    0x18c
    VadRoot:                           0x194
    VadHint:                           0x198
    CloneRoot:                         0x19c
    NumberOfPrivatePages:              0x1a0
    NumberOfLockedPages:               0x1a4
    ForkWasSuccessful:                 0x182
    ExitProcessCalled:                 0x1aa
    CreateProcessReported:             0x1ab
    SectionHandle:                     0x1ac
    Peb:                               0x1b0
    SectionBaseAddress:                0x1b4
    QuotaBlock:                        0x1b8
    LastThreadExitStatus:              0x1bc
    WorkingSetWatch:                   0x1c0
    InheritedFromUniqueProcessId:      0x1c8
    GrantedAccess:                     0x1cc
    DefaultHardErrorProcessing         0x1d0
    LdtInformation:                    0x1d4
    VadFreeHint:                       0x1d8
    VdmObjects:                        0x1dc
    DeviceMap:                         0x1e0
    ImageFileName[0]:                  0x1fc
    VmTrimFaultValue:                  0x20c
    Win32Process:                      0x214
    Win32WindowStation:                0x1c4

Additional Information

For information on the EPROCESS block, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!pte

Displays the Page Table Entry (PTE) and Page Directory Entry (PDE) for the specified address.

Syntax

!pte VirtualAddress
!pte PTE
!pte LiteralAddress 1
!pte StartAddress EndAddress

Parameters

VirtualAddress
Specifies the virtual address whose page table is desired.
PTE
Specifies the address of an actual PTE.
LiteralAddress 1
Specifies the address of an actual PTE or PDE.
StartAddress
(x86 target computer only) Specifies the first virtual address in a range. All page tables in this range will be displayed.
EndAddress
(x86 target computer only) Specifies the last virtual address in a range. All page tables in this range will be displayed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

If one parameter is supplied, and this parameter is an address in the region of memory where the page tables are stored, the debugger will treat this as the PTE parameter. This parameter will be taken as the actual address of the desired PTE, and the debugger will display this PTE and the corresponding PDE.

If one parameter is supplied, and this parameter is not an address in this region, the debugger will treat this as the VirtualAddress parameter. The PTE and PDE that hold the mapping for this address will be displayed.

If two parameters are supplied, and the second parameter is 1 (or any other small number), the debugger will treat the first parameter as LiteralAddress. This address will be intepreted as the actual address of a PTE, and also as the actual address of a PDE, and the corresponding (and possibly invalid) data will be shown.

(x86 target computer only) If two parameters are supplied, and the second parameter is greater than the first, the debugger will treat the two parameters as StartAddress and EndAddress. The command will then display the PTEs for each page in the specified memory range.

For a list of all system PTEs, use the !sysptes extension.

Here is an example from an x86 target computer:

kd> !pte 801544f4
801544F4  - PDE at C0300800        PTE at C0200550
          contains 0003B163      contains 00154121
        pfn 3b G-DA--KWV    pfn 154 G--A--KRV

The first line of this restates the virtual address being investigated. It then gives the virtual address of the PDE and the PTE, which contain information about the virtual-physical mapping of this address.

The second line gives the actual contents of the PDE and the PTE.

The third line takes these contents and analyzes them, breaking them into the page frame number (PFN) and the status bits.

See the !pfn extension or the Converting Virtual Addresses to Physical Addresses section for information on how to interpret and use the PFN.

On an x86 target computer, the status bits for the PDE and the PTE are as follows:

Bit (Set) | Bit (Clear) | Meaning
G | - | Global
L |  | Large page (only occurs in PDEs, never in PTEs)
D | - | Dirty
A | - | Accessed
N | - | Cache disabled
T | - | Write-through
U | K | Owner (user mode or kernel mode)
W | R | Writeable or read-only (for multiprocessor systems)
V |  | Valid (always set if !pte succeeded)

On an IA-64 target computer, the status bits for the PDE and the PTE are slightly different from those of the PPE. The IA-64 PPE bits are as follows:

Bit (Set) | Bit (Clear) | Meaning
V |  | Valid (always set if !pte succeeded)
U | K | Owner (user mode or kernel mode)
D | - | Dirty
A | - | Accessed
W | R | Writeable or read-only (for multiprocessor systems)
E | - | Execute
C | - | Copy on write

The IA-64 PDE and PTE bits are as follows:

Bit (Set) | Bit (Clear) | Meaning
V |  | Valid (always set if !pte succeeded)
U | K | Owner (user mode or kernel mode)
A | - | Accessed
- | D | Dirty
W | R | Writeable or read-only (for multiprocessor systems)
E | - | Execute
C | - | Copy on write

Additional Information

For information on page tables, page directories, and an explanation of the status bits, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!ptov

Displays the entire physical-to-virtual map for a given process.

Syntax

!ptov PFN

Parameters

PFN
Specifies the page frame number (PFN) of the directory base for the process. This is the same as the directory base without the final three hexadecimal digits (in other words, right-shifted 12 bits).

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Here is an example. First, use the !process extension to determine the directory base of the desired process:

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
....
PROCESS ff779190  SessionId: 0  Cid: 04fc    Peb: 7ffdf000  ParentCid: 0394
    DirBase: 098fd000  ObjectTable: e1646b30  TableSize:   8.
    Image: MyApp.exe

In this case, the directory base is 0x098FD000. Discard the three trailing zeros. The result is 0x098FD. This is the page frame number (PFN) of the directory base.

Pass this number to !ptov:

kd> !ptov 98fd
7119000 10000
a21a000 20000
6133000 12e000
9de9000 12f000
2b0c000 130000
87cd000 131000
aaf6000 140000
...     ...

The numbers in the left column are the physical addresses of each memory page that has a mapping for this process. The numbers in the right column are the virtual addresses to which they are mapped.

The total display is very long!

Additional Information

For related topics, see !vtop, !vpdd, and Converting Virtual Addresses to Physical Addresses. For information on page tables and page directories, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!qlocks

Displays the state of all queued spin locks.

Syntax

!qlocks

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This command is only useful on a multiprocessor system.

Additional Information

For information on spin locks, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!ready

Displays summary information about each thread in the system in a READY state.

Syntax

!ready [Flags]

Parameters

Flags
Specifies the level of detail to display. Flags can be any combination of the following bits. If Flags is 0, only a minimal amount of information is displayed. The default is 0x6.
Bit 1 (0x2)
Causes the display to include the thread's wait states.
Bit 2 (0x4)
If this is included without Bit 1 (0x2), this has no effect. If this is included along with Bit 1, the thread will be displayed with a stack trace.
Bit 3 (0x8)
(Windows XP and Windows .NET Server 2003 only) Causes the display of each function to include the return address, the stack pointer, and (on IA-64 systems) the bsp register value. The display of function arguments is suppressed.
Bit 4 (0x10)
(Windows XP and Windows .NET Server 2003 only) Causes the display of each function to include only the return address; arguments and stack pointers are suppressed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The output from this extension is similar to that of !thread, except that only ready threads are displayed, and they are sorted in order of decreasing priority.

Additional Information

For information on thread scheduling and the READY state, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!reg

Displays and searches through registry data.

Syntax

!reg kcb Address
!reg knode Address
!reg kbody Address
!reg kvalue Address
!reg cellindex HiveAddress Index
!reg baseblock HiveAddress
!reg seccache HiveAddress
!reg hashindex HashKey
!reg openkeys {HiveAddress|0}
!reg findkcb Path
!reg hivelist
!reg viewlist HiveAddress
!reg freebins HiveAddress
!reg freecells BinAddress
!reg dirtyvector HiveAddress
!reg freehints HiveAddress
!reg dumppool [s|r]

Parameters

kcb Address
Displays a registry key control block. Address specifies the address of the key control block.
knode Address
Displays a registry key node structure. Address specifies the address of the key node.
kbody Address
Displays a registry key body (KBODY) structure. Address specifies the address of the key body. (Registry key bodies are the actual objects associated with handles.)
kvalue Address
Displays a registry key value structure. Address specifies the address of the value.
cellindex HiveAddress Index
Displays the virtual address for a cell in a hive. HiveAddress specifies the address of the hive. Index specifies the cell index.
baseblock HiveAddress
Displays the base block for a hive (also known as the "hive header"). HiveAddress specifies the address of the hive.
seccache HiveAddress
Displays the security cache for a hive. HiveAddress specifies the address of the hive.
hashindex HashKey
Computes the hash index entry for a hash key. HashKey specifies the key.
openkeys { HiveAddress | 0 }
Displays all open keys in a hive. HiveAddress specifies the address of the hive. If zero is used instead, the entire registry hash table is displayed; this table contains all open keys in the registry.
findkcb Path
Displays the registry key control block corresponding to a registry path. Path specifies the full key path; this path must be present in the hash table.
hivelist
Displays a list of all hives in the system, along with detailed information on each hive.
viewlist HiveAddress
Displays all pinned and mapped views for a hive, with detailed information for each view. HiveAddress specifies the address of the hive.
freebins HiveAddress
Displays all free bins for a hive, with detailed information for each bin. HiveAddress specifies the address of the hive.
freecells BinAddress
Iterates through a bin and displays all free cells inside it. BinAddress specifies the address of the bin.
dirtyvector HiveAddress
Displays the dirty vector for a hive. HiveAddress specifies the address of the hive.
freehints HiveAddress
Displays free hints. HiveAddress specifies the address of the hive.
dumppool [ s | r ]
Displays registry-allocated paged pool. If s is specified, the list of registry pages will be saved to a temporary file. If r is specified, the registry page list will be restored from the previously-saved temporary file.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

To display formatted registry key information, use the !dreg extension instead.

Here are are some examples:

kd> !reg hivelist

-------------------------------------------------------------------------------------------------------------
| HiveAddr |Stable Length|Stable Map|Volatile Length|Volatile Map|MappedViews|PinnedViews|U(Cnt)| BaseBlock | FileName
-------------------------------------------------------------------------------------------------------------
| e16e7428 |       2000  | e16e7484 |          0    |  00000000  |        1  |        0  |     0| e101f000  | \Microsoft\Windows\UsrClass.dat
| e1705a78 |      77000  | e1705ad4 |       1000    |  e1705bb0  |       30  |        0  |     0| e101c000  | ttings\Administrator\ntuser.dat
| e13d4b88 |     814000  | e146a000 |       1000    |  e13d4cc0  |      255  |        0  |     0| e1460000  | emRoot\System32\Config\SOFTWARE
| e13ad008 |      23000  | e13ad064 |       1000    |  e13ad140  |        9  |        0  |     0| e145e000  | temRoot\System32\Config\DEFAULT
| e13b3b88 |       a000  | e13b3be4 |       1000    |  e13b3cc0  |        3  |        0  |     0| e145d000  | emRoot\System32\Config\SECURITY
| e142d008 |       5000  | e142d064 |          0    |  00000000  |        2  |        0  |     0| e145f000  | <UNKNOWN>
| e11e3628 |       4000  | e11e3684 |       3000    |  e11e3760  |        0  |        0  |     0| e11e4000  | <NONAME>
| e10168a8 |     1c1000  | e1016904 |      15000    |  e10169e0  |       66  |        0  |     0| e1017000  | SYSTEM
| e10072c8 |       1000  | e1007324 |          0    |  00000000  |        0  |        0  |     0| e1010000  | <NONAME>
-------------------------------------------------------------------------------------------------------------

kd> !reg hashindex e16e7428

CmpCacheTable = e100a000

Hash Index[e16e7428] : 5ac
Hash Entry[e16e7428] : e100b6b0

kd> !reg openkeys e16e7428

Index 68:      7bab7683 kcb=e13314f8 cell=00000740 f=00200004 \REGISTRY\USER\S-1-5-21-1715567821-413027322-527237240-500_Classes\CLSID
Index 7a1:      48a30288 kcb=e13a3738 cell=00000020 f=002c0004 \REGISTRY\USER\S-1-5-21-1715567821-413027322-527237240-500_Classes

Additional Information

For information on the registry and its components, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!regkcb

Displays registry key control blocks.

Syntax

Windows NT 4.0 Syntax

!regkcb

Windows 2000 Syntax

!regkcb Address

Parameters

Address
Specifies the address of the key control block.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | Not available

Comments

In Windows NT 4.0, this displays all outstanding registry key control blocks. In Windows 2000, this displays a specific registry key control block.

In Windows XP and Windows .NET Server 2003, the !reg extension command should be used instead.

Every registry key has a control block that contains properties such as its permissions.

Here is an example of this command in Windows NT 4.0:

kd> !regkcb
1 -  \REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM
1 -  \REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM\MultifunctionAdapter\0
1 -  \REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM\MultifunctionAdapter\1
1 -  \REGISTRY\Machine\System\ControlSet001\Control\Class
1 -  \REGISTRY\Machine\System\ControlSet001\Control\ServiceGroupOrder
1 -  \REGISTRY\Machine\System\ControlSet001\Control\ProductOptions
1 -  \REGISTRY\Machine\System\ControlSet001\Control\PriorityControl
3 -  \REGISTRY\Machine\System\ControlSet001\ENUM
....

Additional Information

For information on the registry and its components, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!rellist

Displays a Plug and Play relation list.

Syntax

!rellist Address [Flags]

Parameters

Address
Specifies the address of the relation list.
Flags
Specifies additional information to include in the display. This can be any combination of the following bits. The default is zero.
Bit 1 (0x2)
Causes the display to include the CM_RESOURCE_LIST. The display also includes the boot resources list, if it is available.
Bit 2 (0x4)
Causes the display to include the resource requirements list (IO_RESOURCE_LIST).
Bit 3 (0x8)
Causes the display to include the translated CM_RESOURCE_LIST.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

See Plug and Play Debugging for applications of this extension command. For information on these list structures, see the Windows DDK.


!running

Displays a list of running threads on all processors of the target computer.

Syntax

!running [-i] [-t]

Parameters

-i
Causes the display to include idle processors as well.
-t
Causes a stack trace to be displayed for each processor.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

With no options, !running will display the affinity of all active processors and all idle processors. For all active processors, it will also display the current and next thread fields from the process control block (PRCB) and the state of the sixteen built-in queued spin locks.

Here is an example from a multi-processor IA-64 system:

0: kd> !running

System Processors 3 (affinity mask)
  Idle Processors 0

     Prcb              Current           Next
  0  e0000000818f8000  e0000000818f9e50  e0000000866f12f0  ................
 1  e000000086f16010  e00000008620ebe0  e000000086eddbc0  .O..............

The sixteen characters at the end of each line indicate the built-in queued spin locks (the LockQueue entries in the PRCB). A period ( . ) that the lock is not in use; O means the lock is owned by this processor; and W means the processor is queued for the lock. To see more information on the spin lock queue, use !qlocks.

Here is an example that shows active and idle processors along with their stack traces:

0: kd> !running -it

System Processors f (affinity mask)
  Idle Processors f
All processors idle.

     Prcb      Current   Next
  0  ffdff120  805495a0            ................

ChildEBP RetAddr
8053e3f0 805329c2 nt!RtlpBreakWithStatusInstruction
8053e3f0 80533464 nt!_KeUpdateSystemTime+0x126
ffdff980 ffdff980 nt!KiIdleLoop+0x14

  1  f87e0120  f87e2e60            ................

ChildEBP RetAddr
f87e0980 f87e0980 nt!KiIdleLoop+0x14

  2  f87f0120  f87f2e60            ................

ChildEBP RetAddr
f87f0980 f87f0980 nt!KiIdleLoop+0x14

  3  f8800120  f8802e60            ................

ChildEBP RetAddr
f8800980 f8800980 nt!KiIdleLoop+0x14

Additional Information

For more information on debugging multiprocessor computers, see Multiprocessor Syntax.


!sel

The !sel extension command is obsolete. Use the DG (Display Selector) command instead.


!session

In Windows 2000, !session displays one or more user sessions, or displays a specified process running in multiple user sessions.

In Windows XP and Windows .NET Server 2003, !session controls the session context. It can also display a list of all user sessions.

Syntax

Windows 2000 Syntax

!session [SessionID [2 Image]]

Windows XP and Windows .NET Server 2003 Syntax

!session
!session -s DefaultSession
!session -?

Parameters

SessionID
(Windows 2000 only) Specifies the session ID for the session to be displayed. If this is omitted or equal to -1, all sessions are displayed.
2 Image
(Windows 2000 only) Specifies the image name of a process. All processes with this name that belong to the session specified by SessionID will be displayed. If Image is omitted, the csrss.exe process is displayed. Omitting this parameter is an easy way of listing all current user sessions, because every user session contains exactly one csrss.exe process.
-s DefaultSession
(Windows XP and Windows .NET Server 2003 only) Sets the session context to the specified value. If DefaultSession is -1, the session context is set to the current session.
-?
(Windows XP and Windows .NET Server 2003 only) Displays a short help text for this extension.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This is really two different extensions. The !session extension in Windows 2000 is used to display information about a user session.

The !session extension in Windows XP and Windows .NET Server 2003 is used to control the session context. Using !session with no parameters will display a list of active sessions on the target computer. Using !session /s DefaultSession will change the session context to the new default value.

When you set the session context, the process context is automatically changed to the active process for that session. You should always use .cache forcedecodeptes when this occurs.

For more details and a list of all the session-related extensions that are affected by the session context, see Changing Contexts.

Additional Information

For information on user sessions and the Session Manager (smss.exe), see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!spoolused

Displays memory use summaries for the paged pool owned by the specified session.

Syntax

!spoolused -p [-s Session] [TagString]]
!spoolused -?

Parameters

-p
This option is always required.
-s Session
Specifies the session that owns the pool to be displayed. Session is always interpreted as a decimal number. If Session equals -1, the current session is used. If Session equals -2, the session context is used.
TagString
Specifies the pool tag. TagString is a case-sensitive ASCII string. The asterisk (*) can be used to represent any number of characters; the question mark (?) can be used to represent exactly one character. Unless an asterisk is used, TagString must be exactly four characters in length.
-?
Displays a short help text.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

For information on sessions, see Changing Contexts. For information on memory pools and pool tags, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!sprocess

Displays information about the specified session process, or about all processes in the specified session.

Syntax

!sprocess Session [Flags [ImageName]]
!sprocess -?

Parameters

Session
Specifies the session that owns the desired process. Session is always interpreted as a decimal number. If Session equals -1 or is omitted, the current session is used. If Session equals -2, the session context is used.
Flags
Specifies the level of detail to display. Flags can be any combination of the following bits. If Flags is 0, only a minimal amount of information is displayed. The default is 0x7.
Bit 0 (0x1)
Causes the display to include time and priority statistics.
Bit 1 (0x2)
Causes the display to include a list of threads and events associated with the process, and their wait states.
Bit 2 (0x4)
Causes the display to include a list of threads associated with the process. If this is included without Bit 1 (0x2), each thread will be displayed on a single line. If this is included along with Bit 1, each thread will be displayed with a stack trace.
Bit 3 (0x8)
Causes the display of each function to include the return address, the stack pointer, and (on IA-64 systems) the bsp register value. The display of function arguments is suppressed.
Bit 4 (0x10)
Causes the display of each function to include only the return address; arguments and stack pointers are suppressed.
ImageName
Specifies the name of the process to be displayed. All processes whose executable image names match ImageName will be displayed. The image name must match that in the EPROCESS block — in general this is the executable name that was invoked to start the process, including the file extension (usually .exe), and truncated after the 15th character. There is no way to specify an image name that contains a space.
-?
Displays a short help text for this extension. This help text has some omissions.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The output of this extension is similar to that of !process, except that the addresses of _MM_SESSION_SPACE and _MMSESSION are displayed as well.

Additional Information

For information on sessions and processes in kernel mode, see Changing Contexts. For more information on analyzing processes and threads, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!srb

Displays information about a SCSI Request Block (SRB).

Syntax

!srb Address

Parameters

Address
Specifies the hexadecimal address of the SRB on the target computer.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

An SRB is a system-defined structure used to communicate I/O requests from a SCSI class driver to a SCSI port driver.

Additional Information

For information on SRBs, see the Windows DDK.


!stacks

Displays information about the current kernel stacks.

Syntax

!stacks Detail

Parameters

Detail
Specifies the level of detail to use in the display. The default is zero. Possible values include:
0
Causes the display to include a concise summary of the current kernel stacks.
1
Causes the display to include stacks which are currently paged out, as well as the current kernel stacks.
2
Causes the display to include paged out stacks, as well as full parameters for all stacks.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The !stacks extension gives a brief summary of the state of every thread. This can be used instead of the !process extension to get a quick overview of the system, especially when debugging multi-thread issues such as resource conflicts or deadlocks.

Here is an example of the simplest !stacks display:

kd> !stacks 0
Proc.Thread  .Thread  ThreadState  Blocker
                                     [System]
   4.000050  827eea10  Blocked    +0xfe0343a5

                                     [smss.exe]

                                     [csrss.exe]
  b0.0000a8  82723b70  Blocked    ntoskrnl!_KiSystemService+0xc4
  b0.0000c8  82719620  Blocked    ntoskrnl!_KiSystemService+0xc4
  b0.0000d0  827d5d50  Blocked    ntoskrnl!_KiSystemService+0xc4
.....

The first column shows the process ID and the thread ID (separated by a period).

The second column is the current address of the thread.

The third column shows the state of the thread (initialized, ready, running, standby, terminated, transition, or blocked).

The fourth column shows the top address on the thread's stack.

Here are some examples of more detailed !stacks output:

kd> !stacks 1
Proc.Thread  .Thread  ThreadState  Blocker
                                     [System]
   4.000008  827d0030  Blocked    ntoskrnl!MmZeroPageThread+0x66
   4.000010  827d0430  Blocked    ntoskrnl!ExpWorkerThread+0x189
   4.000014  827cf030  Blocked    Stack paged out
   4.000018  827cfda0  Blocked    Stack paged out
   4.00001c  827cfb10  Blocked    ntoskrnl!ExpWorkerThread+0x189
.....
                                     [smss.exe]
  9c.000098  82738310  Blocked    Stack paged out
  9c.0000a0  826a5190  Blocked    Stack paged out
  9c.0000a4  82739d30  Blocked    Stack paged out

                                     [csrss.exe]
  b0.0000bc  826d0030  Blocked    Stack paged out
  b0.0000b4  826c9030  Blocked    Stack paged out
  b0.0000a8  82723b70  Blocked    ntoskrnl!_KiSystemService+0xc4
.....

kd> !stacks 2
Proc.Thread  .Thread  ThreadState  Blocker
                                     [System]
   4.000008  827d0030  Blocked    ntoskrnl!KiSwapThread+0xc5
                                  ntoskrnl!KeWaitForMultipleObjects+0x2b4
                                  ntoskrnl!MmZeroPageThread+0x66
                                  ntoskrnl!Phase1Initialization+0xd82
                                  ntoskrnl!PspSystemThreadStartup+0x4d
                                  ntoskrnl!CreateSystemRootLink+0x3d8
                                  +0x3f3f3f3f
   4.000010  827d0430  Blocked    ntoskrnl!KiSwapThread+0xc5
                                  ntoskrnl!KeRemoveQueue+0x191
.....

Additional Information

For information on kernel stacks, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!sysptes

Displays a formatted view of the system page table entries (PTEs).

Syntax

!sysptes [Flags]

Parameters

Flags
Specifies the level of detail to display. Flags can be any combination of the following bits. The default is zero:
Bit 0 (0x1)
Causes the display to include information on free PTEs.
Bit 1 (0x2)
(Windows NT 4.0 and Windows 2000 only) Causes the display to include unused pages in the page usage statistics.
Bit 2 (0x4)
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Causes the display to include detailed information about any system PTEs that are allocated to mapping locked pages.)
Bit 3 (0x8)
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Displays nonpaged pool expansion free PTE information. If this bit is set, the other lists are not displayed. If both 0x1 and 0x8 are set, all nonpaged pool expansion free PTEs are listed. If only 0x8 is set, just the total is displayed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

To examine a specific PTE, use the !pte extension.

Here is an example from a Windows 2000 system:

kd> !sysptes 1

System PTE Information
  Total System Ptes 50962
     SysPtes list of size   1 has 389 free
     SysPtes list of size   2 has  95 free
     SysPtes list of size   4 has  55 free
     SysPtes list of size   8 has  35 free
     SysPtes list of size  16 has  27 free

    starting PTE: c03c7000
    ending PTE:   c03f8c44

loading (99% complete)

      free ptes: c03c8d60   number free: 45134.

  free blocks: 1   total free: 45134    largest free block: 45134

     Page    Count
       a0        2.
       a1        2.
       a2        2.
       a3        2.
......

In Windows XP and Windows .NET Server 2003, the display is similar, except that the page count statistics at the end are not included.

Additional Information

For information on page tables and PTEs, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!thread

Displays summary information about a thread on the target system.

This extension command should not be confused with the .thread (Set Register Context) command.

Syntax

!thread [Address [Flags]]

Parameters

Address
Specifies the hexadecimal address of the thread on the target computer. If Address is -1 or omitted, it indicates the current thread.
Flags
Specifies the level of detail to display. Flags can be any combination of the following bits. If Flags is 0, only a minimal amount of information is displayed. The default is 0x6:
Bit 1 (0x2)
Causes the display to include the thread's wait states.
Bit 2 (0x4)
If this is included without Bit 1 (0x2), this has no effect. If this is included along with Bit 1, the thread will be displayed with a stack trace.
Bit 3 (0x8)
(Windows XP and Windows .NET Server 2003 only) Causes the display of each function to include the return address, the stack pointer, and (on IA-64 systems) the bsp register value. The display of function arguments is suppressed.
Bit 4 (0x10)
(Windows XP and Windows .NET Server 2003 only) Causes the display of each function to include only the return address; arguments and stack pointers are suppressed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This command can only be used during kernel-mode debugging. It shows the contents of an ETHREAD block.

Here is an example from a Windows 2000 system:

kd> !thread ff8632c0
THREAD ff8632c0  Cid 38c.380  Teb: 7ffde000  Win32Thread: e1bc1a08 WAIT: (WrUserRequest) UserMode Non-Alertable
    ff8543e0  SynchronizationEvent
Not impersonating
Owning Process ff89c7a0
WaitTime (seconds)      16923
Context Switch Count    67                   LargeStack
UserTime                  0:00:00.0000
KernelTime                0:00:00.0093
Start Address 0x77e878c1
Win32 Start Address 0x01003dd0
Stack Init fd536000 Current fd535c20 Base fd536000 Limit fd531000 Call 0
Priority 12 BasePriority 8 PriorityDecrement 0 DecrementCount 0

ChildEBP RetAddr  Args to Child
fd535c38 8012d61c 00000000 e1bc1a08 00000001 ntoskrnl!KiSwapThread+0xc5
fd535cbc 801672a2 00000001 00000001 000021bf ntoskrnl!KeWaitForSingleObject+0x1a1
fd535d4c 80161691 0006ff08 00000000 00000000 ntoskrnl!ExFreePool+0xb
fd535d4c a01772a8 0006ff08 00000000 00000000 ntoskrnl!KiSystemService+0xc4
ffffffff 00000000 00000000 00000000 00000000 +0xa01772a8

The important information in the !thread display is listed in the following table.

Parameter | Meaning
Thread address | The hexadecimal number after the word THREAD is the address of the ETHREAD block. In the preceding example, the thread address is 0xFF8632C0.
Thread ID | The hexadecimal number after the word Cid is the thread. In the preceding example, the thread ID is 0x38C, or decimal 908.
Thread Environment Block (TEB) | The hexadecimal number after the word Teb is the address of the thread environment block. In the preceding example, the TEB is located at address 0x7FFDE000.
System Service Dispatch Table | The hexadecimal number after the word Win32Thread is the address of the system service dispatch table. In the preceding example, the system dispatch table is located at address 0xE1BC1A08.
Thread State | The thread state is displayed at the end of the line which begins with the word WAIT. In the preceding example, the thread is in a non-alertable state.
Owning Process | The hexadecimal number after the words Owning Process gives the address of the EPROCESS for the process that owns this thread.
Start Address | The hexadecimal number after the words Start Address gives the thread start address. This may be given in symbolic form as well.
User Thread Function | The hexadecimal number after the words Win32 Start Address gives the address of the user thread function.
Priority | The priority information for the thread follows the word Priority.
Stack trace | A stack trace for the thread appears at the end of this display.

Additional Information

For information on threads in kernel mode, see Changing Contexts. For more information on analyzing processes and threads, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!threadfields

Displays the names and offsets of the fields within the executive thread (ETHREAD) block.

Syntax

!threadfields

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | Not available (see the Comments section)

Comments

This extension command is not available in Windows XP or Windows .NET Server 2003. Instead, use the DT (Display Type) command to show the ETHREAD structure directly:

kd> dt nt!_ETHREAD

Here is an example of !threadfields from a Windows 2000 system:

kd> !threadfields
 ETHREAD structure offsets:

    Tcb:                           0x0
    CreateTime:                    0x1b0
    ExitTime:                      0x1b8
    ExitStatus:                    0x1c0
    PostBlockList:                 0x1c4
    TerminationPortList:           0x1cc
    ActiveTimerListLock:           0x1d4
    ActiveTimerListHead:           0x1d8
    Cid:                           0x1e0
    LpcReplySemaphore:             0x1e8
    LpcReplyMessage:               0x1fc
    LpcReplyMessageId:             0x200
    ImpersonationInfo:             0x208
    IrpList:                       0x20c
    TopLevelIrp:                   0x214
    ReadClusterSize:               0x21c
    ForwardClusterOnly:            0x220
    DisablePageFaultClustering:    0x221
    DeadThread:                    0x222
    HasTerminated:                 0x224
    GrantedAccess:                 0x228
    ThreadsProcess:                0x22c
    StartAddress:                  0x230
    Win32StartAddress:             0x234
    LpcExitThreadCalled:           0x238
    HardErrorsAreDisabled:         0x239

Additional Information

For information on the ETHREAD block, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!time

The !time extension command is obsolete. Use the .time (Display System Time) command instead.


!timer

Displays a detailed listing of all system timer use.

Syntax

!timer

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The !timer extension displays the timer tree, which stores all timer objects in the system.

Here is an example:

kd> !timer
Dump system timers

Interrupt time: 9f760774 00000000 [12/ 8/2000 10:59:22.685 (Pacific Standard Time)]

List Timer    Interrupt Low/High     Fire Time              DPC/thread
  0 8016aea0 P 9fbd8e00 00000000 [12/ 8/2000 10:59:23.154]  ntoskrnl!PopScanIdleList
  1 8257f118   e4e4225a 00000000 [12/ 8/2000 11:01:19.170]  thread 8257f030
  3 80165fc0   286be1c9 0000594a [ 4/ 1/2001 01:59:59.215]  ntoskrnl!ExpTimeZoneDpcRoutine
    80165f40   2a7bf8d9 006f105e [12/31/2099 23:59:59.216]  ntoskrnl!ExpCenturyDpcRoutine
  5 825a0bf8   a952e1c2 00000000 [12/ 8/2000 10:59:39.232]  thread 825a0b10
 10 8251c7a8   41f54d84 00000001 [12/ 8/2000 11:03:55.310]  thread 8251c6c0
    8249fe88   41f54d84 00000001 [12/ 8/2000 11:03:55.310]  thread 8249fda0
 11 8250e7e8   bc73ffde 00000000 [12/ 8/2000 11:00:11.326]  thread 8250e700

.....

237 82757070   9f904152 00000000 [12/ 8/2000 10:59:22.857]  +f7a56f2e
    82676348   9f904152 00000000 [12/ 8/2000 10:59:22.857]  +fe516352
    82728b78   9f904152 00000000 [12/ 8/2000 10:59:22.857]  +fe516352
238 fe4b5d78   9f92a3ac 00000000 [12/ 8/2000 10:59:22.873]  thread 827ceb10
    801658f0   9f92a3ac 00000000 [12/ 8/2000 10:59:22.873]  ntoskrnl!CcScanDpc
239 8259ad40   765a6f19 00000bba [12/23/2000 09:07:22.900]  thread 825d3670
250 826d42f0   1486bed8 80000000 [         NEVER         ]  thread 825fa030

Total Timers: 193, Maximum List: 7
Current Hand: 226, Maximum Search: 0

Wakeable timers:

Additional Information

For information on timer objects, see the Windows DDK.


!tokenfields

Displays the names and offsets of the fields within the access token object (the TOKEN structure).

Syntax

!tokenfields

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | Not available (see the Comments section)

Comments

This extension command is not available in Windows XP or Windows .NET Server 2003. Instead, use the DT (Display Type) command to show the TOKEN structure directly:

kd> dt nt!_TOKEN

To see a specific instance of the TOKEN structure, use the !token extension.

Here is an example of !tokenfields from a Windows 2000 system:

kd> !tokenfields
 TOKEN structure offsets:
    TokenSource:           0x0
    AuthenticationId:      0x18
    ExpirationTime:        0x28
    ModifiedId:            0x30
    UserAndGroupCount:     0x3c
    PrivilegeCount:        0x44
    VariableLength:        0x48
    DynamicCharged:        0x4c
    DynamicAvailable:      0x50
    DefaultOwnerIndex:     0x54
    DefaultDacl:           0x6c
    TokenType:             0x70
    ImpersonationLevel:    0x74
    TokenFlags:            0x78
    TokenInUse:            0x79
    ProxyData:             0x7c
    AuditData:             0x80
    VariablePart:          0x84

Additional Information

For information on the TOKEN structure, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich. (The user-mode token structures described in the Platform SDK are slightly different.)


!trap

The !trap extension command is obsolete. Use the .trap (Display Trap Frame) command instead.


!tss

The !tss extension command is obsolete. Use the .tss (Display Task State Segment) command instead.


!ubc

Clears a user-space breakpoint.

Syntax

!ubc BreakpointNumber

Parameters

BreakpointNumber
Specifies the number of the breakpoint to be cleared. An asterisk (*) indicates all breakpoints.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This will permanently delete a breakpoint set with !ubp.

See Also

!ubd, !ube, !ubl, !ubp


!ubd

Temporarily disables a user-space breakpoint.

Syntax

!ubd BreakpointNumber

Parameters

BreakpointNumber
Specifies the number of the breakpoint to be disabled. An asterisk (*) indicates all breakpoints.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Disabled breakpoints will be stepped over. Use !ube to re-enable the breakpoint.

See Also

!ubc, !ube, !ubl, !ubp


!ube

Re-enables a user-space breakpoint.

Syntax

!ube BreakpointNumber

Parameters

BreakpointNumber
Specifies the number of the breakpoint to be enabled. An asterisk (*) indicates all breakpoints.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This is used to re-enable a breakpoint that was disabled by !ubd.

See Also

!ubc, !ubd, !ubl, !ubp


!ubl

Lists all user-space breakpoints and their current status.

Syntax

!ubl

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Here is an example of the use and display of user-space breakpoints:

kd> !ubp 8014a131
This command is VERY DANGEROUS, and may crash your system!
If you don't know what you are doing, enter "!ubc *" now!

kd> !ubp 801544f4

kd> !ubd 1

kd> !ubl
 0: e ffffffff`8014a131 (ffffffff`82deb000) 1 ffffffff
 1: d ffffffff`801544f4 (ffffffff`82dff000) 0 ffffffff

Each line in this listing contains the breakpoint number, the status (e for enabled or d for disabled), the virtual address used to set the breakpoint, the physical address of the actual breakpoint, the byte position, and the contents of this memory location at the time the breakpoint was set.

See Also

!ubc, !ubd, !ube, !ubp


!ubp

Sets a breakpoint in user space.

Syntax

!ubp Address

Parameters

Address
Specifies the hexadecimal virtual address of the location in user space where the breakpoint is to be set.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The !ubp extension sets a breakpoint in user space. The breakpoint is set on the actual physical page, not just the virtual page.

Setting a physical breakpoint will simultaneously modify every virtual copy of a page, with unpredictable results. One possible consequence is corruption of the system state, possibly followed by a bug check or other system crash. Therefore, these breakpoints should be used cautiously, if at all.

This extension cannot be used to set breakpoints on pages that have been swapped out of memory. If a page is swapped out of memory after a breakpoint is set, the breakpoint will cease to exist.

It is not possible to set a breakpoint inside a page table or a page directory.

Each breakpoint is assigned a breakpoint number. To find out the breakpoint number assigned, use !ubl. Breakpoints are enabled upon creation. To step over a breakpoint, you must first disable it by using !ubd. To clear a breakpoint, use !ubc.

See Also

!ubc, !ubd, !ube, !ubl


!urb

Displays the USB request block (URB) at the specified address.

Syntax

!urb Address

Parameters

Address
Specifies the hexadecimal address of the URB structure.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | Not available

Comments

The !urb extension is not available in Windows XP and later versions of Windows.

Additional Information

For information on URBs, see the Windows DDK.


!vad

Displays details of the virtual address descriptor (VAD) for one or more virtual addresses.

Syntax

!vad VAD-Root [Flags]

Parameters

VAD-Root
Specifies the hexadecimal address of the root of the VAD tree to be displayed.
Flags
Specifies the form the display will take. Possible values include:
0
The entire VAD tree based at VAD-Root will be displayed. (This is the default.)
1
Only the VAD specified by VAD-Root will be displayed. The display will include a more detailed analysis.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The address of the root of the VAD for any process can be found by using the !process command.

Here is an example of the !vad extension:

kd> !vad 824bc2f8
VAD     level      start      end    commit
82741bf8 ( 1)      78000    78045         8 Mapped  Exe  EXECUTE_WRITECOPY
824ef368 ( 2)      7f6f0    7f7ef         0 Mapped       EXECUTE_READ
824bc2f8 ( 0)      7ffb0    7ffd3         0 Mapped       READONLY
8273e508 ( 2)      7ffde    7ffde         1 Private      EXECUTE_READWRITE
82643fc8 ( 1)      7ffdf    7ffdf         1 Private      EXECUTE_READWRITE

Total VADs:     5  average level:    2  maximum depth: 2

kd> !vad 824bc2f8 1

VAD @ 824bc2f8
  Start VPN:         7ffb0  End VPN:    7ffd3  Control Area:  827f1208
  First ProtoPte: e1008500  Last PTE e100858c  Commit Charge         0 (0.)
  Secured.Flink          0  Blink           0  Banked/Extend:        0 Offset 0
   ViewShare NoChange READONLY

SecNoChange

Additional Information

For information on virtual address descriptors, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!verifier

Displays the status of Driver Verifier and its actions.

Syntax

Windows 2000 Syntax

!verifier [Flags [Image]]

Windows XP and Windows .NET Server 2003 Syntax

!verifier [Flags [Image]]
!verifier [Flags [Quantity]]
!verifier ?

Parameters

Flags
Specifies what information will be displayed in the output from this command. (Regardless of the value of Flags, !verifier will display the Driver Verifier options that are active, along with statistics on pool allocations, IRQL raises, spin locks, and trims.) This can be any sum of the following bits; the default is 0:
Bit 0 (0x1)
Causes the display to include names of all drivers being verified. The number of bytes currently allocated to each driver from the nonpaged pool and the paged pool is also displayed.
Bit 1 (0x2)
Causes the display to include information about pools (pool size, headers, and pool tags). Information about outstanding memory allocations left by unloaded drivers is displayed as well. This flag has no effect unless bit 0 (0x1) is set as well.
Bit 2 (0x4)
(Windows XP and Windows .NET Server 2003 only; x86 target only) Causes the display to include fault injection information. The return address, symbol name, and displacement of the code requesting each allocation are displayed. If Flags is exactly 0x4 and the Quantity parameter is included, the number of these records displayed can be chosen. Otherwise, four records are displayed.
Bit 3 (0x8)
(Windows XP and Windows .NET Server 2003 only) Causes the display to include the most recent IRQL changes made by the drivers being verified. The old IRQL, new IRQL, processor, and time stamp are displayed. If Flags is exactly 0x8 and the Quantity parameter is included, the number of these records displayed can be chosen. Otherwise, four records are displayed.
Image
If Flags is used and is not equal to 0x4 or 0x8, this specifies the name of a driver. This is used to filter the information displayed by Flags 0x1 and 0x2: only the specified driver is considered. This driver must be currently verified.
Quantity
(Windows XP and Windows .NET Server 2003 only) If Flags is exactly equal to 0x4, this specifies the number of fault injection records to display. If Flags is exactly equal to 0x8, this specifies the number of IRQL log entries to display.
?
(Windows XP and Windows .NET Server 2003 only) Causes a short help text to be displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

When using Driver Verifier to test graphics drivers, use the !gdikdx.verifier extension instead of !verifier.

Here is an example from a Windows XP system. Note how the display is sorted by driver name:

kd> !verifier 0xf

Verify Level 1f ... enabled options are:
      special pool
      special irql
      inject random pool failures
      all pool allocations checked on unload
      Io subsystem checking enabled

Summary of All Verifier Statistics

RaiseIrqls                             0x0
AcquireSpinLocks                       0x22a
Synch Executions                       0xbcd7
Trims                                  0x20e

Pool Allocations Attempted             0x48
Pool Allocations Succeeded             0x48
Pool Allocations Succeeded SpecialPool 0x48
Pool Allocations With NO TAG           0x0
Pool Allocations Failed                0x0
Pool Allocations Failed Deliberately   0x0

Current paged pool allocations         0x8 for 000002D8 bytes
Peak paged pool allocations            0xa for 00000494 bytes
Current nonpaged pool allocations      0xb for 00003038 bytes
Peak nonpaged pool allocations         0xb for 00003038 bytes

Driver Verification List

Entry     State           NonPagedPool   PagedPool   Module

fe527df8 Loaded           00002094       000002b8    ftdisk.sys

Current Pool Allocations  00000007    00000005
Current Pool Bytes        000002b8    00002094
Peak Pool Allocations     00000009    00000005
Peak Pool Bytes           00000338    00002094

PoolAddress  SizeInBytes    Tag       CallersAddress
f7b1bff0     0x00000010     ScFt      fdbac7af
f7b1df88     0x00000078     ScFt      fdbb6e9f
f7bfbfd0     0x00000030     ScFt      fdbac7af
fe4e4000     0x00002000     ScFt      fdba01e6
f7c19ff8     0x00000004     ScFt      fdba2677
f7c2bfb0     0x00000050     ScFt      fdbac2c1
f7c2df60     0x000000a0     ScFt      fdba672e
f7c47fe0     0x00000020     ScFt      fdba6968
f7c73f60     0x000000a0     ScFt      fdba672e
f7c8dfe0     0x00000020     ScFt      fdba6968
f7cb9f60     0x000000a0     ScFt      fdba672e
f7cd3fe0     0x00000020     ScFt      fdba6968

fe527d68 Loaded           00000f84       00000000    i8042prt.sys

Current Pool Allocations  00000000    00000005
Current Pool Bytes        00000000    00000f84
Peak Pool Allocations     00000002    00000005
Peak Pool Bytes           000001bc    00000f84

PoolAddress  SizeInBytes    Tag       CallersAddress
f8a6ff40     0x000000c0     8042      fdde2eec
f8a71f88     0x00000074     8042      fdde2f3e
f8cf1b50     0x000004b0     8042      fdddf64c
f93bb6a0     0x00000960     8042      fdde0990
f93b9fc0     0x00000040     8042      fdddfd0e

fe527cd8 Loaded           00000020       00000020    flpydisk.sys

Current Pool Allocations  00000001    00000001
Current Pool Bytes        00000020    00000020
Peak Pool Allocations     00000001    00000001
Peak Pool Bytes           00000020    00000020

PoolAddress  SizeInBytes    Tag       CallersAddress
f93abfe0     0x00000020     Flop      fdf5dcb5
f93affe0     0x00000020     Flop      fdf5b75d

-----------------------------------------------
Fault injection trace log
-----------------------------------------------
No fault injection traces found.
-----------------------------------------------
Track irql trace log
-----------------------------------------------

Size of track irql queue is 0x80

Thread:             FFFFFFFFFE4FA880
Old irql:           0
New irql:           2
Processor:          0
Time stamp:         5B97C

    FFFFFFFF80535D9E ntoskrnl!VerifierKfAcquireSpinLock+0x28
    FFFFFFFFFDB9ED56 +0xfffffffffdb9ed56
    FFFFFFFFFDB9F2CA +0xfffffffffdb9f2ca
    FFFFFFFF804175BD ntoskrnl!IopfCallDriver+0x31
    FFFFFFFFFDBEA69B +0xfffffffffdbea69b

Thread:             FFFFFFFFFE4FA880
Old irql:           2
New irql:           0
Processor:          0
Time stamp:         5B979

    FFFFFFFF80535E57 ntoskrnl!VerifierKfReleaseSpinLock+0x67
    FFFFFFFFFDB9EEED +0xfffffffffdb9eeed
    FFFFFFFFFDB9F2CA +0xfffffffffdb9f2ca
    FFFFFFFF804175BD ntoskrnl!IopfCallDriver+0x31
    FFFFFFFFFDBEA69B +0xfffffffffdbea69b

Thread:             FFFFFFFFFE4FA880
Old irql:           0
New irql:           2
Processor:          0
Time stamp:         5B979

    FFFFFFFF80535D9E ntoskrnl!VerifierKfAcquireSpinLock+0x28
    FFFFFFFFFDB9ED56 +0xfffffffffdb9ed56
    FFFFFFFFFDB9F2CA +0xfffffffffdb9f2ca
    FFFFFFFF804175BD ntoskrnl!IopfCallDriver+0x31
    FFFFFFFFFDBEA69B +0xfffffffffdbea69b

Thread:             FFFFFFFFFE4FA880
Old irql:           2
New irql:           0
Processor:          0
Time stamp:         5B974

    FFFFFFFF80535E57 ntoskrnl!VerifierKfReleaseSpinLock+0x67
    FFFFFFFFFDB9EEED +0xfffffffffdb9eeed
    FFFFFFFFFDB9F2CA +0xfffffffffdb9f2ca
    FFFFFFFF804175BD ntoskrnl!IopfCallDriver+0x31
    FFFFFFFFFDBEA69B +0xfffffffffdbea69b

Additional Information

For information on Driver Verifier, see the Windows DDK.


!vm

Displays summary information about virtual memory use statistics on the target system.

Syntax

Windows NT 4.0 Syntax

!vm

Windows 2000, Windows XP, and Windows .NET Server 2003 Syntax

!vm [Flags]

Parameters

Flags
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) Specifies what information will be displayed in the output from this command. This can be any sum of the following bits. The default is 0, which causes the display to include system-wide virtual memory statistics as well as memory statistics for each process.
Bit 0 (0x1)
Causes the display to omit process-specific statistics.
Bit 1 (0x2)
Causes the display to include memory management thread stacks.
Bit 2 (0x4)
(Windows XP and Windows .NET Server 2003 only) Causes the display to include terminal server memory usage.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Here is an example of the short output produced when Flags is 1:

kd> !vm 1

*** Virtual Memory Usage ***
      Physical Memory:     16270   (   65080 Kb)
      Page File: \??\E:\pagefile.sys
         Current:     98304Kb Free Space:     61044Kb
         Minimum:     98304Kb Maximum:       196608Kb
      Available Pages:      5543   (   22172 Kb)
      ResAvail Pages:       6759   (   27036 Kb)
      Locked IO Pages:       112   (     448 Kb)
      Free System PTEs:    45089   (  180356 Kb)
      Free NP PTEs:         5145   (   20580 Kb)
      Free Special NP:       336   (    1344 Kb)
      Modified Pages:        714   (    2856 Kb)
      NonPagedPool Usage:    877   (    3508 Kb)
      NonPagedPool Max:     6252   (   25008 Kb)
      PagedPool 0 Usage:     729   (    2916 Kb)
      PagedPool 1 Usage:     432   (    1728 Kb)
      PagedPool 2 Usage:     436   (    1744 Kb)
      PagedPool Usage:      1597   (    6388 Kb)
      PagedPool Maximum:   13312   (   53248 Kb)
      Shared Commit:        1097   (    4388 Kb)
      Special Pool:          229   (     916 Kb)
      Shared Process:       1956   (    7824 Kb)
      PagedPool Commit:     1597   (    6388 Kb)
      Driver Commit:         828   (    3312 Kb)
      Committed pages:     21949   (   87796 Kb)
      Commit limit:        36256   (  145024 Kb)

All memory use is listed in pages and in kilobytes. The most useful information in this display is the following:

Parameter | Meaning
physical memory | Total physical memory in the system.
available pages | Number of pages of memory available on the system, both virtual and physical.
nonpaged pool usage | The amount of pages allocated to the nonpaged pool. The nonpaged pool is memory that cannot be swapped out to the paging file, so it must always occupy physical memory. If this number is too large, this is usually an indication that there is a memory leak somewhere in the system.

Additional Information

The !memusage extension command can be used to analyze physical memory usage. For more information on memory management, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!vpb

Displays a volume parameter block (VPB).

Syntax

!vpb Address

Parameters

Address
Specifies the hexadecimal address of the VPB.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Here is an example. First, we display the device tree with the !devnode extension:

kd> !devnode 0 1
Dumping IopRootDeviceNode (= 0x80e203b8)
DevNode 0x80e203b8 for PDO 0x80e204f8
  InstancePath is "HTREE\ROOT\0"
  State = DeviceNodeStarted (0x308)
  Previous State = DeviceNodeEnumerateCompletion (0x30d)
  DevNode 0x80e56dc8 for PDO 0x80e56f18
    InstancePath is "Root\dmio\0000"
    ServiceName is "dmio"
    State = DeviceNodeStarted (0x308)
    Previous State = DeviceNodeEnumerateCompletion (0x30d)
  DevNode 0x80e56ae8 for PDO 0x80e56c38
    InstancePath is "Root\ftdisk\0000"
    ServiceName is "ftdisk"
    State = DeviceNodeStarted (0x308)
    Previous State = DeviceNodeEnumerateCompletion (0x30d)
    DevNode 0x80e152a0 for PDO 0x80e15cb8
      InstancePath is "STORAGE\Volume\1&30a96598&0&Signature5C34D70COffset7E00Length60170A00"
      ServiceName is "VolSnap"
      TargetDeviceNotify List - f 0xe1250938  b 0xe14b9198
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
    .....

The last device node listed is a volume. Examine its physical device object (PDO) with the !devobj extension:

kd> !devobj 80e15cb8
Device object (80e15cb8) is for:
 HarddiskVolume1 \Driver\Ftdisk DriverObject 80e4e248
Current Irp 00000000 RefCount 14 Type 00000007 Flags 00001050
Vpb 80e15c30 DevExt 80e15d70 DevObjExt 80e15e40 Dope 80e15bd8 DevNode 80e152a0
ExtensionFlags (0000000000)
AttachedDevice (Upper) 80e14c60 \Driver\VolSnap
Device queue is not busy.

The address of this device's VPB is included in this listing. Use this address with the !vpb extension:

kd> !vpb 80e15c30
Vpb at 0x80e15c30
Flags: 0x1 mounted
DeviceObject: 0x80de5020
RealDevice:   0x80e15cb8
RefCount: 14
Volume Label:           MY-DISK-C

Additional Information

For information on VPBs, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!vpdd

Displays physical addresses, virtual addresses, and memory contents for the specified process.

Syntax

!vpdd Process VirtualAddress
!vpdd PID VirtualAddress

Parameters

Process
Specifies the address of the process whose memory is to be displayed.
PID
Specifies the PID (process ID) of the process whose memory is to be displayed.
VirtualAddress
Specifies the virtual address whose page is desired.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | Not available

Comments

Here is an example. Suppose you want to see the memory owned by the cmd.exe process stored at virtual address 0x4AD00000. First, use !process to determine the address of the process:

kd> !process 0 0
.......
PROCESS 810e0020  SessionId: 0  Cid: 04e4    Peb: 7ffdf000  ParentCid: 014c
    DirBase: 0268a000  ObjectTable: 810db008  TableSize:  22.
    Image: CMD.EXE

You can use either the process address (0x810E0020) or the PID (0x4E4) as the first parameter of !vpdd. The second parameter is the virtual address you wish to display:

kd> !vpdd  810e0020 4ad00000
00fcf000 4ad00000  00905a4d 00000003 00000004 0000ffff
00fcf010 4ad00010  000000b8 00000000 00000040 00000000
00fcf020 4ad00020  00000000 00000000 00000000 00000000
00fcf030 4ad00030  00000000 00000000 00000000 000000d0
00fcf040 4ad00040  0eba1f0e cd09b400 4c01b821 685421cd
00fcf050 4ad00050  70207369 72676f72 63206d61 6f6e6e61
00fcf060 4ad00060  65622074 6e757220 206e6920 20534f44
00fcf070 4ad00070  65646f6d 0a0d0d2e 00000024 00000000

In this display, the first column shows the physical address and the second column shows the virtual address. The remainder of the line shows the memory data stored in this location, in the form of four DWORDs.

Additional Information

For related topics, see !vtop, !ptov, and Converting Virtual Addresses to Physical Addresses. For information on page tables and page directories, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!vtop

Converts a virtual address to the corresponding physical address, and displays other page table and page directory information.

Syntax

Windows 2000 Syntax

!vtop DirBase VirtualAddress
!vtop PFN VirtualAddress

Windows XP and Windows .NET Server 2003 Syntax

!vtop DirBase VirtualAddress
!vtop PFN VirtualAddress
!vtop 0 VirtualAddress

Parameters

DirBase
Specifies the directory base for the process. Each process has its own virtual address space. Use the !process extension to determine the directory base for a process.
PFN
Specifies the page frame number (PFN) of the directory base for the process. This is the same as the directory base without the final three hexadecimal digits (in other words, right-shifted 12 bits).
0
(Windows XP and Windows .NET Server 2003 only) Causes !vtop to use the current process context for address translation.
VirtualAddress
Specifies the virtual address whose page is desired.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The first parameter can be either the PFN of the directory base or the full directory base. In hexadecimal, these numerals are identical except for the trailing three zeros.

Here is an example:

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
....
PROCESS ff779190  SessionId: 0  Cid: 04fc    Peb: 7ffdf000  ParentCid: 0394
    DirBase: 098fd000  ObjectTable: e1646b30  TableSize:   8.
    Image: MyApp.exe

kd> !vtop 98fd000 12f980
Pdi 0 Pti 12f
0012f980 09de9000 pfn(09de9)

kd> !vtop 98fd 12f980
Pdi 0 Pti 12f
0012f980 09de9000 pfn(09de9)

Notice how the trailing three zeros are optional. The !vtop extension displays the page directory index (PDI), the page table index (PTI), the virtual address that you had originally input, the physical address of the beginning of the physical page, and the page frame number (PFN) of the page table entry (PTE).

If you want to convert the virtual address 0x0012F980 to a physical address, you simply have to take the last three hexadecimal digits (0x980) and add them to the physical address of the beginning of the page (0x09DE9000). This gives the physical address 0x09DE9980.

Additional Information

For other methods of achieving these results, see Converting Virtual Addresses to Physical Addresses. Also see !ptov and !vpdd. For information on page tables and page directories, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!wdmaud

Displays a variety of WDM Audio (WDMAud) structures.

Syntax

!wdmaud Address Flags

Parameters

Address
Specifies the address of the structure to be displayed.
Flags
Specifies the information to display. This must include exactly one of the bits 0x1, 0x2, 0x4, and 0x8. The 0x100 bit can be added to any of these.
Bit 0 (0x1)
Displays a list of all IOCTLs that have been sent to wdmaud.sys. When this is used, Address should specify the address of the WdmaIoctlHistoryListHead. If the 0x100 bit is set, the display will also include the pContext that each IOCTL was sent with.
Bit 1 (0x2)
Displays a list of all IRPs that WDMAud has marked as pending. When this is used, Address should specify the address of the WdmaPendingIrpListHead. If the 0x100 bit is set, the display will also include the context on which each IRP was allocated.
Bit 2 (0x4)
Displays a list of all MDLs that WDMAud has allocated. When this is used, Address should specify the address of the WdmaAllocatedMdlListHead. If the 0x100 bit is set, the display will also include the context on which each MDL was allocated.
Bit 3 (0x8)
Displays a list of all active contexts attached to wdmaud.sys. When this is used, Address should specify the address of the WdmaContextListHead. If the 0x100 bit is set, the display will also include the data members of each context structure.
Bit 8 (0x100)
Causes the display to include verbose information.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The contexts attached to wdmaud.sys (pContext) contain most of the state data for each device. Whenever wdmaud.drv is loaded into a new process, wdmaud.sys will be notified of its arrival. Whenever wdmaud.drv is unloaded, wdmaud.sys cleans up any allocations made in that context.

Additional Information

For information on WDM audio architecture and audio drivers, see the Windows DDK.


!wsle

Displays all working set list entries (WSLEs).

Syntax

Windows NT 4.0 and Windows 2000 Syntax

!wsle [DisplayMode [Address]]

Windows XP and Windows .NET Server 2003 Syntax

!wsle [Flags [Address]]

Parameters

DisplayMode
(Windows NT 4.0 and Windows 2000 only) Specifies the information to include in the display. This can be any single one of the following values. The default is zero:
0
Displays only basic information about the working set list.
7
Displays basic information about the working set list, plus information about each WSLE's address, age, lock status, and reference count. If a WSLE has an invalid page table entry (PTE) or page directory entry (PDE) associated with it, this is displayed as well.
8
Displays basic information about the working set list, plus the index and value of each WSLE.
Flags
(Windows XP and Windows .NET Server 2003 only) Specifies the information to include in the display. This can be any combination of the following bits. The default is zero — if this is used, only basic information about the working set is displayed.
Bit 0 (0x1)
Causes the display to include information about each WSLE's address, age, lock status, and reference count. If a WSLE has an invalid page table entry (PTE) or page directory entry (PDE) associated with it, this is displayed as well.
Bit 1 (0x2)
Causes the display to include the total number of valid WSLEs, the index of the last WSLE, and the index of the first free WSLE.
Address
Specifies the address of the working set list. If this is omitted, the default working set list is used. (In Windows NT 4.0 and Windows 2000, specifying -1 for Address is the same as omitting it. In Windows XP and Windows .NET Server 2003, specifying zero for Address is the same as omitting it.)

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This extension can take a significant amount of time to execute.

Here is an example from an x86 target computer running Windows .NET Server 2003:

kd> !wsle 3

Working Set @ c0503000
    FirstFree:       a7  FirstDynamic:          4
    LastEntry      23d  NextSlot:         4  LastInitialized      259
    NonDirect       65  HashTable:        0  HashTableSize:         0

Reading the WSLE data...

Virtual Address           Age  Locked  ReferenceCount
        c0300203          0        1        1
        c0301203          0        1        1
        c0502203          0        1        1
        c0503203          0        1        1
        c01ff201          0        0        1
        77f74d19          3        0        1
        7ffdfa01          2        0        1
        c0001201          0        0        1

.....

Reading the WSLE data...
Valid WSLE entries = 0xa7
found end @ wsle index 0x259

.....

Additional Information

For information on working sets, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!zombies

Displays all dead ("zombie") processes or threads.

Syntax

!zombies [Flags [RestartAddress]]

Parameters

Flags
Specifies what will be displayed. Possible values include:
1
Displays all zombie processes. (This is the default.)
2
Displays all zombie threads.
RestartAddress
Specifies the hexadecimal address at which to begin the search. This is useful if the previous search was terminated prematurely. The default is zero.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Zombie processes are dead processes which have not yet been removed from the process list. Zombie threads are analogous.

To see a list of all processes and threads, use the !process extension.

Additional Information

For information on processes and threads in kernel mode, see Changing Contexts. For more information on analyzing processes and threads, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


User-Mode Extensions

This section of the reference describes extension commands which are primarily used during user-mode debugging.

The debugger should automatically load the proper version of the extension commands; you do not normally have to keep track of the DLL versions being used. See Using Debugger Extension Commands for a description of the default module search order.

If you have unloaded the necessary extension DLL, or have changed the default DLL, you may need to specify the correct file. See Loading Debugger Extension DLLs for an explanation of how to load extension modules.

Each extension command reference page lists the DLLs which expose that command. Use the following rules to determine the proper directory from which to load this extension DLL:

  • If the target application is running on the free build of Windows® NT® 4.0, use nt4fre\ntsdexts.dll.
  • If your target application is running on the checked build of Windows NT 4.0, use nt4chk\ntsdexts.dll.
  • If your target application is running on the free build of Windows 2000, use w2kfre\ntsdexts.dll.
  • If your target application is running on the checked build of Windows 2000, use w2kchk\ntsdexts.dll.
  • If your target application is running on Windows XP or Windows .NET Server 2003, use winxp\ntsdexts.dll.

In addition, user-mode extensions that are not specific to any single operating system can be found in winext\uext.dll.


!avrf

Controls the settings of Application Verifier, and displays a variety of output produced by Application Verifier.

Syntax

!avrf
!avrf -hp { Length | -a Address }
!avrf -vs { Length | -a Address }
!avrf -ex [ Length ]
!avrf -cnt
!avrf -trm
!avrf -threads [ThreadID]
!avrf -trace TraceIndex
!avrf -brk
!avrf -brk BreakEventType
!avrf -flt
!avrf -flt EventType Probability
!avrf -flt break EventType
!avrf -flt stacks Length
!avrf -trg [ Start End | dll Module | all ]
!avrf -skp [ Start End | dll Module | all | Time ]

Parameters

-hp
Displays the heap operation log. For details and an example, see Heap Operation Logs.
-vs
Displays the virtual space operation log. For details and examples, see Virtual Space Operation Logs.
-ex
Displays the exception log. For details and an example, see Exception Logs.
Length
Specifies the number of records to display. If the -ex option is used, Length may be omitted; this causes all exceptions to be displayed.
-a Address
Specifies an address. Records of allocations containing this address will be displayed. Records of frees beginning with this address will be displayed.
-cnt
Displays a list of global counters.
-trm
Displays a log of all terminated and suspended threads.
-threads
Displays information about threads in the target process. For child threads, the stack size and the CreateThread flags specified by the parent are displayed as well.
ThreadID
Specifies the ID of the thread to display. If this is omitted, all threads are displayed.
-trace TraceIndex
Displays a stack trace for the specified TraceIndex. Some structures use this 16-bit index number to identify a stack trace; this index points to a location within the stack trace database. If you are analyzing such a structure, you will find this syntax useful.
-brk
Specifies that this is a break-event command. When !avrf -brk is used with no additional parameters, the break event settings are displayed. See Requesting Breaks on Certain Events for an example.
BreakEventType
Specifies the type number of the break event. For a list of possible types, see Requesting Breaks on Certain Events.
-flt
Specifies that this is a fault-injection command. When !avrf -flt is used with no additional parameters, the current fault injection settings are displayed. See Choosing Which Events to Fault for an example.
EventType
Specifies the type number of the event. For a list of possible types, see Choosing Which Events to Fault.
Probability
Specifies the frequency with which the event will fail. This can be any integer between 0 and 100 (0x64).
break
Causes Application Verifier to break into the debugger each time this fault is injected. See Choosing Which Events to Fault for an example of such a break.
stacks
Displays stack traces for the most recent fault-injected operations. See Choosing Which Events to Fault for an example.
-trg
Specifies that this is a target range command. When -trg is used with no additional parameters, the current target ranges are displayed. For details, see Choosing Where to Fault.
-skp
Specifies that this is a exclusion range command. When -trg is used with no additional parameters, the current target ranges are displayed. For details, see Choosing Where to Fault.
Start
Specifies the beginning address of the target range or exclusion range.
End
Specifies the ending address of the target range or exclusion range.
Module
Specifies the name of a module to be targetted or excluded. Module should include the full module name, including the .exe or .dll extension. Path information should not be included.
all
Causes all target ranges or exclusion ranges to be reset.
Time
Causes all faults to be suppressed for Time milliseconds after execution resumes.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | exts.dll

Additional Information

When the !avrf extension is used with no parameters, it displays the current Application Verifier options. If the Full page heap or Fast fill heap option has been enabled, information about active page heaps will be displayed as well. See Heap Operation Logs for some examples.

If an Application Verifier Stop has occurred, the !avrf extension with no parameters will reveal the nature of the stop and what caused it. See Debugging Application Verifier Stops for some examples.

If symbols for ntdll.dll and verifier.dll are missing, the !avrf extension will generate an error message. See Setting Up a Debugger for Application Verifier to address this problem.

Additional Information

For general information on Application Verifier, see Application Verifier or the Application Compatibility Toolkit.


!critsec

Displays a critical section.

Syntax

!critsec Address

Parameters

Address
Specifies the hexadecimal address of the critical section.

DLL

Windows NT 4.0 | ntsdexts.dll
Windows 2000 | ntsdexts.dll
Windows XP Windows .NET Server 2003 | ntsdexts.dll

Comments

If you don't know the address of the critical section, you should use the !ntsdexts.locks extension. This displays all critical sections which have been initialized by calling RtlInitializeCriticalSection.

Here is an example:

0:000> !critsec 3a8c0e9c

CritSec +3a8c0e9c at 3A8C0E9C
LockCount          1
RecursionCount     1
OwningThread       99
EntryCount         472
ContentionCount    1
*** Locked

Additional Information

For information on critical sections, see the Platform SDK, the Windows DDK, or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich. Also see !ntsdexts.locks and !cs.


!cs

Displays one or more critical sections, or the entire critical section tree.

Syntax

!cs [-s]
!cs [-s] [Address]
!cs [-s] StartAddress EndAddress
!cs [-s] -d InfoAddress
!cs [-s] -t [TreeAddress]
!cs -?

Parameters

-s
Causes each critical section's initialization stack trace to be displayed, if this is available.
Address
Specifies the address of the critical section to be displayed. If this omitted, all critical sections in the current process are displayed.
StartAddress
Specifies the beginning of the address range to be searched for critical sections.
EndAddress
Specifies the end of the address range to be searched for critical sections.
-d
Causes the debugger to display critical sections associated with DebugInfo.
InfoAddress
Specifies the address of the DebugInfo.
-t
Causes the debugger to display a critical section tree. Before the -t option can be used, Application Verifier must be activated for the target process, and the Check lock usage option must be selected. For more information, see Application Verifier.
TreeAddress
Specifies the address of the root of the critical section tree. If this is zero or omitted, the critical section tree for the current process is displayed.
-?
Causes a short help text for this extension to be displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | exts.dll

Comments

This extension requires full symbols (including type information) for the process being debugged and for ntdll.dll. If you do not have symbols for ntdll.dll, see Installing Windows Symbol Files.

Here are some examples. The following command will display information about the critical section at address 0x7803B0F8 and show its initialization stack trace:

0:001> !cs -s 0x7803B0F8
Critical section   = 0x7803B0F8 (MSVCRT!__app_type+0x4)
DebugInfo          = 0x6A262080
NOT LOCKED
LockSemaphore      = 0x0
SpinCount          = 0x0

Stack trace for DebugInfo = 0x6A262080:

0x6A2137BD: ntdll!RtlInitializeCriticalSectionAndSpinCount+0x9B
0x6A207A4C: ntdll!LdrpCallInitRoutine+0x14
0x6A205569: ntdll!LdrpRunInitializeRoutines+0x1D9
0x6A20DCE1: ntdll!LdrpInitializeProcess+0xAE5

The following command will display information about the critical section whose DebugInfo is at address 0x7803B0F8:

0:001> !cs -d 0x6A262080
DebugInfo          = 0x6A262080
Critical section   = 0x7803B0F8 (MSVCRT!__app_type+0x4)
NOT LOCKED
LockSemaphore      = 0x0
SpinCount          = 0x0

The following command will display information about all the active critical sections in the current process:

0:001> !cs
-----------------------------------------
DebugInfo          = 0x6A261D60
Critical section   = 0x6A262820 (ntdll!RtlCriticalSectionLock+0x0)
LOCKED
LockCount          = 0x0
OwningThread       = 0x460
RecursionCount     = 0x1
LockSemaphore      = 0x0
SpinCount          = 0x0
-----------------------------------------
DebugInfo          = 0x6A261D80
Critical section   = 0x6A262580 (ntdll!DeferedCriticalSection+0x0)
NOT LOCKED
LockSemaphore      = 0x7FC
SpinCount          = 0x0
-----------------------------------------
DebugInfo          = 0x6A262600
Critical section   = 0x6A26074C (ntdll!LoaderLock+0x0)
NOT LOCKED
LockSemaphore      = 0x0
SpinCount          = 0x0

.....

The following command displays the critical section tree:

0:000> !cs -t
Tree root 002528e0
Level     Node       CS    Debug    Enter     Wait TryEnter    Leave
--------------------------------------------------------------------
    0 002528e0 77ecb760 77fbcfe0        0        0        0        0
    1 00252940 77ecb078 77fbd020        0        0        0        0
    2 002529a0 77ecb340 77fbd060      708        0        0      708
    3 002529d0 77ecb6a0 77fbd080        0        0        0        0
    4 00252a00 77ecb3a0 77fbd0a0      708        0        0      708
    1 00252910 77ecb7e0 77fbd000        0        0        0        0
    2 00252a30 77ecb7c0 77fbd0c0        0        0        0        0
    2 00252970 77ecb860 77fbd040        0        0        0        0
    3 00252a60 77ecb800 77fbd0e0        0        0        0        0

Additional Information

For information on critical sections, see the Platform SDK, the Windows DDK, or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich. Also see !ntsdexts.locks and !critsec.


!dp (!ntsdexts.dp)

Displays a CSR process.

This extension command should not be confused with the DP (Display Memory) command, or with the !kdext*.dp extension command.

Syntax

!dp [v] [ PID | CSR-Process ]

Parameters

v
Verbose mode. Causes the display to include structure and thread list.
PID
Specifies the process ID of the CSR process.
CSR-Process
Specifies the hexadecimal address of the CSR process.

DLL

Windows NT 4.0 | ntsdexts.dll
Windows 2000 | ntsdexts.dll
Windows XP Windows .NET Server 2003 | ntsdexts.dll

Comments

This extension displays the process address, process ID, sequence number, flags, and reference count. If verbose mode is selected, additional details are displayed, and thread information is shown for each process.

If no process is specified, all processes are displayed.

See Also

!dt


!dphdump

Displays the debug page heap.

Syntax

!dphdump Address

Parameters

Address
Specifies the heap base address or heap handle.

DLL

Windows NT 4.0 | ntsdexts.dll
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | Not available

Comments

If you are investigating the page heap in Windows 2000 (Service Pack 1 or later), Windows XP, or Windows .NET Server 2003, you should use the !heap extension instead.

See Also

!dphfind, !dphflags, !dphhogs


!dphfind

Finds the debug page heap containing the specified address.

Syntax

!dphfind Address

Parameters

Address
Specifies a hexadecimal address that the debug page heap must contain.

DLL

Windows NT 4.0 | ntsdexts.dll
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | Not available

Comments

Address is typically the address of a fault that occurred when an application attempted to reference heap memory from a debug page heap allocation.

If you are investigating the page heap in Windows 2000 (Service Pack 1 or later), Windows XP, or Windows .NET Server 2003, you should use the !heap extension instead.

See Also

!dphdump, !dphflags, !dphhogs


!dphflags

Sets or displays the global page heap flags.

Syntax

!dphflags [FLAGS]

Parameters

FLAGS
Specifies a bit field containing any combination of the following bits:
Bit 0 (0x1)
Causes the debugger to enable page heap. (In 99% of the cases you will want this to be set. If this is zero, the standard heap is used.)
Bit 1 (0x2)
Causes the debugger to collect stack traces. (This is normally set on checked builds only.)
Bit 2 (0x4)
Causes the debugger to minimize memory impact.
Bit 3 (0x8)
Specifies the minimization method. If this bit is set, minimization is random. If it is zero, minimization is based on size range. (This setting is ignored unless bit 2 (0x4) is set.)
Bit 4 (0x10)
Causes the debugger to catch backward overruns.
Bits 15 to 8
Specifies the percentage of available memory (from total memory) below which allocations will be made from standard heap. Only has effect if bit 2 (0x4) is set.
Bits 31 to 16
Specifies the probability for page heap allocation. Only has effect if bits 2 (0x4) and 3 (0x8) are set. Two sizes should be specified: the smaller size in bits 31 to 24, the larger in bits 23 to 16. Allocations which have sizes between these two values will be allocated from the page heap.

DLL

Windows NT 4.0 | ntsdexts.dll
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | Not available

Comments

If you are investigating the page heap in Windows 2000 (Service Pack 1 or later), Windows XP, or Windows .NET Server 2003, you should use the !heap extension instead.

Here are some examples. The following command enables stack trace collections on free builds (where it is not the default):

!dphflags 0x03

The following command puts the inaccessible page at the beginning of the allocation, and enables stack traces:

!dphflags 0x13

The following command will allocate from the page heap with 48% probability. Also, if the available memory drops below 48%, then all allocations are made from the standard heap:

!dphflags 0x3000300F

See Also

!dphdump, !dphfind, !dphhogs


!dphhogs

Displays debug page heap hogs.

Syntax

!dphhogs Address [count] [reset]

Parameters

Address
Specifies the heap base address or heap handle.
count
Causes the list to be sorted by count (rather than by bytes).
reset
Causes all allocation counts to be reset to zero.

DLL

Windows NT 4.0 | ntsdexts.dll
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | Not available

Comments

This is only available on checked builds of Windows NT 4.0 running on x86 processors.

If you are investigating the page heap in Windows 2000 (Service Pack 1 or later), Windows XP, or Windows .NET Server 2003, you should use the !heap extension instead.

See Also

!dphdump, !dphfind, !dphflags


!dreg

Displays registry information.

Syntax

!dreg [-d|-w] KeyPath[!Value]
!dreg

Parameters

-d
Causes binary values to be displayed as DWORDs.
-w
Causes binary values to be displayed as WORDs.
KeyPath
Specifies the registry key path. It can begin with any of the following abbreviations:
hklm
HKEY_LOCAL_MACHINE
hkcu
HKEY_CURRENT_USER
hkcr
HKEY_CLASSES_ROOT
hku
HKEY_USERS

If no abbreviation is used, HKEY_LOCAL_MACHINE is assumed.

Value
Specifies the name of the registry value to be displayed. If an asterisk (*) is used, all values are displayed. If Value is omitted, all subkeys are displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | ntsdexts.dll
Windows XP Windows .NET Server 2003 | ntsdexts.dll

Comments

This extension is most useful during remote debugging, as it allows you to browse the registry of the remote machine. It is also useful when controlling the user-mode debugger from the kernel debugger, since you cannot run a standard registry editor on the target machine when it's frozen. (You can use the .sleep command for this purpose as well. See Controlling the User-Mode Debugger from the Kernel Debugger for details.)

It is also useful when debugging locally, as the information is presented in an easily-readable format.

To display raw registry information, use the !reg extension instead.

Here are some examples. The following will display all subkeys of the specified registry key:

!dreg hkcu\Software\Microsoft

The following will display all values in the specified registry key:

!dreg System\CurrentControlSet\Services\Tcpip!*

The following will display the value "Start" in the specified registry key:

!dreg System\CurrentControlSet\Services\Tcpip!Start

Typing !dreg without any arguments will display a short help text.

Additional Information

For information on the registry, see the Windows DDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!dt

Displays information about a CSR thread.

This extension command should not be confused with the DT (Display Type) command.

Syntax

!dt [v] CSR-Thread

Parameters

v
Verbose mode.
CSR-Thread
Specifies the hexadecimal address of the CSR thread.

DLL

Windows NT 4.0 | ntsdexts.dll
Windows 2000 | ntsdexts.dll
Windows XP Windows .NET Server 2003 | ntsdexts.dll

Comments

This extension displays the thread, process, client ID, flags, and reference count associated with the CSR thread. If verbose mode is selected, the display will also include list pointers, thread handle, and the wait block.

See Also

!dp (!ntsdexts.dp)


!evlog

Displays, changes, or backs up the event log.

Syntax

!evlog addsource [-d] [-s Source] [-t Type] [-f MsgFile]
!evlog backup [-d] [-l EventLog] [-f BackupFile]
!evlog clear [-!] [-d] [-l EventLog] [-f BackupFile]
!evlog info
!evlog option [-d] [-!] [-n Count] [ -l EventLog [ -+ | -r RecordBound ]] [-o Order] [-w Width]
!evlog read [-d] [-l EventLog] [-s Source] [-e ID] [-c Category] [-t Type] [-n Count] [-r Record]
!evlog report [-s Source] [-e ID] [-c Category] [-t Type] Message
!evlog [Option] -?

Parameters

addsource
Adds an event source to the registry. By default, this only adds events from the DebuggerExtensions source (to support !evlog report).
backup
Makes a backup of the specified event log and writes it to a file.
clear
Erases the specified event log, and optionally creates a file recording its old contents.
info
Displays summary information about the event log.
option
Sets the default search options. These options will be used in future !evlog read commands.
read
Displays a list of events logged to the specified event log. Details of this display — such as the number of records displayed and the chronological order of the display — can be controlled by the !evlog read parameters or by a previous use of !evlog option.
report
Writes an event record to the application event log.
-d
Specifies that all default values should be used. The -d option is only required if you are omitting all other parameters. However, with the !evlog option command this option displays the existing default settings.
-!
With !evlog option, this resets all defaults. With !evlog clear, this prevents a backup file from being written.
Source
Specifies the event source. The default value is DebuggerExtensions.
Type
Specifies the success type. Possible Type values are 1 (Error), 2 (Warning), 4 (Information), 8 (Audit_Success), or 16 (Audit_Failure). A value of 0 represents Success. For !evlog read and !evlog report the default is Success (0). For !evlog addsource these bits can be combined, and the default is all bits (31).
MsgFile
Specifies the path and filename of the message file. If the path is omitted, the directory of the current uext.dll is used.
EventLog
For !evlog read, !evlog backup, and !evlog clear, EventLog specifies the event log from which to read. The possible values are Application, System, and Security. The default is Application.

For !evlog option, EventLog specifies the event log whose maximum count is to be set. The possible values are All, Application, System, and Security. The default is All.

BackupFile
Specifies the path and filename of the backup file. The default location is the current directory. The default filename is EventLog_backup.evt, where EventLog is the event log used in this command. If this file already exists, the command will be aborted.
Count
Specifies the maximum number of records to retrieve. The default is 20.
-+
Specifies that the current maximum record number should be the highest record number retrieved in future !evlog read commands. (In other words, no records will be shown as long as the search is performed forward.)
RecordBound
Specifies the highest record number to retrieve in future !evlog read commands. If zero is specified, no bound is set — this is the default.
Record
If -n Count is not included, -r Record specifies the record number to retrieve. If -n Count is included, Record specifies the record number at which the display should begin.
Order
Specifies the search order, either Forwards or Backwards. The default is Forwards. A backward search order causes searches start from the most recent record logged to the event log, and continue in reverse-chronological order as matching records are found.
Width
Specifies the data display width, in characters. This is the width displayed in the "Data:" section. The default is 8 characters.
ID
Specifies the prefix to display before the event. Possible values are 0 (no prefix), 1000 ("Information"), 2000 ("Success"), 3000 ("Warning"), and 4000 ("Error"). The default is 0.
Category
Specifies the event category. Possible values are 0 (no category), 1 (Devices), 2 (Disk), 3 (Printers), 4 (Services), 5 (Shell), 6 (System_Event), and 7 (Network). The default is 0.
Message
Specifies a text message to add to the event description.
Option
Specifies the !evlog option whose help text is to be displayed.
-?
Causes the debugger to display !evlog help text.

DLL

Windows NT 4.0 | uext.dll
Windows 2000 | uext.dll
Windows XP Windows .NET Server 2003 | uext.dll

Comments

After you have added an event source to the registry with !evlog addsource, you can view the values with !dreg. For example:

0:000> !dreg hklm\system\currentcontrolset\services\eventlog\Application\<source>!*

The !evlog option command is used to set new defaults for the !evlog read command. This lets you avoid retyping all the parameters every time you use !evlog read. Setting a maximum record bound with the -+ parameter or the -r Records parameter allows you to terminate all searches after a known record number is encountered. This can be useful if you are only interested in all records logged after a certain event.

Before using !evlog report, you should use !evlog addsource to configure an event source in the registry. Once this has been configured, the event viewer will recognize the various event IDs.

Here is an example of the !evlog info extension:

0:000> !evlog info -?
--------------------------------
Application Event Log:
  # Records       : 4362
  Oldest Record # : 1
  Newest Record # : 4362
  Event Log Full  : false
--------------------------------
System Event Log:
  # Records       : 2296
  Oldest Record # : 1
  Newest Record # : 2296
  Event Log Full  : false
--------------------------------
Security Event Log:
  # Records       : 54544
  Oldest Record # : 1
  Newest Record # : 54544
  Event Log Full  : false
--------------------------------

0:000> !evlog option -n 4
Default EvLog Option Settings:
--------------------------------
Max Records Returned: 4
Search Order:         Backwards
Data Display Width:   8
--------------------------------
Bounding Record Numbers:
  Application Event Log: 0
  System Event Log:      0
  Security Event Log:    0
--------------------------------

0:000> !evlog read -l application
-------------- 01 --------------
Record #: 4364

Event Type:      Error (1)
Event Source:    Userenv
Event Category:  None (0)
Event ID:        1000 (0xC00003E8)
Date:            06/06/2002
Time:            18:03:17
Description:     (1 strings)
The Group Policy client-side extension Security was passed flags (17) and returned a failure status code of (87).

-------------- 02 --------------
Record #: 4363

Event Type:      Warning (2)
Event Source:    SceCli
Event Category:  None (0)
Event ID:        1202 (0x800004B2)
Date:            06/06/2002
Time:            18:03:17
Description:     (1 strings)
0x57 : The parameter is incorrect.
Please look for more details in TroubleShooting section in Security Help.

-------------- 03 --------------
Record #: 4362

Event Type:      Error (1)
Event Source:    Userenv
Event Category:  None (0)
Event ID:        1000 (0xC00003E8)
Date:            06/06/2002
Time:            16:04:08
Description:     (1 strings)
The Group Policy client-side extension Security was passed flags (17) and returned a failure status code of (87).

-------------- 04 --------------
Record #: 4361

Event Type:      Warning (2)
Event Source:    SceCli
Event Category:  None (0)
Event ID:        1202 (0x800004B2)
Date:            06/06/2002
Time:            16:04:08
Description:     (1 strings)
0x57 : The parameter is incorrect.
Please look for more details in TroubleShooting section in Security Help.
WARNING: Max record count (4) exceeded, increase record count to view more


!gatom

Displays the global atom table.

Syntax

!gatom

DLL

Windows NT 4.0 | ntsdexts.dll
Windows 2000 | ntsdexts.dll
Windows XP Windows .NET Server 2003 | ntsdexts.dll

Additional Information

For information on the global atom table, see the Platform SDK.


!igrep

Searches for a pattern in disassembly.

Syntax

!igrep [Pattern [StartAddress]]

Parameters

Pattern
Specifies the pattern to search for. If omitted, the last Pattern is used.
StartAddress
Specifies the hexadecimal address at which to begin searching. If omitted, the current program counter is used.

DLL

Windows NT 4.0 | ntsdexts.dll
Windows 2000 | ntsdexts.dll
Windows XP Windows .NET Server 2003 | Not available


!locks (!ntsdexts.locks)

Displays a list of critical sections associated with the current process.

This extension command should not be confused with the !kdext*.locks extension command.

Syntax

!locks [Options]

Parameters

Specifies the amount of information to be diplayed. Any combination of the following options can be used:

-v
Causes the display to include all critical sections, even those which are not currently owned.
-o
(Windows XP and Windows .NET Server 2003 only) Causes the display to only include "orphaned" information (pointers which do not actually point to valid critical sections).

DLL

Windows NT 4.0 | ntsdexts.dll
Windows 2000 | ntsdexts.dll
Windows XP Windows .NET Server 2003 | ntsdexts.dll

Comments

This extension command shows all critical sections that have been initialized by calling RtlInitializeCriticalSection.

To see the details of each critical section, use the !critsec extension.

Here is an example:

0:000> !locks

CritSec w3svc!g_pWamDictator+a0 at 68C2C298
LockCount          0
RecursionCount     1
OwningThread       d1
EntryCount         1
ContentionCount    0
*** Locked

CritSec SMTPSVC+66a30 at 67906A30
LockCount          0
RecursionCount     1
OwningThread       d0
EntryCount         1
ContentionCount    0
*** Locked

Additional Information

For information on critical sections, see the Platform SDK, the Windows DDK, or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich. Also see !cs and !critsec.


!runaway

Displays information about the time consumed by each thread.

Syntax

!runaway [Flags]

Parameters

Flags
Specifies the kind of information to be displayed. Flags can be any combination of the following bits. The default value is 0x1:
Bit 0 (0x1)
Causes the debugger to show the amount of user time consumed by each thread.
Bit 1 (0x2)
Causes the debugger to show the amount of kernel time consumed by each thread.
Bit 2 (0x4)
Causes the debugger to show the amount of time that has elapsed since each thread was created.

DLL

Windows NT 4.0 | Not available
Windows 2000 | ntsdexts.dll
Windows XP Windows .NET Server 2003 | ntsdexts.dll

The !runaway extension can only be used during live debugging; it cannot be used for crash dump file debugging.

Comments

This extension is a quick way to find out which threads are spinning out of control or consuming too much CPU time.

Here is an example:

0:001> !runaway 7

 User Mode Time
 Thread    Time
 55c        0:00:00.0093
 1a4        0:00:00.0000

 Kernel Mode Time
 Thread    Time
 55c        0:00:00.0140
 1a4        0:00:00.0000

 Elapsed Time
 Thread    Time
 55c        0:00:43.0533
 1a4        0:00:25.0876

Additional Information

For information on threads in user mode, see Controlling Processes and Threads. For more information on analyzing processes and threads, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!threadtoken

Displays the impersonation state of the current thread.

Syntax

!threadtoken

DLL

Windows NT 4.0 | Not available
Windows 2000 | ntsdexts.dll
Windows XP Windows .NET Server 2003 | Not available

Comments

The !threadtoken extension is obsolete in Windows XP and later versions of Windows. Use !token instead.

If the current thread is impersonating, the token that this thread is using will be displayed.

Otherwise, a message reading "Thread is not impersonating" will appear. The process token will then be displayed.

Tokens will be displayed in the same format that !handle uses when displaying token handles.

Here is an example:

0:000> ~
.  0  id: 1d0.55c   Suspend: 1 Teb 7ffde000 Unfrozen
#  1  id: 1d0.1a4   Suspend: 1 Teb 7ffdd000 Unfrozen

0:000> !threadtoken

***Thread is not impersonating, using process token***
    Auth Id    0 : 0x1c93d
    Type       Primary
    Imp Level  Anonymous
     Token Id  0 : 0x5e8c19
     Mod Id    0 : 0x5e8c12
     Dyn Chg   0x1f4
     Dyn Avail 0x1a4
     Groups    26
     Privs     17
     User      S-1-5-21-2127521184-1604012920-1887927527-74790
     Groups    26
               S-1-5-21-2127521184-1604012920-1887927527-513
               S-1-1-0
               S-1-5-32-544
               S-1-5-32-545
               S-1-5-21-2127521184-1604012920-1887927527-277551
               S-1-5-21-2127521184-1604012920-1887927527-211604
               S-1-5-21-2127521184-1604012920-1887927527-10546
               S-1-5-21-2127521184-1604012920-1887927527-246657
               S-1-5-21-2127521184-1604012920-1887927527-277552
               S-1-5-21-2127521184-1604012920-1887927527-416040
               S-1-5-21-2127521184-1604012920-1887927527-96548
               S-1-5-21-2127521184-1604012920-1887927527-262644
               S-1-5-21-2127521184-1604012920-1887927527-155802
               S-1-5-21-2127521184-1604012920-1887927527-158763
               S-1-5-21-2127521184-1604012920-1887927527-279132
               S-1-5-21-2127521184-1604012920-1887927527-443952
               S-1-5-21-2127521184-1604012920-1887927527-175772
               S-1-5-21-2127521184-1604012920-1887927527-388472
               S-1-5-21-2127521184-1604012920-1887927527-443950
               S-1-5-21-2127521184-1604012920-1887927527-266975
               S-1-5-21-2127521184-1604012920-1887927527-158181
               S-1-5-21-2127521184-1604012920-1887927527-279435
               S-1-5-5-0-116804
               S-1-2-0
               S-1-5-4
               S-1-5-11
     Privileges    17
               SeUndockPrivilege ( Enabled Default )
               SeTakeOwnershipPrivilege ( )
               SeShutdownPrivilege ( )
               SeDebugPrivilege ( )
               SeIncreaseBasePriorityPrivilege ( )
               SeAuditPrivilege ( )
               SeSyncAgentPrivilege ( )
               SeLoadDriverPrivilege ( )
               SeSystemEnvironmentPrivilege ( Enabled )
               SeRemoteShutdownPrivilege ( )
               SeProfileSingleProcessPrivilege ( )
               SeCreatePagefilePrivilege ( )
               SeCreatePermanentPrivilege ( )
               SeSystemProfilePrivilege ( Enabled )
               SeBackupPrivilege ( )
               SeMachineAccountPrivilege ( )
               SeEnableDelegationPrivilege ( Enabled )

Additional Information

For information on threads and impersonation, see the Platform SDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!vadump

Displays all virtual memory ranges and their corresponding protection information.

Syntax

!vprot [-v]

Parameters

-v
Causes the display to include information about each original allocation region as well. Since individual addresses within a region can have their protection altered after memory is allocated (by VirtualProtect, for example), the original protection status for this larger region may not be the same as that of each range within the region.

DLL

Windows NT 4.0 | uext.dll
Windows 2000 | uext.dll
Windows XP Windows .NET Server 2003 | uext.dll

Comments

Here is an example:

0:000> !vadump
BaseAddress:       00000000
RegionSize:        00010000
State:             00010000  MEM_FREE
Protect:           00000001  PAGE_NOACCESS

BaseAddress:       00010000
RegionSize:        00001000
State:             00001000  MEM_COMMIT
Protect:           00000004  PAGE_READWRITE
Type:              00020000  MEM_PRIVATE
.........

In this display, the State line shows the state of the memory range beginning at the specified BaseAddress. The possible state values are MEM_COMMIT, MEM_FREE, and MEM_RESERVE.

The Protect line shows the protection status of this memory range. The possible protection values are PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_WRITECOPY, PAGE_EXECUTE_WRITECOPY, and PAGE_GUARD.

The Type line shows the memory type. The possible values are MEM_IMAGE, MEM_MAPPED, and MEM_PRIVATE.

Here is an example using the -v parameter:

0:000> !vadump -v
BaseAddress:       00000000
AllocationBase:    00000000
RegionSize:        00010000
State:             00010000  MEM_FREE
Protect:           00000001  PAGE_NOACCESS

BaseAddress:       00010000
AllocationBase:    00010000
AllocationProtect: 00000004  PAGE_READWRITE
RegionSize:        00001000
State:             00001000  MEM_COMMIT
Protect:           00000004  PAGE_READWRITE
Type:              00020000  MEM_PRIVATE
.........

When -v is used, the AllocationProtect line shows the default protection that the entire region was created with. The Protect line shows the actual protection for this specific address.

Additional Information

To view memory protection information for a single virtual addres, use !vprot. For information on memory protection, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!vprot

Displays virtual memory protection information.

Syntax

!vprot [Address]

Parameters

Address
Specifies the hexadecimal address whose memory protection status is to be displayed.

DLL

Windows NT 4.0 | uext.dll
Windows 2000 | uext.dll ntsdexts.dll
Windows XP Windows .NET Server 2003 | uext.dll ntsdexts.dll

Comments

The !vprot extension command can be used for both live debugging and dump file debugging.

Here is an example:

0:000> !vprot 30c191c
BaseAddress: 030c1000
AllocationBase: 030c0000
AllocationProtect: 00000080 PAGE_EXECUTE_WRITECOPY
RegionSize: 00011000
State: 00001000 MEM_COMMIT
Protect: 00000010 PAGE_EXECUTE
Type: 01000000 MEM_IMAGE

In this display, the AllocationProtect line shows the default protection that the entire region was created with. Note that individual addresses within this region can have their protection altered after memory is allocated (for example, if VirtualProtect is called). The Protect line shows the actual protection for this specific address. The possible protection values are PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_WRITECOPY, PAGE_EXECUTE_WRITECOPY, and PAGE_GUARD.

The State line also applies to the specific virtual address passed to !vprot. The possible state values are MEM_COMMIT, MEM_FREE, and MEM_RESERVE.

The Type line shows the memory type. The possible values are MEM_IMAGE, MEM_MAPPED, and MEM_PRIVATE.

Additional Information

To view memory protection information for all memory ranges owned by the target process, use !vadump. For information on memory protection, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


Specialized Extensions

This section of the reference discusses extensions commands in the less-used extension DLLs.

These include:

Logger Extensions (logexts.dll)

NDIS Extensions (ndiskd.dll)

RPC Extensions (rpcexts.dll)

ACPI Extensions (acpikd.dll and kdexts.dll)

Graphics Driver Extensions (gdikdx.dll)

OEM Support Extensions (kdex2x86.dll)


Logger Extensions (logexts.dll)

Extension commands related to the Logger and LogViewer tools can be found in logexts.dll.

This DLL appears in the winext directory. It can be used with all Windows operating systems.


!logexts.help

The !logexts.help extension displays a help text showing all logexts.dll extension commands.

Syntax

!logexts.help

DLL

Windows NT 4.0 | logexts.dll
Windows 2000 | logexts.dll
Windows XP Windows .NET Server 2003 | logexts.dll

Additional Information

For more information, see Logger and LogViewer.


!logexts.logb

The !logexts.logb extension displays or flushes the output buffer.

Syntax

!logexts.logb p
!logexts.logb f

Parameters

p
Causes the contents of the output buffer to be displayed in the debugger.
f
Flushes the output buffer to the disk.

DLL

Windows NT 4.0 | logexts.dll
Windows 2000 | logexts.dll
Windows XP Windows .NET Server 2003 | logexts.dll

Comments

As a performance consideration, log output is flushed to disk only when the output buffer is full. By default, the buffer is 2144 bytes.

The !logexts.logb p extension displays the contents of the buffer in the debugger.

The !logexts.logb f extension flushes the buffer to the log files. Since the buffer memory is managed by the target application, the automatic writing of the buffer to disk will not occur if there is an access violation or some other non-recoverable error in the target application. In such cases, you should use this command to manually flush the buffer to the disk, or else the most recently-logged APIs may not appear in the log files.

Additional Information

For more information, see Logger and LogViewer.


!logexts.logc

The !logexts.logc extension displays all API categories, displays all APIs in a specific category, or enables or disables the logging of APIs in one or more categories.

Syntax

!logexts.logc e Categories
!logexts.logc d Categories
!logexts.logc p Category
!logexts.logc

Parameters

e
Enables logging of the specified categories.
d
Disables logging of the specified categories.
Categories
Specifies the categories to be enabled or disabled. If multiple categories are listed, separate them with spaces. An asterisk (*) can be used to indicate all categories.
p
Displays all APIs that belong to the specified category.
Category
Specifies the category whose APIs will be displayed. Only one category can be specified with the p option.

DLL

Windows NT 4.0 | logexts.dll
Windows 2000 | logexts.dll
Windows XP Windows .NET Server 2003 | logexts.dll

Comments

Without any options, !logexts.logc will display the current list of available categories, and will indicate which ones are enabled and disabled.

If a category is disabled, the hooks for all APIs in that category will be removed so that there is no longer any performance overhead. COM hooks are not removed because they cannot be re-enabled at will.

Enabling only certain categories can be useful when you are only interested in a particular type of interaction that the program is having with the Windows — for example, file operations. This reduces the log file size and also reduces the effect that Logger has on the execution speed of the process.

The following command will enable the logging of all categories:

0:000> !logexts.logc e *

The following command will disable the logging of category 7:

0:000> !logexts.logc d 7

The following command will enable the logging of categories 13 and 15:

0:000> !logexts.logc e 13 15

The following command will display all APIs belonging to category 3:

0:000> !logexts.logc p 3

Additional Information

For more information, see Logger and LogViewer.


!logexts.logd

The !logexts.logd extension disables logging.

Syntax

!logexts.logd

DLL

Windows NT 4.0 | logexts.dll
Windows 2000 | logexts.dll
Windows XP Windows .NET Server 2003 | logexts.dll

Comments

This will cause all API hooks to be removed in an effort to allow the program to run freely. COM hooks are not removed because they cannot be re-enabled at will.

Additional Information

For more information, see Logger and LogViewer.


!logexts.loge

The !logexts.loge extension enables logging. If logging has not been initialized, it will be initialized and enabled.

Syntax

!logexts.loge [OutputDirectory]

Parameters

OutputDirectory
Specifies the directory to use for output. If OutputDirectory is specified, it must exist — the debugger will not create it. If a relative path is specified, it will be relative to the directory from which the debugger was started. If OutputDirectory is omitted, the path to the Desktop will be used. The debugger will create a LogExts subdirectory of OutputDirectory, and all Logger output will be placed in this subdirectory.

DLL

Windows NT 4.0 | logexts.dll
Windows 2000 | logexts.dll
Windows XP Windows .NET Server 2003 | logexts.dll

Comments

If Logger has not yet been injected into the target application by the !logexts.logi extension, the !logexts.loge extension will inject Logger into the target, and then enable logging.

If !logexts.logi has already been run, you cannot include OutputDirectory, since the output directory will have already been set.

Additional Information

For more information, see Logger and LogViewer.


!logexts.logi

The !logexts.logi extension initializes logging by injecting Logger into the target application.

Syntax

!logexts.logi [OutputDirectory]

Parameters

OutputDirectory
Specifies the directory to use for output. If OutputDirectory is specified, it must exist — the debugger will not create it. If a relative path is specified, it will be relative to the directory from which the debugger was started. If OutputDirectory is omitted, the path to the Desktop will be used. The debugger will create a LogExts subdirectory of OutputDirectory, and all Logger output will be placed in this subdirectory.

DLL

Windows NT 4.0 | logexts.dll
Windows 2000 | logexts.dll
Windows XP Windows .NET Server 2003 | logexts.dll

Comments

This command initializes logging, but does not actually enable it. Logging can be enabled with the !logexts.loge command.

Additional Information

For more information, see Logger and LogViewer.


!logexts.logm

The !logexts.logm extension creates or displays a module inclusion list or a module exclusion list.

Syntax

!logexts.logm i Modules
!logexts.logm x Modules
!logexts.logm

Parameters

i
Causes Logger to use a module inclusion list. It will consist of the specified Modules.
x
Causes Logger to use a module exclusion list. It will consist of logexts.dll, kernel32.dll, and the specified Modules.
Modules
Specifies the modules to be included or excluded. This list is not cumulative; each use of this command creates an entirely new list. If multiple modules are listed, separate them with spaces. An asterisk (*) can be used to indicate all modules.

DLL

Windows NT 4.0 | logexts.dll
Windows 2000 | logexts.dll
Windows XP Windows .NET Server 2003 | logexts.dll

Comments

With no parameters, the !logexts.logm extension displays the current inclusion list or exclusion list.

The extensions !logexts.logm x * and !logexts.logm i are equivalent: they result in a completely empty inclusion list.

The extensions !logexts.logm i * and !logexts.logm x are equivalent: they result in an exclusion list that contains only logexts.dll and kernel32.dll. These two modules are always excluded, since Logger is not permitted to log itself.

Here are some examples:

0:001> !logm
Excluded modules:
  LOGEXTS.DLL      [mandatory]
  KERNEL32.DLL     [mandatory]
  USER32.DLL
  GDI32.DLL
  ADVAPI32.DLL

0:001> !logm x winmine.exe
Excluded modules:
  logexts.dll      [mandatory]
  kernel32.dll     [mandatory]
  winmine.exe

0:001> !logm x user32.dll gdi32.dll
Excluded modules:
  logexts.dll      [mandatory]
  kernel32.dll     [mandatory]
  user32.dll
  gdi32.dll

0:001> !logm i winmine.exe mymodule2.dll
Included modules:
  winmine.exe
  mymodule2.dll

Additional Information

For more information, see Logger and LogViewer.


!logexts.logo

The !logexts.logo extension sets or displays the Logger output options.

Syntax

!logexts.logo {e|d} {d|t|v}
!logexts.logo

Parameters

e|d
Specifies whether to enable (e) or disable (d) the indicated output type.
d|t|v
Specifies the output type. Three types of Logger output are possible: messages sent directly to the debugger (d), a text file (t), or a verbose .lgv file (v).

DLL

Windows NT 4.0 | logexts.dll
Windows 2000 | logexts.dll
Windows XP Windows .NET Server 2003 | logexts.dll

If !logexts.logo is used without any parameters, the current logging status, the output directory, and the current settings for the debugger, text file, and verbose log are displayed:

0:000> !logo
Logging currently enabled.

Output directory: MyLogs\LogExts\

Output settings:
  Debugger            Disabled
  Text file           Enabled
  Verbose log         Enabled

In the example above, the output directory is a relative path, so it is located relative to the directory in which the debuggers were started.

If you wished to disable verbose logging, you would use the following command:

0:000> !logo d v
  Debugger            Disabled
  Text file           Enabled
  Verbose log         Disabled

Text file and .lgv files will be placed in the current output directory. To read an .lgv file, use LogViewer.

Additional Information

For more information, see Logger and LogViewer.


NDIS Extensions (ndiskd.dll)

Extension commands which are useful for debugging NDIS (Network Driver Interface Specification) drivers can be found in ndiskd.dll.

The Windows 2000 version of this extension DLL appears in the w2kfre and w2kchk directories. The Windows XP and Windows .NET Server 2003 version of this extension DLL appear in the winxp directory.


!ndiskd.dbglevel

The !ndiskd.dbglevel extension sets the NDIS debug level.

Syntax

!ndiskd.dbglevel [Level]

Parameters

Level
Specifies the amount of debug tracing in NDIS components that are selected within the !ndiskd.dbgsystems extension. Only one level can be selected. The following levels are possible:
INFO
LOG
WARN
ERR
FATAL

DLL

Windows NT 4.0 | Not available
Windows 2000 | ndiskd.dll
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.dbgsystems

The !ndiskd.dbgsystems extension controls which NDIS components will transmit debug information.

Syntax

!ndiskd.dbgsystems [Values]

Parameters

Values
Selects various NDIS components to trace and watch for debug information. If multiple components are selected, separate them with spaces. If a previously-selected component is repeated, its debug monitoring will be toggled off. The following values are possible:
INIT
CONFIG
SEND
RECV
PROTOCOL
BIND
BUS_QUERY
REGISTRY
MEMORY
FILTER
REQUEST
WORK_ITEM
PNP
PM
OPEN
LOCKS
RESET
WMI
NDIS_CO
REFERENCE

DLL

Windows NT 4.0 | Not available
Windows 2000 | ndiskd.dll
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.findpacket

The !ndiskd.findpacket extension finds the specified packets.

Syntax

!ndiskd.findpacket v VirtualAddress
!ndiskd.findpacket p PoolAddress

Parameters

VirtualAddress
Specifies a virtual address that is contained in the desired packet.
PoolAddress
Specifies a pool address. All un-returned packets in this pool will be displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.gminiports

The !ndiskd.gminiports extension displays a list of all miniports, including those that have not yet started.

Syntax

!ndiskd.gminiports

DLL

Windows NT 4.0 | Not available
Windows 2000 | ndiskd.dll
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.help

The !ndiskd.help extension displays a help text showing all ndiskd.dll extension commands.

Syntax

!ndiskd.help

DLL

Windows NT 4.0 | Not available
Windows 2000 | ndiskd.dll
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.int_ctxt

The !ndiskd.int_ctxt extension displays the second argument of ndisMIsr.

Syntax

!ndiskd.int_ctxt  NDIS_MINIPORT_INTERRUPT

Parameters

NDIS_MINIPORT_INTERRUPT
Specifies the value of the miniport interrupt.

DLL

Windows NT 4.0 | Not available
Windows 2000 | ndiskd.dll
Windows XP Windows .NET Server 2003 | Not available

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.mem

The !ndiskd.mem extension displays a log of all allocated memory, if enabled.

Syntax

!ndiskd.mem

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.miniport

The !ndiskd.miniport extension displays a Miniport block.

Syntax

!ndiskd.miniport MiniportBlock

Parameters

MiniportBlock
Specifies the address of the Miniport block to be displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | ndiskd.dll
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.miniports

The !ndiskd.miniports extension displays a list of all miniports, except for those that have not yet started.

Syntax

!ndiskd.miniports

DLL

Windows NT 4.0 | Not available
Windows 2000 | ndiskd.dll
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.mopen

The !ndiskd.mopen extension displays a Miniport Open block.

Syntax

!ndiskd.mopen MiniportOpenBlock

Parameters

MiniportOpenBlock
Specifies the address of the Miniport Open block to be displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | ndiskd.dll
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.ndis

The !ndiskd.ndis extension displays some useful NDIS information.

Syntax

!ndiskd.ndis

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.pkt

The !ndiskd.pkt extension displays information about a packet.

Syntax

!ndiskd.pkt Packet Verbosity

Parameters

Packet
Specifies the address of the packet.
Verbosity
Specifies the amount of detail to be displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | ndiskd.dll
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.pktpool

The !ndiskd.pktpool extension displays the contents of an NDIS packet pool.

Syntax

!ndiskd.pktpool PktPool Number

Parameters

PktPool
Specifies a pointer to the NDIS packet pool.

DLL

Windows NT 4.0 | Not available
Windows 2000 | ndiskd.dll
Windows XP Windows .NET Server 2003 | Not available

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.pktpools

The !ndiskd.pktpools extension displays a list of all allocated packet pools.

Syntax

!ndiskd.pktpools

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.protocol

The !ndiskd.protocol extension displays the contents of a protocol block.

Syntax

!ndiskd.protocol ProtocolBlock

Parameters

ProtocolBlock
Specifies the address of the protocol block.

DLL

Windows NT 4.0 | Not available
Windows 2000 | ndiskd.dll
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


!ndiskd.protocols

The !ndiskd.protocols extension displays a list of all protocols and their open objects.

Syntax

!ndiskd.protocols

DLL

Windows NT 4.0 | Not available
Windows 2000 | ndiskd.dll
Windows XP Windows .NET Server 2003 | ndiskd.dll

Additional Information

For information on NDIS drivers, see the Windows DDK.


RPC Extensions (rpcexts.dll)

Extension commands which are useful for debugging Microsoft® Remote Procedure Call (RPC) can be found in rpcexts.dll.

The Windows 2000 version of this extension DLL appears in the w2kfre and w2kchk directories. The Windows XP and Windows .NET Server 2003 version of this extension DLL appear in the winxp directory.


!rpcexts.checkrpcsym

The !rpcexts.checkrpcsym determines whether RPC symbols are correct.

Syntax

!rpcexts.checkrpcsym

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | rpcexts.dll

Comments

This extension performs only limited checking of symbols, so it is possible that it tells you your symbols are correct, even though they are not. However, if it tells you your symbols are not correct, they most definitely are not correct.

If symbols are correct, output will look like this:

0:002> !rpcexts.checkrpcsym
RPC symbols are correct

If symbols are invalid, output will look something like this:

0:002> !rpcexts.checkrpcsym
*** ERROR: Symbol file could not be found -- Using default symbols ***
Cannot find address of RPCRT4!WS_NewConnection
RPC symbols are wrong

Additional Information

For more information on debugging Microsoft Remote Procedure Call (RPC), see RPC Debugging.


!rpcexts.getcallinfo

The !rpcexts.getcallinfo extension searches the system's RPC state information for server-side call (SCALL) information.

Syntax

!rpcexts.getcallinfo [ CallID | 0 [ IfStart | 0 [ ProcNum | 0xFFFF [ProcessID|0] ] ] ]
!rpcexts.getcallinfo -?

Parameters

CallID
Specifies the call ID. This parameter is optional; include it if you only want to display calls matching a specific CallID value.
IfStart
Specifies the first DWORD of the interface UUID on which the call was made. This parameter is optional; include it if you only want to display calls matching a specific IfStart value.
ProcNum
Specifies the procedure number of this call. (The RPC Runtime identifies individual routines from an interface by numbering them by position in the IDL file — the first routine in the interface is 0, the second 1, and so on.)
ProcessID
Specifies the process ID (PID) of the server process that owns the calls you wish to display. This parameter is optional; omit it if you wish to display calls owned by multiple processes.
-?
Displays a short help text.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | rpcexts.dll

Comments

This extension can only be used with CDB or with user-mode WinDbg.

The parameters are parsed from left to right. To skip a parameter, supply the value "0" — except for the ProcNum parameter, which is skipped by supplying the value 0xFFFF.

Here is an example:

0:002> !rpcexts.getcallinfo
Searching for call info ...
PID  CELL ID   ST PNO IFSTART  TIDNUMBER CALLFLAG CALLID   LASTTIME CONN/CLN
----------------------------------------------------------------------------
00c4 0000.0006 00 009 367abb81 0000.0007 00000001 0000004a 00018b41 0000.0005
00c4 0000.000a 00 007 367abb81 0000.002d 00000001 0000009f 000134ff 0000.0009
00c4 0000.000d 00 00f 82273fdc 0000.002d 00000001 00000002 00036cd8 0000.0042
00c4 0000.0010 00 00f 367abb81 0000.002d 00000001 00000078 00011636 0000.000f
00c4 0000.0012 00 00d 8d9f4e40 0000.0007 00000001 0000004f 000097bd 0000.0011
00c4 0000.0015 00 000 367abb81 0000.0004 00000001 0000004c 0002cccf 0000.0014
00c4 0000.0017 00 007 367abb81 0000.0004 00000001 00000006 0000cf5e 0000.0016
00c4 0000.0018 00 000 367abb81 0000.002d 00000001 0000000b 0001236f 0000.002a
00c4 0000.0019 01 00b 82273fdc 0000.0002 00000009 00000000 00018b19 00d0.0104
00c4 0000.001b 00 009 65a93890 0000.0007 00000001 000000ea 0003cd14 0000.001a
00c4 0000.0021 00 03b 8d9f4e40 0000.0013 00000001 0000000b 0001162c 0000.0020
00c4 0000.0022 01 008 82273fdc 0000.001f 00000009 00000000 00013405 00c4.02e8
00c4 0000.0024 00 007 367abb81 0000.0004 00000001 00000006 0000f198 0000.0023
00c4 0000.0026 00 000 367abb81 0000.0036 00000001 000000ab 00038049 0000.0025
00c4 0000.0027 01 00b 82273fdc 0000.001f 00000009 00000000 00020b7c 00a8.0228
00c4 0000.0028 01 008 82273fdc 0000.003e 00000009 00000000 0003a949 0294.02f0
00c4 0000.0029 00 00d 8d9f4e40 0000.002d 00000001 0000033f 0003831a 0000.0031
00c4 0000.0030 00 03b 8d9f4e40 0000.0013 00000001 00000002 00024e43 0000.002f
00c4 0000.0032 01 008 82273fdc 0000.001f 00000009 00000000 000118f3 022c.019c
00c4 0000.0035 00 007 367abb81 0000.0033 00000001 00000074 0001042d 0000.0034
00c4 0000.0038 00 007 367abb81 0000.002d 00000001 0000000a 0002a3e4 0000.0037
00c4 0000.003a 00 007 367abb81 0000.0036 00000001 00000063 0003b7b8 0000.0039
00c4 0000.003b 00 004 3ba0ffc0 0000.002d 00000001 00000005 0002dd79 0000.002e
00c4 0000.003f 01 008 82273fdc 0000.0002 00000009 00000000 000245c6 01c0.037c
00c4 0000.0043 01 008 82273fdc 0000.0002 00000009 00000000 00037d50 020c.0394
00c4 0000.0049 00 008 8d9f4e40 0000.0007 00000001 000002b1 0004e900 0000.0048
0170 0000.0009 01 002 e60c73e6 0000.0002 00000009 baadf00d 0004ad30 020c.03a4
0170 0000.000a 01 002 0b0a6584 0000.0008 00000009 baadf00d 0001187b 00c4.012c
0170 0000.000c 01 002 0b0a6584 0000.0008 00000009 baadf00d 00011cdc 022c.019c
0170 0000.000d 01 003 00000136 0000.0011 00000009 baadf00d 00034845 020c.02b4
0170 0000.000e 01 000 412f241e 0000.0002 00000009 baadf00d 00012491 0294.02b8
0170 0000.000f 01 002 0b0a6584 0000.0011 00000009 baadf00d 000492e7 026c.0118
0170 0000.0010 01 002 e60c73e6 0000.0013 00000009 baadf00d 0004ab78 0378.038c
0170 0000.0014 01 004 e60c73e6 0000.0011 00000001 baadf00d 0002bc25 0378.024c
0170 0000.0015 01 003 00000136 0000.0013 00000009 00000003 00031d8d 0378.00b8
0170 0000.0018 01 004 00000136 0000.0002 00000001 baadf00d 00032e05 020c.026c
020c 0000.0004 01 003 00000132 0000.000b 00000009 00000000 00034953 0170.0240
020c 0000.000e 01 001 2f5f6520 0000.001e 00000009 00120006 00035bac 020c.03b4
020c 0000.0010 01 000 629b9f66 0000.000f 00000009 00000000 000279ff 00a8.0194
020c 0000.0011 01 004 faedcf59 0000.0003 00000009 00000012 0003836b 0378.024c
020c 0000.0012 01 001 629b9f66 0000.000f 00000009 00000000 0003657e 020c.02ec
020c 0000.0017 01 005 00000134 0000.0002 00000001 00000016 0003836b 0378.024c
020c 0000.001d 01 001 2f5f6520 0000.0014 00000001 0020007d 000351b2 020c.0258
0294 0000.0004 01 004 00000132 0000.0002 00000009 00000000 0003b786 0170.01ac
0378 0000.0004 01 003 00000134 0000.0003 0000000b 00300038 0002d896 020c.021c
026c 0000.0004 02 000 19bb5061 0000.0002 00000001 00000001 0004caa5 0000.0003

For a similar example using the DbgRpc tool, see Get RPC Call Information.

Additional Information

For more information on debugging Microsoft Remote Procedure Call (RPC), see RPC Debugging.


!rpcexts.getclientcallinfo

The !rpcexts.getclientcallinfo extension searches the system's RPC state information for client call (CCALL) information.

Syntax

!rpcexts.getclientcallinfo [ CallID | 0 [ IfStart | 0 [ ProcNum | 0xFFFF [ProcessID|0] ] ] ]
!rpcexts.getclientcallinfo -?

Parameters

CallID
Specifies the call ID. This parameter is optional; include it if you only want to display calls matching a specific CallID value.
IfStart
Specifies the first DWORD of the interface UUID on which the call was made. This parameter is optional; include it if you only want to display calls matching a specific IfStart value.
ProcNum
Specifies the procedure number of this call. (The RPC Runtime identifies individual routines from an interface by numbering them by position in the IDL file — the first routine in the interface is 0, the second 1, and so on.) This parameter is optional; include it if you only want to display calls matching a specific ProcNum value.
ProcessID
Specifies the process ID (PID) of the client process that owns the calls you wish to display. This parameter is optional; omit it if you wish to display calls owned by multiple processes.
-?
Displays a short help text.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | rpcexts.dll

Comments

This extension can only be used with CDB or with user-mode WinDbg. It is only available if full RPC state information is being gathered.

Here is an example:

0:002> !rpcexts.getclientcallinfo
Searching for call info ...
PID  CELL ID   PNO  IFSTART  TIDNUMBER CALLID   LASTTIME PS CLTNUMBER ENDPOINT
------------------------------------------------------------------------------
03d4 0000.0001 0000 19bb5061 0000.0000 00000001 0004ca9b 07 0000.0002 1118

For a similar example using the DbgRpc tool, see Get RPC Client Call Information.

Additional Information

For more information on debugging Microsoft Remote Procedure Call (RPC), see RPC Debugging.


!rpcexts.getdbgcell

The !rpcexts.getdbgcell extension displays RPC state information for the specified cell.

Syntax

!rpcexts.getdbgcell ProcessID CellID1.CellID2
!rpcexts.getdbgcell -?

Parameters

ProcessID
Specifies the process ID (PID) of the process whose server contains the desired cell.
CellID1.CellID2
Specifies the number of the cell to be displayed.
-?
Displays a short help text.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | rpcexts.dll

Comments

This extension can only be used with CDB or with user-mode WinDbg.

Here is an example:

0:002> !rpcexts.getdbgcell c4 0.19
Getting cell info ...
Call
Status: Active
Procedure Number: 11
Interface UUID start (first DWORD only): 82273FDC
Call ID: 0x0 (0)
Servicing thread identifier: 0x0.3E
Call Flags: cached, LRPC
Last update time (in seconds since boot):1453.459 (0x5AD.1CB)
Caller (PID/TID) is: d0.1ac (208.428)

For a similar example using the DbgRpc tool, see Get RPC Cell Information.

Additional Information

For more information on debugging Microsoft Remote Procedure Call (RPC), see RPC Debugging.


!rpcexts.getendpointinfo

The !rpcexts.getendpointinfo extension searches the system's RPC state information for endpoint information.

Syntax

!rpcexts.getendpointinfo [EndpointName]
!rpcexts.getendpointinfo -?

Parameters

EndpointName
Specifies the number of the endpoint to be displayed. If omitted, the endpoints for all processes on the system are displayed.
-?
Displays a short help text.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | rpcexts.dll

Comments

This extension can only be used with CDB or with user-mode WinDbg.

Here is an example:

0:002> !rpcexts.getendpointinfo
Searching for endpoint info ...
PID  CELL ID   ST PROTSEQ        ENDPOINT
-------------------------------------------------------------
00a8 0000.0001 01            NMP \PIPE\InitShutdown
00a8 0000.0003 01            NMP \PIPE\SfcApi
00a8 0000.0004 01            NMP \PIPE\ProfMapApi
00a8 0000.0005 01           LRPC OLE5
00a8 0000.0007 01            NMP \pipe\winlogonrpc
00c4 0000.0001 01           LRPC ntsvcs
00c4 0000.0003 01            NMP \PIPE\ntsvcs
00c4 0000.0008 01            NMP \PIPE\scerpc
00d0 0000.0001 01            NMP \PIPE\lsass
00d0 0000.0003 01            NMP \pipe\WMIEP_d0
00d0 0000.0006 01           LRPC policyagent
00d0 0000.0007 01            NMP \PIPE\POLICYAGENT
0170 0000.0001 01           LRPC epmapper
0170 0000.0003 01            TCP 135
0170 0000.0005 01            SPX 34280
0170 0000.0006 01             NB 135
0170 0000.0007 01             NB 135
0170 0000.000b 01            NMP \pipe\epmapper
01c0 0000.0001 01            NMP \pipe\spoolss
01c0 0000.0003 01           LRPC spoolss
01c0 0000.0007 01           LRPC OLE7
020c 0000.0001 01           LRPC OLE2
020c 0000.0005 01           LRPC senssvc
020c 0000.0007 01            NMP \pipe\tapsrv
020c 0000.0009 01           LRPC tapsrvlpc
020c 0000.000c 01            NMP \PIPE\ROUTER
020c 0000.0016 01            NMP \pipe\WMIEP_20c
0218 0000.0001 01            NMP \PIPE\winreg
022c 0000.0001 01           LRPC LRPC0000022c.00000001
022c 0000.0003 01            TCP 1041
022c 0000.0005 01            SPX 24576
022c 0000.0006 01            NMP \PIPE\atsvc
0294 0000.0001 01           LRPC OLE3
0378 0000.0001 01           LRPC OLE9
026c 0000.0001 01            TCP 1118
0344 0000.0001 01           LRPC OLE12

For a similar example using the DbgRpc tool, see Get RPC Endpoint Information.

Additional Information

For more information on debugging Microsoft Remote Procedure Call (RPC), see RPC Debugging.


!rpcexts.getthreadinfo

The !rpcexts.getthreadinfo extension searches the system's RPC state information for thread information.

Syntax

!rpcexts.getthreadinfo ProcessID [ThreadID]
!rpcexts.getthreadinfo -?

Parameters

ProcessID
Specifies the process ID (PID) of the process containing the desired thread.
ThreadID
Specifies the thread ID of the thread to be displayed. If omitted, all threads in the specified process will be displayed.
-?
Displays a short help text.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | rpcexts.dll

Comments

This extension can only be used with CDB or with user-mode WinDbg.

Here is an example:

0:002> !rpcexts.getthreadinfo 26c
Searching for thread info ...
PID  CELL ID   ST TID      LASTTIME
-----------------------------------
026c 0000.0002 01 000003c4 0004caa5
026c 0000.0005 03 00000254 0004ca9b

For a similar example using the DbgRpc tool, see Get RPC Thread Information.

Additional Information

For more information on debugging Microsoft Remote Procedure Call (RPC), see RPC Debugging.


!rpcexts.help

The !rpcexts.help extension displays a help text showing all rpcexts.dll extension commands.

Syntax

!rpcexts.help

DLL

Windows NT 4.0 | Not available
Windows 2000 | rpcexts.dll
Windows XP Windows .NET Server 2003 | rpcexts.dll


!rpcexts.rpcreadstack

The !rpcexts.rpcreadstack extension reads an RPC client-side stack and retrieves the call information.

Syntax

!rpcexts.rpcreadstack ThreadStackPointer

Parameters

ThreadStackPointer
Specifies the pointer to the thread stack.

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP Windows .NET Server 2003 | rpcexts.dll

Comments

For a common use of this extension, see Analyzing a Stuck Call Problem.

Here is an example:

0:001> !rpcexts.rpcreadstack 68fba4
CallID: 1
IfStart: 19bb5061
ProcNum: 0
        Protocol Sequence:      "ncacn_ip_tcp"  (Address: 00692ED8)
        NetworkAddress: ""      (Address: 00692F38)
        Endpoint:       "1120"  (Address: 00693988)

Additional Information

For more information on debugging Microsoft Remote Procedure Call (RPC), see RPC Debugging.


!rpcexts.rpctime

The !rpcexts.rpctime extension displays the current system time.

Syntax

!rpcexts.rpctime

DLL

Windows NT 4.0 | Not available
Windows 2000 | rpcexts.dll
Windows XP Windows .NET Server 2003 | rpcexts.dll

Comments

This extension can only be used with CDB or with user-mode WinDbg.

Here is an example:

0:001> !rpcexts.rpctime
Current time is: 059931.126  (0x00ea1b.07e)


ACPI Extensions (acpikd.dll and kdexts.dll)

Extension commands which are useful for debugging ACPI (Advanced Configuration and Power Interface) BIOS code can be found in acpikd.dll and kdexts.dll.

The Windows 2000 versions of these extension commands appear in the acpikd.dll module located in the w2kfre and w2kchk directories. Note that this extension module has an internal build number of 2179, while Windows 2000 has a build number of 2195. Ignore the resulting version mismatch errors!

For Windows XP and Windows .NET Server 2003, some of the ACPI debugging extensions can be found in winxp\acpikd.dll, while others can be found in winxp\kdexts.dll.


!acpikd.help

The !acpikd.help extension displays a help text showing all acpikd.dll extension commands.

Syntax

!acpikd.help

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | acpikd.dll

Additional Information

For more information, see ACPI Debugging.


!amli ?

The !amli ? extension displays help text for the !amli extension commands.

Syntax

Windows 2000 Syntax

!acpikd.amli ? [Command]

Windows XP and Windows .NET Server 2003 Syntax

!amli ? [Command]

Parameters

Command
Specifies the !amli command whose help is to be displayed. For example, !amli ? set displays help for the !amli set command. If Command is omitted, a list of all commands is displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli bc

The !amli bc extension permanently clears an AML breakpoint.

Syntax

Windows 2000 Syntax

!acpikd.amli bc Breakpoint
!acpikd.amli bc *

Windows XP and Windows .NET Server 2003 Syntax

!amli bc Breakpoint
!amli bc *

Parameters

Breakpoint
Specifies the number of the breakpoint to be cleared.
*
Specifies that all breakpoints should be cleared.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

To determine the breakpoint number of a breakpoint, use the !amli bl extension.

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli bd

The !amli bd extension temporarily disables an AML breakpoint.

Syntax

Windows 2000 Syntax

!acpikd.amli bd Breakpoint
!acpikd.amli bd *

Windows XP and Windows .NET Server 2003 Syntax

!amli bd Breakpoint
!amli bd *

Parameters

Breakpoint
Specifies the number of the breakpoint to be disabled.
*
Specifies that all breakpoints should be disabled.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

A disabled breakpoint can be re-enabled by using the !amli be extension.

To determine the breakpoint number of a breakpoint, use the !amli bl extension.

Here is an example of this command:

kd> !amli bl
 0:  c29accf5 [\_WAK]
 1:  c29c20a5 [\_SB.PCI0.ISA.BAT1._BST]

kd> !amli bd 1

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli be

The !amli be extension enables an AML breakpoint.

Syntax

Windows 2000 Syntax

!acpikd.amli be Breakpoint
!acpikd.amli be *

Windows XP and Windows .NET Server 2003 Syntax

!amli be Breakpoint
!amli be *

Parameters

Breakpoint
Specifies the breakpoint number of the breakpoint to be enabled.
*
Specifies that all breakpoints should be enabled.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

All breakpoints are enabled when they are created. Breakpoints are only disabled if you have used the !amli bd extension.

To determine the breakpoint number of a breakpoint, use the !amli bl extension.

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli bl

The !amli bl extension displays a list of all AML breakpoints.

Syntax

Windows 2000 Syntax

!acpikd.amli bl

Windows XP and Windows .NET Server 2003 Syntax

!amli bl

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The AMLI Debugger supports a maximum of ten breakpoints.

Here is an example of the !amli bl extension:

kd> !amli bl
 0: <e> ffffffff80e5e2f1:[\_SB.LNKD._SRS]
 1: <e> ffffffff80e5d969:[\_SB.LNKB._STA]
 2: <d> ffffffff80e630c9:[\_WAK]
 3: <e> ffffffff80e612c9:[\_SB.MBRD._CRS]

The first column gives the breakpoint number. The <e> and <d> marks indicate whether the breakpoint is enabled or disabled. The address of the breakpoint is in the next column. Finally, the method containing the breakpoint is listed, with the offset of the breakpoint if it is not set at the start of the method.

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli bp

The !amli bp extension places a breakpoint in AML code.

Syntax

Windows 2000 Syntax

!acpikd.amli bp { MethodName | CodeAddress }

Windows XP and Windows .NET Server 2003 Syntax

!amli bp { MethodName | CodeAddress }

Parameters

MethodName
Specifies the full path of the method name on which the breakpoint will be set.
CodeAddress
Specifies the address of the AML code at which the breakpoint will be set. If CodeAddress is prefixed with two percent signs (%%), it is interpreted as a physical address. Otherwise it is interpreted as a virtual address.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The AMLI Debugger supports a maximum of ten breakpoints.

Here is an example. The following command will set a breakpoint on the _DCK method:

kd> !amli bp \_sb.pci0.dock._dck

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli cl

The !amli cl extension clears the AML interpreter's event log.

Syntax

Windows 2000 Syntax

!acpikd.amli cl

Windows XP and Windows .NET Server 2003 Syntax

!amli cl

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli debugger

The !amli debugger extension breaks into the AMLI Debugger.

Syntax

Windows 2000 Syntax

!acpikd.amli debugger

Windows XP and Windows .NET Server 2003 Syntax

!amli debugger

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

When this command is issued, notification is sent to the AML interpreter. The next time the interpreter is active, it will immediately break into the AMLI Debugger.

The !amli debugger extension only causes one break. If you wish it to break again, you need to use this extension again, or set a breakpoint.

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli dh

The !amli dh extension displays the AML interpreter's internal heap block.

Syntax

Windows 2000 Syntax

!acpikd.amli dh [HeapAddress]

Windows XP and Windows .NET Server 2003 Syntax

!amli dh [HeapAddress]

Parameters

HeapAddress
Specifies the address of the heap block. If this is omitted, the global heap is displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

In Windows 2000, this command is available only if you are using the checked build of this extension (w2kchk\acpikd.dll).

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli dl

The !amli dl extension displays a portion of the AML interpreter's event log.

Syntax

Windows 2000 Syntax

!acpikd.amli dl

Windows XP and Windows .NET Server 2003 Syntax

!amli dl

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The event log chronicles the most recent 150 events that occurred in the interpreter.

Here is an example of the log display:

kd> !amli dl
RUN!: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000000: Ctx=c18b4000,rc=0
KICK: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000000: rc=0
SYNC: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000002,LockPhase=0,Locked=0,IRQL=00: Obj=\_WAK
ASYN: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000002,LockPhase=0,Locked=0,IRQL=00: Obj=\_WAK
REST: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000002: Ctx=c18b4000,Obj=\_WAK
INSQ: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000002: Ctx=c18b4000,Obj=\_WAK
EVAL: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000002: Ctx=c18b4000,Obj=\_WAK
RUNC: [c15a6618]QTh=c15a6618,QCt=c18b4000,QFg=00000002: Ctx=c18b4000,Obj=\_WAK

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli dns

The !amli dns extension displays an ACPI namespace object.

Syntax

Windows 2000 Syntax

!acpikd.amli dns [/s] [Name | Address]

Windows XP and Windows .NET Server 2003 Syntax

!amli dns [/s] [Name | Address]

Parameters

/s
Causes the entire namespace subtree under the specified object to be displayed recursively.
Name
Specifies the namespace path.
Address
Specifies the address of the namespace node.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

If neither Name nor Address is specified, the entire ACPI namespace tree is displayed recursively. The /s parameter is always assumed in this case, even if it is not specified.

This command is useful for determining what a particular namespace object is — whether it is a method, a fieldunit, a device, or another type of object.

Without the /s parameter, this extension is equivalent to the !nsobj extension. With the /s parameter, it is equivalent to the !nstree extension.

Here are some examples. The following command displays the namespace for the object bios:

AMLI(? for help)-> dns \bios

ACPI Name Space: \BIOS (80E5F378)
OpRegion(BIOS:RegionSpace=SystemMemory,Offset=0xfcb07500,Len=2816)

The following command displays the namespace for the object _BST, and the tree subordinate to it:

kd> !amli dns /s \_sb.pci0.isa.bat1._bst

ACPI Name Space: \_SB.PCI0.ISA.BAT1._BST (c29c2044)
Method(_BST:Flags=0x0,CodeBuff=c29c20a5,Len=103)

To display the namespace for the device BAT1, type:

kd> !amli dns /s \_sb.pci0.isa.bat1

To display the namespace of everything subordinate to the DOCK device, type:

kd> !amli dns /s \_sb.pci0.dock

To display the namespace subordinate to the _DCK method, type:

kd> !amli dns /s \_sb.pci0.dock._dck

To display the entire namespace, type:

kd> !amli dns

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli do

The !amli do extension displays an AML data object.

Syntax

Windows 2000 Syntax

!acpikd.amli do Address

Windows XP and Windows .NET Server 2003 Syntax

!amli do Address

Parameters

Address
Specifies the address of the data object.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli ds

The !amli ds extension displays an AML stack.

Syntax

Windows 2000 Syntax

!acpikd.amli ds [/v] [Address]

Windows XP and Windows .NET Server 2003 Syntax

!amli ds [/v] [Address]

Parameters

/v
Causes the display to be more verbose. In Windows 2000, this option is available only if you are using the checked build of this extension (w2kchk\acpikd.dll).
Address
Specifies the address of the context block whose stack is desired. If Address is omitted, the current context is used.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli find

The !amli find extension finds an ACPI namespace object.

Syntax

Windows 2000 Syntax

!acpikd.amli find Name

Windows XP and Windows .NET Server 2003 Syntax

!amli find Name

Parameters

Name
Specifies the name of the namespace object (without the path).

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

The !amli find command takes the name of the object and returns the full path and name. The Name parameter must be the final segment of the full path and name.

Here are some examples. The following command will find all declarations of the object _SRS:

kd> !amli find _srs
\_SB.LNKA._SRS
\_SB.LNKB._SRS
\_SB.LNKC._SRS
\_SB.LNKD._SRS

This is not simply a text search. The command !amli find srs would not display any hits, since the final segment of each of these declarations is "_SRS", not "SRS". The command !amli find LNK would similary return no hits. The command !amli find LNKB would display the single node that terminates in "LNKB", not the four children of this node shown in the previous display:

kd> !amli find lnkb
\_SB.LNKB.

If you need to see the children of a node, use the !amli dns command with the /s parameter.

Here is another example, issued from the AMLI Debugger prompt. This shows all declarations of the object _BST in the namespace:

AMLI(? for help)-> find _bst
\_SB.PCI0.ISA.BAT1._BST
\_SB.PCI0.ISA.BAT2._BST

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli lc

The !amli lc extension lists all active ACPI contexts.

Syntax

Windows 2000 Syntax

!acpikd.amli lc

Windows XP and Windows .NET Server 2003 Syntax

!amli lc

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

Each context corresponds to a method currently running in the AML interpreter.

Here is an example:

AMLI(? for help)-> lc
 Ctxt=80e3f000, ThID=00000000, Flgs=A--C-----, pbOp=00000000, Obj=\_SB.LNKA._STA
 Ctxt=80e41000, ThID=00000000, Flgs=A--C-----, pbOp=00000000, Obj=\_SB.LNKB._STA
 Ctxt=80e9a000, ThID=00000000, Flgs=A--C-----, pbOp=00000000, Obj=\_SB.LNKC._STA
 Ctxt=80ea8000, ThID=00000000, Flgs=A--C-----, pbOp=00000000, Obj=\_SB.LNKD._STA
*Ctxt=80e12000, ThID=80e6eda8, Flgs=---CR----, pbOp=80e5d5ac, Obj=\_SB.LNKA._STA

The Obj field gives the full path and name of the method as it appears in the ACPI tables.

The Ctxt field gives the address of the context block. The asterisk (*) indicates the current context. This is the context that was being executed by the interpreter when the break occurred.

The abbreviation pbOp indicates the instruction pointer ("pointer to binary op codes").

There are nine flags that can be displayed in the Flgs section. If a flag is not set, a hyphen is displayed instead. The full list of flags is as follows:

Flag | Meaning
A | Asynchronous evaluation
N | Nested evaluation
Q | In the ready queue
C | Needs a callback
R | Running
W | Ready
T | Timeout
D | Timer dispatch
P | Timer pending

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli ln

The !amli ln extension displays the specified method, or the method containing a given address.

Syntax

Windows 2000 Syntax

!acpikd.amli ln [ MethodName | CodeAddress ]

Windows XP and Windows .NET Server 2003 Syntax

!amli ln [ MethodName | CodeAddress ]

Parameters

MethodName
Specifies the full path of the method name. If MethodName specifes an object that is not actually a method, an error results.
CodeAddress
Specifies the address of the AML code that is contained in the desired method. If CodeAddress is prefixed with two percent signs (%%), it is interpreted as a physical address. Otherwise it is interpreted as a virtual address.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

If neither MethodName nor CodeAddress are specified, the method associated with the current context is displayed.

The following command shows the method being currently run:

kd> !amli ln
c29accf5: \_WAK

The method _WAK is shown, with address 0xC29ACCF5.

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli r

The !amli r extension displays information about the current context, or about the specified context.

Syntax

Windows 2000 Syntax

!acpikd.amli r [ContextAddress]

Windows XP and Windows .NET Server 2003 Syntax

!amli r [ContextAddress]

Parameters

Address
Specifies the address of the context block to be displayed. The address of a context block can be determined from the Ctxt field in the !amli lc display. If ContextAddress is prefixed with two percent signs (%%), it is interpreted as a physical address. Otherwise it is interpreted as a virtual address. If this parameter is omitted, the current context is displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

If the AMLI Debugger prompt appears suddenly, this is a useful command to use.

For example, the following command will display the current context of the interpreter:

AMLI(? for help)-> r

Context=c18b4000*, Queue=00000000, ResList=00000000
ThreadID=c15a6618, Flags=00000010
StackTop=c18b5eec, UsedStackSize=276 bytes, FreeStackSize=7636 bytes
LocalHeap=c18b40c0, CurrentHeap=c18b40c0, UsedHeapSize=88 bytes
Object=\_WAK, Scope=\_WAK, ObjectOwner=c18b4108, SyncLevel=0
AsyncCallBack=ff06b5d0, CallBackData=0, CallBackContext=c99efddc

MethodObject=\_WAK
80e0ff5c: Local0=Unknown()
80e0ff70: Local1=Unknown()
80e0ff84: Local2=Unknown()
80e0ff98: Local3=Unknown()
80e0ffac: Local4=Unknown()
80e0ffc0: Local5=Unknown()
80e0ffd4: Local6=Unknown()
80e0ffe8: Local7=Unknown()
80e0e040: RetObj=Unknown()

Next AML Pointer: ffffffff80e630df:[\_WAK+16]

ffffffff80e630df : If(S4BW
ffffffff80e630e5 : {
ffffffff80e630e5 : | Store(Zero, S4BW)
ffffffff80e630eb : }

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli set

The !amli set extension sets or displays the AMLI Debugger options.

Syntax

Windows 2000 Syntax

!acpikd.amli set Options

Windows XP and Windows .NET Server 2003 Syntax

!amli set Options

Parameters

Options
Specifies one or more options to be set. Separate multiple options with spaces. Possible values include:
spewon
(Windows XP and Windows .NET Server 2003 only) Causes full debug output to be sent from the target computer. This option should be left on at all times for effective AML debugging. See the Comments section for details.
spewoff
(Windows XP and Windows .NET Server 2003 only) Suppresses debug output.
verboseon
Turns on verbose mode. This causes the AMLI Debugger to display the names of AML methods as they are evaluated.
verboseoff
Turns off verbose mode.
traceon
Activates ACPI tracing. This produces much more output than the verboseon option. This option is very useful for tracking SMI-related hard hangs.
traceoff
Deactivates ACPI tracing.
nesttraceon
Activates nest tracing. This option is only effective if the traceon option is also selected.
nesttraceoff
Deactivates nest tracing.
lbrkon
Breaks into the AMLI Debugger when DDB loading is completed.
lbrkoff
Deactivates the lbrkon option.
errbrkon
Breaks into the AMLI Debugger whenever the interpreter has a problem evaluating AML code.
errbrkoff
Deactivates the errbrkon option.
logon
Enables event logging.
logoff
Disables event logging.
logmuton
Enables mutex event logging.
logmutoff
Disables mutex event logging.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

If no options are specified, the current status of all options is displayed.

In Windows NT and Windows 2000, full debug output is always sent to the debugger. However, Windows XP and Windows .NET Server 2003 usually filter out most of these messages. If you are running the AMLI Debugger on these systems, you need to turn this output on with !amli set spewon, or else many important AMLI Debugger messages will be lost.

If the AML interpreter breaks into the AMLI Debugger, this output will be automatically turned on.

For more details on this output filtering, see DbgPrintEx and KdPrintEx in the Windows DDK.

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!amli u

The !amli u extension unassembles AML code.

Syntax

Windows 2000 Syntax

!acpikd.amli u [ MethodName | CodeAddress ]

Windows XP and Windows .NET Server 2003 Syntax

!amli u [ MethodName | CodeAddress ]

Parameters

MethodName
Specifies the full path of the method name to be disassembled.
CodeAddress
Specifies the address of the AML code where disassembly will begin. If CodeAddress is prefixed with two percent signs (%%), it is interpreted as a physical address. Otherwise it is interpreted as a virtual address.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

If neither MethodName nor CodeAddress are specified, and you are issuing this command from an AMLI Debugger prompt, the disassembly starts at the beginning of the current method.

The disassembly display will continue until the end of the method is reached.

Note The standard U (Unassemble) command will not give proper results with AML code.

Here are some examples. To disassemble the object at address 0x80E5D701, use the following command:

kd> !amli u 80e5d701

ffffffff80e5d701 : CreateWordField(CRES, 0x1, IRQW)
ffffffff80e5d70c : And(\_SB_.PCI0.LPC_.PIRA, 0xf, Local0)
ffffffff80e5d723 : Store(One, Local1)
ffffffff80e5d726 : ShiftLeft(Local1, Local0, IRQW)
ffffffff80e5d72d : Return(CRES)

The following command will disassemble the _DCK method:

kd> u \_sb.pci0.dock._dck

Additional Information

For information about related commands and their uses, see The AMLI Debugger.


!facs

The !facs extension displays a Firmware ACPI Control Structure (FACS).

Syntax

Windows 2000 Syntax

!acpikd.facs Address

Windows XP and Windows .NET Server 2003 Syntax

!facs Address

Parameters

Address
Specifies the address of the FACS.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

For more information, see ACPI Debugging.


!fadt

The !fadt extension displays a Fixed ACPI Description Table (FADT).

Syntax

Windows 2000 Syntax

!acpikd.fadt Address

Windows XP and Windows .NET Server 2003 Syntax

!fadt Address

Parameters

Address
Specifies the address of the FADT.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

For more information, see ACPI Debugging.


!mapic

The !mapic extension displays an ACPI Multiple APIC table.

Syntax

Windows 2000 Syntax

!acpikd.mapic Address

Windows XP and Windows .NET Server 2003 Syntax

!mapic Address

Parameters

Address
Specifies the address of the Multiple APIC Table.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

For more information, see ACPI Debugging.


!nsobj

The !nsobj extension displays an ACPI namespace object.

Syntax

Windows 2000 Syntax

!acpikd.nsobj [Address]

Windows XP and Windows .NET Server 2003 Syntax

!nsobj [Address]

Parameters

Address
Specifies the address of the namespace object. If this is omitted, the root of the namespace tree is used.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This extension is equivalent to !amli dns.

Additional Information

For more information, see ACPI Debugging.


!nstree

The !nstree extension displays an ACPI namespace object and its children in the namespace tree.

Syntax

Windows 2000 Syntax

!acpikd.nstree [Address]

Windows XP and Windows .NET Server 2003 Syntax

!nstree [Address]

Parameters

Address
Specifies the address of the namespace object. This object and the entire namespace tree subordinate to it will be displayed. If Address is omitted, the entire namespace tree is displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Comments

This extension is equivalent to !amli dns /s.

Additional Information

For more information, see ACPI Debugging.


!rsdt

The !rsdt extension displays the ACPI Root System Description Table.

Syntax

Windows 2000 Syntax

!acpikd.rsdt

Windows XP and Windows .NET Server 2003 Syntax

!rsdt

DLL

Windows NT 4.0 | Not available
Windows 2000 | acpikd.dll
Windows XP Windows .NET Server 2003 | kdexts.dll

Additional Information

For more information, see ACPI Debugging.


Graphics Driver Extensions (gdikdx.dll)

Extension commands which are useful for debugging the Graphics Driver Interface (GDI) can be found in gdikdx.dll.

The Windows NT 4.0 version of this extension DLL appears in the nt4fre and nt4chk directories. The Windows 2000 version of this extension DLL appears in the w2kfre and w2kchk directories. There is no Windows XP or Windows .NET Server 2003 version of this extension DLL.


!gdikdx.verifier

The !gdikdx.verifier extension displays the status of Driver Verifier during the verification of a graphics driver.

Syntax

!gdikdx.verifier  [-Flags]

Parameters

Flags
Specifies what information will be displayed in the output from this command. Any combination of the following (preceded by a hyphen) is allowed:
d
Causes the display to include statistics on Memory Pool Tracking. This includes the address, size, and tag of each pool.
h (or ?)
Displays a brief help text about this command.

DLL

Windows NT 4.0 | Not available
Windows 2000 | gdikdx.dll
Windows XP Windows .NET Server 2003 | Not available

Comments

When verifying drivers that are not graphics drivers, the standard kernel-mode extension !verifier should be used instead of !gdikdx.verifier.

Regardless of which flags are selected, this extension will display the Driver Verifier options that are active. It will also display statistics on the frequency of random failure.

Additional Information

For information on Driver Verifier, see the Windows DDK.


OEM Support Extensions (kdex2x86.dll)

The OEM Support Extensions can be found in nt4fre\kdex2x86.dll and w2kfre\kdex2x86.dll.

These extension commands are not described in this documentation.

For descriptions of these extensions, see the OEM Support Tools documentation. To get this documentation, along with the entire OEM Support Tools package, search for Knowledge Base article Q253066 at http://support.microsoft.com/default.aspx and follow the instructions on that page.


Debugger-Related APIs

This reference section includes:

Routines in Wdbgexts.h

The Symbol Server API


Routines in Wdbgexts.h

The routines in this section of the reference are exposed by the wdbgexts.h header file. This file is shipped with the Microsoft® Windows® DDK.

These routines are intended for use in debugger extension commands. Writers of new debugger extensions will find these routines useful for controlling and inspecting the computer or application being debugged. The wdbgexts.h header file should be included by any code calling these routines.

For further information, see Writing New Debugger Extensions.


CheckControlC

Checks to see if the user pressed CTRL+C. Use CheckControlC in all loops to allow the user to press CTRL+C to end long processes.

ULONG
  CheckControlC (
    VOID
    );

Return Value

If the user has pressed CTRL+C, the return value is TRUE; otherwise, it is FALSE.


Disassm

Disassembles the instruction pointed to by lpOffset and places the printable string into lpBuffer.

ULONG
  Disassm (
    PULONG lpOffset,
    PCSTR lpBuffer,
    ULONG fShowEffectiveAddress
    );

Parameters

lpOffset
Pointer to the instruction to be disassembled.
lpBuffer
Returns the disassembled instruction.
fShowEffectiveAddress
Controls whether or not to print the effective address, if appropriate.

Return Value

If the routine succeeds, the return value is TRUE; otherwise, it is FALSE.


dprintf

Prints a formatted string to the Debugger Command window. Works like the C-language routine printf.

VOID
  dprintf (
    PCSTR format
    . . . .  [arguments]
    );

Parameters

format
Pointer to the format string to print, as in printf.
arguments
Arguments for the format string, as in printf.


GetContext

GetContext is similar to the Microsoft Win32® GetThreadContext routine. It returns the context of the process being debugged.

ULONG
  GetContext (
    ULONG Target,
    PCONTEXT lpContext,
    ULONG cbSizeOfContext
    );

Parameters

Target
User mode: Specifies the thread ID of the thread being debugged.

Kernel Mode: Specifies the processor number of the processor being debugged.

lpContext
Points to the address of a context structure that receives the appropriate context of the process being debugged. The context structure is highly machine-specific.
cbSizeOfContext
Specifies the size of the context structure.

Return Value

If the routine succeeds, the return value is TRUE; otherwise, it is FALSE.


GetDebuggerData

GetDebuggerData retrieves information stored in a data block.

ULONG
  GetDebuggerData (
    ULONG Tag,
    PVOID Buf,
    ULONG Size
    );

Parameters

Tag
This should be set equal to KDBG_TAG. (This value is specified in wdbgexts.h.)
Buf
Pointer to the debugger data block.
Size
Specifies the size of the data block, including the header.

Return Value

If the data block is found, the return value is TRUE; otherwise, it is FALSE.


GetExpression

Returns the value of expression. The expression is evaluated using the assembler-style expression evaluator.

ULONG
  GetExpression (
    PCSTR expression
    );

Parameters

expression
The expression to evaluate.

Return Value

The value of the expression passed to GetExpression.


GetKdContext

GetKdContext returns the total number of processors and the number of the current processor in the structure ppi points to.

ULONG
  GetKdContext (
    PPROCESSORINFO ppi
    );

Parameters

ppi
Pointer to the following structure:
typedef struct _tagPROCESSORINFO {
  USHORT  Processor;           // current processor
  USHORT  NumberProcessors;    // total number of processors
} PROCESSORINFO, *PPROCESSORINFO;

Return Value

The total number of processors


GetSetSympath

GetSetSympath can be used to either get or set the symbol search path.

VOID
  GetSetSympath (
    IN PSTR Arg,
    OUT PSTR Result OPTIONAL,
    IN int Length
    );

Parameters

Arg
The new search path. If this argument is NULL or the string is empty, the search path is not set, and the current setting is returned in Result.
Result
Optional. If Arg is NULL, GetSetSympath stores the current search path in the buffer pointed to by Result.
Length
The size of the buffer for storing the result.

Comments

When the symbol path is changed, a call to ReloadSymbols is made implicitly.


GetSymbol

Locates the symbol nearest to address.

VOID
  GetSymbol (
    PVOID offset,
    PUCHAR pchBuffer,
    PULONG pDisplacement
    );

Parameters

offset
An address near the symbol you want located.
pchBuffer
Returns the name of the symbol found.
pDisplacement
The displacement from the beginning of the symbol.


Ioctl

Ioctl is the entry-point for many of the functionalities supplied for kernel debugger extension routines. (Many of the other routines in this section are simply wrappers for calls to Ioctl.)

ULONG
  Ioctl (
    USHORT IoctlType,
    PVOID lpvData,
    ULONG cbSizeOfContext
    );

Parameters

IoctlType
Type of Ioctl routine call.
lpvData
Points to the address of an IoctlType-specific structure.
cbSizeOfContext
The size of the structure lpvData points to.

Return Value

Meaning of return value depends on IoctlType.


ReadControlSpace

Reads the processor-specific control space into the array pointed to by buf.

VOID
  ReadControlSpace (
    USHORT processor,
    ULONG address,
    PVOID buf,
    ULONG size
    );

Parameters

processor
The number of the processor whose control space is to be read.
address
The address of the control space.
buf
The address of an array of bytes to hold the control space data.
size
The number of bytes in the array pointed to by buf.


ReadIoSpace

Reads from the system I/O locations.

VOID
  ReadIoSpace (
    ULONG address,
    PULONG data,
    PULONG size
    );

Parameters

address
The I/O address to read from.
data
The address of a variable to hold the data read (must be at least size bytes long).
size
The address of a variable that contains the number of bytes to read (1, 2, or 4 only). After the data is read, size will contain the number of bytes actually read.


ReadIoSpaceEx

ReadIoSpaceEx is an extended version of ReadIoSpace. It reads not only the system I/O locations, but also I/O locations on a bus. ReadIoSpace works like ReadIoSpaceEx, except that it defaults interfacetype to ISA, busnumber to zero, and addressspace to one.

VOID
  ReadIoSpaceEx (
    ULONG address,
    PULONG data,
    PULONG size,
    ULONG interfacetype,
    ULONG busnumber,
    ULONG addressspace
    );

Parameters

address
The I/O address to read from.
data
The address of a variable to hold the data read (must be at least size bytes long).
size
The address of a variable that contains the number of bytes to read (1, 2, or 4 only). After the data is read, size will contain the number of bytes actually read.
interfacetype
The type of interface on which the extended I/O space exists. Values include ISA, EISA, and MCA. For more information, see ntddk.h, which is available as part of Windows DDK.
busnumber
The number of the bus on which the extended I/O space exists. This is typically zero, unless there is more than one bus of a given type.
addressspace
This is typically one.


ReadMemory

ReadMemory works like the Win32 ReadProcessMemory function. It reads memory from the process being debugged. The entire area to be read must be accessible, or the operation fails.

ULONG
  ReadMemory (
    ULONG offset,
    PVOID lpBuffer,
    ULONG cb,
    PULONG lpcbBytesRead
    );

Parameters

offset
The base address in the process being debugged of the memory to be read.
lpBuffer
Pointer to the buffer to receive the memory read.
cb
The number of bytes that you want ReadMemory to read.
lpcbBytesRead
The actual number of bytes that ReadMemory transferred into the buffer. This parameter is optional; if it is NULL, it is ignored.

Return Value

If the routine succeeds, the return value is TRUE; otherwise, it is FALSE.


ReadMsr

ReadMsr reads the contents of a Model Specific Register on an Intel Pentium® family processor. Refer to Intel Corporation's Pentium and Pentium Pro documentation for more details.

VOID
  ReadMsr (
    ULONG MsrReg,
    ULONGLONG *MsrValue,
    );

Parameters

MsrReg
ID number of the Model Specific Register.
MsrValue
Pointer to store value of register.


ReadPhysical

Reads from physical memory.

VOID
  ReadPhysical (
    LARGE_INTEGER address,
    PVOID buf,
    ULONG size,
    PULONG sizer
    );

Parameters

address
The physical address to read.
buf
The address of an array of bytes to hold the data read.
size
The number of bytes to read.
sizer
The address of a variable to receive the number of bytes actually read.


SetContext

SetContext is similar to the Win32 SetThreadContext routine. It sets the context of the process being debugged.

ULONG
  SetContext (
    ULONG Target,
    PCONTEXT lpContext,
    ULONG cbSizeOfContext
    );

Parameters

Target
User mode: Specifies the thread ID of the thread being debugged.

Kernel Mode: Specifies the processor number of the processor being debugged.

lpContext
Points to the address of a context structure that contains the context to be set for the process being debugged. The context structure is highly machine-specific.
cbSizeOfContext
Specifies the size of the context structure.

Return Value

If the routine succeeds, the return value is TRUE; otherwise, it is FALSE.


SetThreadForOperation

SetThreadForOperation sets the thread to use for the next StackTrace call.

VOID
  SetThreadForOperation (
    PULONG Thread
    );

Parameters

Thread
Pointer to thread object to be used for next stack trace.


StackTrace

Retrieves a stack trace for the process being debugged. Returns the number of frames read into the buffer pointed to by StackFrames.

ULONG
  StackTrace (
    ULONG FramePointer,
    ULONG StackPointer,
    ULONG ProgramCounter,
    PEXTSTACKTRACE StackFrames,
    ULONG Frames
    );

Parameters

FramePointer
Specifies the frame pointer. If no specific value is desired, this should simply be set to zero.
StackPointer
Specifies the stack pointer. If no specific value is desired, this should simply be set to zero.
ProgramCounter
Specifies the instruction pointer. If no specific value is desired, this should simply be set to zero.
StackFrames
Pointer to a buffer that is large enough to hold the number of stack frames specified by Frames. The stack frames are stored in the following data structure:
typedef struct _tagEXTSTACKTRACE {
    ULONG       FramePointer;
    ULONG       ProgramCounter;
    ULONG       ReturnAddress;
    ULONG       Args[4];
} EXTSTACKTRACE, *PEXTSTACKTRACE;
Frames
The maximum number of frames that will fit into the buffer.

Return Value

The actual number of frames written to the buffer pointed to by StackFrames.


WriteIoSpace

Writes to the system I/O locations.

VOID
  WriteIoSpace (
    ULONG address,
    ULONG data,
    PULONG size
    );

Parameters

address
The I/O address to write to.
data
The address of a variable that holds the data to write (must be at least size bytes long).
size
The address of a variable that contains the number of bytes to write (1, 2, or 4 only). After the data is written, size will contain the number of bytes actually written.


WriteIoSpaceEx

WriteIoSpaceEx is an extended version of WriteIoSpace. It writes not only to the system I/O locations, but also I/O to locations on a bus. WriteIoSpace works like WriteIoSpaceEx, except that it defaults interfacetype to ISA, busnumber to zero, and addressspace to one.

VOID
  WriteIoSpaceEx (
    ULONG address,
    ULONG data,
    PULONG size,
    ULONG interfacetype,
    ULONG busnumber,
    ULONG addressspace
    );

Parameters

address
The I/O address to write to.
data
The address of a variable that holds the data to write (must be at least size bytes long).
size
The address of a variable that contains the number of bytes to write (1, 2, or 4 only). After the data is written, size will contain the number of bytes actually written.
interfacetype
The type of interface on which the extended I/O space exists. Values include ISA, EISA, and MCA. For more information, see ntddk.h, which is available as part of the Windows DDK.
busnumber
The number of the bus on which the extended I/O space exists. This is typically zero, unless there is more than one bus of a given type.
addressspace
This is typically one.


WriteMemory

WriteMemory works like the Win32 WriteProcessMemory routine. It writes memory to the process being debugged. The entire area to be written must be accessible, or the operation fails.

ULONG
  WriteMemory (
    ULONG offset,
    LPCVOID lpbuffer,
    ULONG cb,
    PULONG lpcbBytesWritten
    );

Parameters

offset
The base address in the process being debugged of the memory to be written.
lpbuffer
Pointer to the buffer that contains the data to be written.
cb
The number of bytes that WriteMemory should write.
lpcbBytesWritten
The number of bytes that WriteMemory transferred from the buffer. This parameter is optional; if it is NULL, it is ignored.

Return Value

If the routine succeeds, the return value is TRUE; otherwise, it is FALSE.


WriteMsr

WriteMsr writes to a Model-Specific Register on a Pentium family processor.

VOID
  WriteMsr (
    ULONG MsrReg,
    ULONGLONG MsrValue
    );

Parameters

MsrReg
ID number of the Model-Specific Register.
MsrValue
New value of register.


WritePhysical

Writes to physical memory.

VOID
  WritePhysical (
    LARGE_INTEGER address,
    PVOID buf,
    ULONG size,
    PULONG sizew
    );

Parameters

address
The physical address to write.
buf
The address of an array of bytes to hold the data written.
size
The number of bytes to write.
sizew
The address of a variable to receive the number of bytes actually written.


The Symbol Server API

The routines in this section of the reference are needed if you wish to write your own symbol server. See Using Other Symbol Servers for details.

These routines are part of the DbgHelp interface. For full documentation regarding this interface, see the Platform SDK.


SymbolServer

The SymbolServer function is an entry point to the symbol server DLL. It is used to locate a symbol file. The PSYMBOLSERVERPROC type defines a pointer to this callback function. SymbolServer is a placeholder for the library-defined function name.

BOOL CALLBACK SymbolServer(
  LPCSTR params,
  LPCSTR filename,
  PVOID  id,
  DWORD  two,
  DWORD  three,
  LPSTR  path
);

Parameters

params
[in] Pointer to a string that specifies server-specific information. This information is used to identify which store to use for locating symbols. For more information, see Using Symbol Servers and Symbol Stores.
filename
[in] The name of the symbol file to be returned.
id
[in] The first of three identifying parameters (see Remarks).
two
[in] The second of three identifying parameters (see Remarks).
three
[in] The third of three identifying parameters (see Remarks).
path
[out] A buffer that receives the fully qualified path to the symbol file. This buffer must be at least MAX_PATH bytes long.

Return Values

If the server locates a valid symbol file, it returns TRUE; otherwise, it returns FALSE and GetLastError returns a value that indicates why the symbol file was not returned.

Remarks

The identifying parameters are filled in as follows.

  • If DbgHelp is looking for a .dbg file, the id parameter contains the TimeDateStamp of the original image as found in its PE header. Parameter two contains the SizeOfImage field, also extracted from the PE header. Parameter three is unused and set to zero.
  • If DbgHelp is looking for a .pdb file, the id parameter contains the PDB signature as found in the codeview debug directory of the original image. Parameter two contains the PDB age. Parameter three is unused and set to zero.
  • If DbgHelp is looking for any other type of image, such as an executable file, it is probably being called through the SymFindFileInPath function. In this case, the parameters are opaque to DbgHelp. However, if this function is being used to retrieve an executable file, it is expected that the parameters will be filled in as for a .dbg file, using TimeDateStamp and the image size as parameters.

Requirements

Windows NT/2000/XP: Included in Windows XP.
Redistributable: Requires DbgHelp.dll 5.1 on Windows NT 4.0; Windows 2000; and Windows 95/98/Me.
Header: Declared in DbgHelp.h.

Additional Information

For more details regarding functions in the Debug Help library, see the Platform SDK.


SymbolServerClose

The SymbolServerClose function is an entry point to the symbol server DLL. It is called every time the SymCleanup function is called. The PSYMBOLSERVERCLOSEPROC type defines a pointer to this callback function. SymbolServerGetOptions is a placeholder for the library-defined function name.

BOOL SymbolServerClose( );

Parameters

This function has no parameters.

Return Values

The server can return TRUE to indicate success, or return FALSE and call the SetLastError function to indicate an error condition.

Requirements

Windows NT/2000/XP: Included in Windows XP.
Redistributable: Requires DbgHelp.dll 5.1 on Windows NT 4.0; Windows 2000; and Windows 95/98/Me.
Header: Declared in DbgHelp.h.

Additional Information

For more details regarding functions in the Debug Help library, see the Platform SDK.


SymbolServerGetOptions

The SymbolServerGetOptions function is an entry point to the symbol server DLL. It is used to retrieve the symbol server options. The PSYMBOLSERVERGETOPTIONSPROC type defines a pointer to this callback function. SymbolServerGetOptions is a placeholder for the library-defined function name.

UINT_PTR CALLBACK SymbolServerGetOptions();

Parameters

This function has no parameters.

Return Values

The function returns the symbol server options that have been set.

Remarks

If you are using SymSrv (symsrv.dll) as your symbol server, the return value will be a sum of the following values.

Value | Meaning
SSRVOPT_CALLBACK | Indicates that SymSrv is expecting a callback function.
SSRVOPT_DWORD | Indicates that the id parameter passed to the SymbolServer function is a DWORD value. (This is the default, even if this option does not appear.)
SSRVOPT_DWORDPTR | Indicates that the id parameter passed to the SymbolServer function is a pointer to a DWORD.
SSRVOPT_GUIDPTR | Indicates that the id parameter passed to the SymbolServer function is a pointer to a GUID.
SSRVOPT_UNATTENDED | Indicates that SymSrv will never display dialog boxes or popups.
SSRVOPT_NOCOPY | Indicates that SymSrv will not verify that the path parameter passed out by the SymbolServer function actually exists. In this case, SymbolServer will always return a TRUE value.
SSRVOPT_PARENTWIN | Indicates that SymSrv is using a user-specified window as the parent window of all dialog boxes and popups, rather than using the desktop window.

Requirements

Windows NT/2000/XP: Included in Windows XP.
Redistributable: Requires DbgHelp.dll 5.1 on Windows NT 4.0; Windows 2000; and Windows 95/98/Me.
Header: Declared in DbgHelp.h.

Additional Information

For more details regarding functions in the Debug Help library, see the Platform SDK.


SymbolServerSetOptions

The SymbolServerSetOptions function is an entry point to the symbol server DLL. It is used to set the symbol server options. The PSYMBOLSERVERSETOPTIONSPROC type defines a pointer to this callback function. SymbolServerSetOptions is a placeholder for the library-defined function name.

BOOL CALLBACK SymbolServerSetOptions(
  UINT_PTR options,
  ULONG64  data
);

Parameters

options
Specifies the options to be set.
data
Server-specific data.

Return Values

The server can return TRUE to indicate success, or return FALSE and call the SetLastError function to indicate an error condition.

Remarks

If you are using SymSrv (symsrv.dll) as your symbol server, the option parameter should be one of the SSRVOPT_XXX constants defined in dbghelp.h. The meaning of the data parameter depends on the value of options. The following values are possible:

Value of id parameter | Type of data parameter | Meaning
SSRVOPT_CALLBACK | PSYMBOLSERVERCALLBACKPROC | Specifies a callback function. The value of data gives a pointer to this function. If data is NULL, any previously-set callback function is ignored.
SSRVOPT_PARAMTYPE | UINT_PTR | Indicates the data type of the id parameter passed to the SymbolServer function. The value of data indicates the desired type. The following values for data are permitted: SSRVOPT_DWORD (indicates a DWORD value — this is the default); SSRVOPT_DWORDPTR (indicates a pointer to a DWORD); SSRVOPT_GUIDPTR (indicates a pointer to a GUID).
SSRVOPT_UNATTENDED | ULONG64 | If data is nonzero, this instructs SymSrv to never display dialog boxes or popups. If data is zero, SymSrv will display these graphical features when making WinInet connections.
SSRVOPT_NOCOPY | ULONG64 | If data is nonzero, SymSrv will not verify that the path parameter passed out by the SymbolServer function actually exists. In this case, SymbolServer will always return a TRUE value. If data is zero, this option will be turned off.
SSRVOPT_PARENTWIN | HWND | SymSrv will use data to identify the parent window that should be used for all dialog boxes and popups. If data is NULL, SymSrv will use the desktop window as the parent (this is the default).

Requirements

Windows NT/2000/XP: Included in Windows XP.
Redistributable: Requires DbgHelp.dll 5.1 on Windows NT 4.0; Windows 2000; and Windows 95/98/Me.
Header: Declared in DbgHelp.h.

Additional Information

For more details regarding functions in the Debug Help library, see the Platform SDK.


Debugger Error and Warning Messages

This reference section describes some of the error and warning messages that the debugger can display.


dbgerr001: PEB is paged out

Debugger error dbgerr001 displays the message "PEB is paged out." This error indicates that the process environment block (PEB) is not accessible.

To load symbols, the debugger looks at the list of modules loaded by the operating system. The pointer to the user-mode module list is one of the items stored in the PEB.

In order to reclaim memory, the Memory Manager may page out user-mode data to make space for other process or kernel mode components.

When this error occurs, it means that the debugger has detected that the PEB data structure for this process is no longer readable. Most likely, is has been paged out to disk.

Without this data structure, the debugger can not determine which images symbols should be loaded for.

Note This only affects symbol files for the user-mode modules. Kernel-mode modules and symbols are not affected, as they are tracked in a different list.


dbgerr002: Bad pointer

Debugger error dbgerr002 displays the message "Bad pointer." This error indicates a problem retrieving a symbol file.

The symbol server has the file indexed, but is being redirected to another location to find the file. No file is accessible at this other location.

Two common causes of this problem are:

  • the path is a UNC path, and the computer containing this server is not available,
  • the path indicates a directory or file that has been deleted.

If your symbol store was created by using SymStore, you can find the full path to this file by examining file.ptr. For details, see Using SymStore.


dbgerr003: Mismatched symbols

Debugger error dbgerr003 displays the message "File has mismatched symbols." This error indicates that the symbol file corresponding to the executable File is not the correct version.

The debugger has indeed found a symbol file at the location mentioned. However, DbgHelp thinks that this symbol file may not be the correct file, probably due to a version mismatch.

The debugger may end up loading this symbol file anyway, depending on what else it finds in the path.


dbgerr004: Page not present in dump file

Debugger error dbgerr004 displays the message "Page number not present in dump file." This error indicates that the debugger needed a memory page that was not included in the dump file being debugged.

The specified number is the page frame number (PFN) corresponding to the location in physical memory of the original page.

Kernel-mode memory dumps come in three sizes, and the smaller sizes do not include all the memory pages. For details, see Varieties of Kernel-Mode Dump Files.

User-mode memory dumps also come in various sizes. See User-Mode Dump Files for details.


Stack unwind information not available

When the debugger is examining the call stack, it may display the message "Stack unwind information not available. Following frames may be wrong."

This warning indicates that the debugger is not certain that the frames in the call stack listed after this message are correct.

To trace the call stack, the debugger examines the stack and analyzes the functions that have used the stack. This lets it identify the chain of return addresses that form the call stack. However, this procedure requires symbol information for each module containing the functions that used the stack.

If this symbol information is not available, the debugger is forced to make a "best guess" about which frames are return addresses. This warning information is displayed to indicate the uncertain nature of the call stack after this point.

If the stack does not appear correct to you, you may need to use more complicated techniques to determine the stack. See Stack Traces for more details.


WinDbg Graphical Interface Features

This section of the reference discusses the individual elements of the WinDbg Graphical Interface. These include:

Debugging Information Windows

The File Menu

The Edit Menu

The View Menu

The Debug Menu

The Window Menu

The Help Menu

Toolbar Buttons

Shortcut Keys


Debugging Information Windows

This section of the reference discusses the components of the various debugging information windows.


The Command Window

The Debugger Command window is the main debugging information window used in WinDbg. The word "command" appears in its title bar. This window is used for input and output for all debugger and extension commands.

This window can be opened or made active by using the View | Command command, pressing the ALT+1 shortcut key, or clicking the following toolbar button:

The Debugger Command window is used to enter debugger commands and extension commands. The output from any debugger command appears in this window (although changes to other parts of the graphical interface may result as well).

When debugging in user mode, this window corresponds to the entire CDB window. When debugging in kernel mode, this window corresponds to the entire KD window. However, certain commands will work differently in the different debuggers; see the individual command pages for details.

In WinDbg, the Debugger Command window is split into two panes. The small bottom pane is used to enter text commands. The large upper pane is used to view command output.

You can use the UP and DOWN ARROW keys to scroll through the command history. When a previous command appears, it can be edited. Pressing ENTER will cause the currently-visible command to be executed. The cursor does not need to be at the end of the line for this to work correctly.

Right-clicking in this window automatically pastes the contents of the clipboard into the text pane.

Additional Information

For more information on the use of this window, see The Debugger Command Window. For a general overview of techniques used to control debugging information windows, see Using Debugging Information Windows.


The Watch Window

The Watch window displays information about global variables, local variables, and registers. You can customize it to show just those items you wish to keep track of.

This window can be opened or made active by using the View | Watch command, pressing the ALT+2 shortcut key, or clicking the following toolbar button:

The Watch window has up to four possible columns. The Name and Value columns are always present; the Type and Offset columns are optional.

To display the Type column, toggle the Typecast button. To display the Offset column, toggle the Offsets button. You can also right-click on the Watch window and use the context menu to control the display of these columns; this context menu also allows you to hide the Typecast and Offsets buttons themselves.

To add a variable to the Watch list, click in the first empty cell in the Name column, enter the name of this variable, and hit ENTER. Separate the module name from the variable with an exclamation point (!). If you do not specify the module, the current module is assumed. You can also enter an address in the Name field; this address must begin with a decimal digit (if necessary, use the prefix 0x).

If the variable you have entered is defined in the current function's scope, its value will appear in the Value column. If it is not defined, the message "Error: Cannot get value" will appear in the Value column.

Even if a variable is not defined, it may be useful to add it to the Watch window. If the program counter enters a function in which a variable of this name is defined, its value will appear in the window at that time.

To remove a variable from the watch list, double-click on its name, press DELETE, and then press ENTER. You can also replace an old name with a new name by double-clicking on the old name, typing the new name in its place, and pressing ENTER.

Registers can be added to the Watch window as well. Register names must be prefixed with an "at" sign (@). Unlike variables, register values cannot be changed through the Watch window.

If a variable is recognized as a data structure, a box will appear next to its name. Clicking on this box expands and collapses the display of the members of this structure.

To change the value of a local variable, double-click its Value cell. Enter the new value, or edit the old value (the cut, copy, and paste keys and commands are available during this editing). The value you enter can include any C++ expression. See C++ Numbers and Operators for details. Pressing ENTER will store this new value; pressing ESC will discard it. If a you submit an invalid value, the old value will reappear after you press ENTER.

Integer values are always displayed in hexadecimal, but they are entered in the current radix (unless you specify a different radix prefix). To change the current radix, use the N (Set Number Base) command in the Debugger Command window.

Each variable is displayed in the format proper for its own data type. The Type column shows the current data type of each variable. All data structures will have their type names in this column. Other variable types initially have the words "Enter new type" in this field. If you double-click on this, you can enter a new data type; this allows you to perform typecasts. This alters the current display of this variable in the Watch window. However, it does not cause any other changes in the debugger or in the target; these changes only apply to the Watch window. If the Watch window is closed and reopened, these changes will vanish.

You can control the display of long integers with the .enable_long_status (Enable Long Integer Display) command.

If you want to display unicode strings in the Watch window, you need to use the .enable_unicode (Enable Unicode Display) command first.

The Offset column shows the offset of each member of a data structure.

Unlike the Locals window, the Watch window is not affected by changes to the register context. Only those variables that are defined in the scope of the current program counter can have their values displayed or modified.

Additional Information

For other methods of controlling variables, and a description of other memory-related commands, see Reading and Writing Memory. For more details on registers and their manipulation, see Reading and Writing Registers and Flags. For a general overview of techniques used to control debugging information windows, see Using Debugging Information Windows.


The Locals Window

The Locals window displays information about all the local variables in the current scope.

This window can be opened or made active by using the View | Locals command, pressing the ALT+3 shortcut key, or clicking the following toolbar button:

The Locals window has up to four possible columns. The Name and Value columns are always present; the Type and Offset columns are optional.

To display the Type column, toggle the Typecast button. To display the Offset column, toggle the Offsets button. You can also right-click on the Locals window and use the context menu to control the display of these columns; this context menu also allows you to hide the Typecast and Offsets buttons themselves.

The name of each local variable is displayed in the Name column. If a variable is a data structure, a box will appear next to its name. Clicking on this box expands and collapses the display of the members of this structure.

The Value column displays the current value of each variable. If you double-click on the value of a variable, you can enter a new value.

To change the value of a local variable, double-click its Value cell. Enter the new value, or edit the old value (the cut, copy, and paste keys and commands are available during this editing). The value you enter can include any C++ expression. See C++ Numbers and Operators for details. Pressing ENTER will store this new value; pressing ESC will discard it. If a you submit an invalid value, the old value will reappear after you press ENTER.

Integer values are always displayed in hexadecimal, but they are entered in the current radix (unless you specify a different radix prefix). To change the current radix, use the N (Set Number Base) command in the Debugger Command window.

Each variable is displayed in the format proper for its data type. The Type column shows the current data type of each variable. All data structures will have their type names in this column. Other variable types initially have the words "Enter new type" in this field. If you double-click on this, you can enter a new data type; this allows you to perform typecasts. This alters the current display of this variable in the Locals window. However, it does not cause any other changes in the debugger or in the target; these changes only apply to the Locals window. If the Locals window is closed and reopened, these changes will vanish.

You can control the display of long integers with the .enable_long_status (Enable Long Integer Display) command.

If you want to display unicode strings in the Locals window, you need to use the .enable_unicode (Enable Unicode Display) command first.

The Offset column shows the offset of each member of a data structure.

The local context determines which set of local variables will be displayed. When the local context changes for any reason, the Locals window is automatically updated. By default, the local context matches the current position of the program counter. For information on how this can be changed, see Local Context.

Additional Information

For other methods of controlling local variables, an overview of using variables and changing the scope, and a description of other memory-related commands, see Reading and Writing Memory. For a general overview of techniques used to control debugging information windows, see Using Debugging Information Windows.


The Registers Window

The Registers window displays the registers and flags from the current target processor.

This window can be opened or made active by using the View | Registers command, pressing the ALT+4 shortcut key, or clicking the following toolbar button:

The Registers window has two columns. The Reg column lists all the registers for the target processor. The Value column displays the current value of each register.

To change the value of a register in the list, double-click in its Value cell. Enter the new value, or edit the old value (the cut, copy, and paste keys and commands are available during this editing). Pressing ENTER will store this new value; pressing ESC will discard it. If a register cannot be changed, or if you submit an invalid value, the old value will reappear after you press ENTER.

Register values are displayed in the current radix, and new values must be entered in this radix. To change the current radix, use the N (Set Number Base) command in the Debugger Command window.

The most recently-changed register has its value displayed in red.

To change the list of registers that are displayed, click the Customize button. The Customize Register List dialog box will appear. You can now edit the list of registers to change the order in which registers are displayed. (You cannot actually delete a register from the list; if you do, it will reappear at the end.) There must be a space between register names. Press OK to save your changes, or Cancel to discard your changes.

You can also right-click on the Registers window and use the context menu to summon the Customize Register List dialog box, or hide the toolbar containing the Customize button.

In user mode, the registers displayed are those associated with the current thread. See Controlling Processes and Threads for details.

In kernel mode, the registers displayed are those associated with the current register context. The register context can be set to match a specific thread, context record, or trap frame. Only the most important registers for the specified register context are actually displayed, and their values cannot be changed. See Register Context for details.

Additional Information

For more details on registers and their manipulation, see Reading and Writing Registers and Flags. For more information on the register context and other context settings, see Changing Contexts. For a general overview of techniques used to control debugging information windows, see Using Debugging Information Windows.


The Memory Window

The Memory window displays a formatted range from memory.

Any number of instances of the Memory window can be open at one time. (This behavior differs from that of the other debugging information windows.) A new Memory window can be opened by using the View | Memory command, pressing the ALT+5 shortcut key, or clicking the following toolbar button:

Dialog Box

When a Memory window is opened, the Memory Options dialog box appears.

In kernel mode, there are six memory types available. These are Virtual Memory, Physical Memory, Bus Data, Control Data, IO (I/O port information), and MSR (model-specific register information). Select the tab corresponding to the information you wish to access.

In user mode, only the Virtual Memory tab is available.

Once you have selected the proper tab, enter the appropriate information by using the text boxes and the drop-down boxes. The Offset text box specifies the address of the beginning of the memory range you wish to view.

The Display format drop-down box controls the style of the display. Possible data types include: short words, double words, and quad-words; short, long, and quad integers and unsigned integers; 10, 16, 32, and 64-byte real numbers, ASCII characters, Unicode characters, and hexadecimal bytes. (The display of hexadecimal bytes includes ASCII characters as well.)

The display itself is not affected by the current default radix. However, the address which you enter is interpreted in the current radix. If the current radix is not 16, you should prefix a hexadecimal address with 0x. To change the default radix, use the N (Set Number Base) command in the Debugger Command window.

When you click OK in the Memory Options dialog box, the Memory window itself appears.

The Memory Window

The Memory window dispalys data in several columns. The left column gives the address of the beginning of each line. The remaining columns display the requested information, from left to right. If you selected "Bytes" as the display format, the ASCII characters that correspond to these bytes is displayed at the right side of the window.

To alter the contents of memory, simply click the mouse in the window and type new information. Only hexadecimal information can be edited; ASCII and Unicode characters cannot be edited directly. Changes take effect the moment you type new information.

To see other sections of memory, use the Previous and Next buttons, or press the PAGE UP or PAGE DOWN keys. This displays the immediately preceding or following sections of memory. If an invalid page is requested, an error message is displayed.

The RIGHT, LEFT, UP and DOWN arrow keys will allow you to navigate within the window. If you use these keys to move off the page, a new page will be shown. Before using these keys, it is best to resize the Memory window so it does not have scroll bars; this lets you distinguish between the actual page edge and the window cutoff.

You can change the address and display format by using the address text box and the Display format drop-down box at the top of the Memory window. Note that the Memory window refreshes its display as you enter an address, so you may get error messages before you have completed typing this address.

You can cause the Memory Options dialog box to reappear by selecting the Edit | Properties menu command or by clicking the following toolbar button:

This allows you to change any of the options you wish.

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory. For a general overview of techniques used to control debugging information windows, see Using Debugging Information Windows.


The Calls Window

The Calls window displays the current call stack information.

This window can be opened or made active by using the View | Call Stack command, pressing the ALT+6 shortcut key, or clicking the following toolbar button:

The Calls window displays the call stack information in several columns, most of which can be visible or hidden.

The buttons at the top of this window control the display format. You can toggle these buttons with the mouse, or right-click on the Calls window and use the context menu to control these buttons. This context menu also allows you to hide the toolbar buttons themselves.

If no buttons are toggled, only the name or offset of each function is displayed.

Toggling the Args button will cause the first three parameters passed to the function to be displayed. On an x86 processor, this includes the first three parameters passed to the function (Args to Child). On an IA-64 processor, this includes the parameters passed to the function (Arguments to Callee), as long as the Nonvolatile regs button is also toggled.

Toggling the Func info button displays FPO data and other internal information about the function. This is only available on an x86 processor.

Toggling the Source button will cause source module names and line numbers to be displayed after the function names (if the debugger has this information).

Toggling the Addrs button will cause addresses to be displayed. On an x86 processor, this includes the base pointer for the stack frame (ChildEBP) and the return address (RetAddr). On an IA-64 processor, this includes a pointer to the function being called (Callee-BSP) and the return address (Return-RA), unless both the Args and Nonvolatile regs buttons are toggled as well.

Toggling the Headings button will cause column headings to appear at the top of each column.

Toggling the Nonvolatile regs button will cause the nonvolatile portion of the register context to be displayed. This is only available on an IA-64 processor.

Toggling the Frame nums button will cause frame numbers to be displayed. Frames are always numbered consecutively, beginning with zero.

Toggling the Arg types button will cause detailed information to be displayed about the arguments expected and received by the functions in the stack.

Pressing the More or Less buttons will change the length of the stack trace. Each time one of these buttons is pressed, the stack display will increase or decrease by ten frames.

If you double-click on a line of the call stack, or select that line and then press ENTER, WinDbg will move you to the call location in the Source or Disassembly window. This also causes the local context to change to the selected stack frame. If you wish to run from this point or to run to this point, see Controlling the Target for methods of doing this.

In user mode, the stack trace is based on the stack of the current thread. See Controlling Processes and Threads for details.

In kernel mode, the stack trace is based on the current register context. The register context can be set to match a specific thread, context record, or trap frame. See Register Context for details.

Additional Information

For more information on stack traces, and for other ways to display stack traces, see Viewing the Call Stack. For more information on the register context and the local context, see Changing Contexts. For a general overview of techniques used to control debugging information windows, see Using Debugging Information Windows.


The Disassembly Window

The Disassembly window displays executable code in assembly language.

This window can be opened or made active by using the View | Disassembly command, pressing the ALT+7 shortcut key, or clicking the following toolbar button:

The debugger takes a section of memory, interprets it as binary machine instructions, and "disassembles" it to produce an assembly-code version of these instructions. The resulting code is displayed in the Disassembly window.

To disassemble a different section of memory, enter the desired address in the Offset text box. Pressing ENTER after typing this address is optional. Note that the Disassembly window will display code before you have completed the address; disregard this code.

To see other sections of memory, use the Previous and Next buttons, or press the PAGE UP or PAGE DOWN keys. This displays disassembled code from the immediately preceding or following sections of memory. The RIGHT, LEFT, UP and DOWN arrow keys will allow you to navigate within the window. If you use these keys to move off the page, a new page will be shown.

Error messages may result if you request disassembly of a section of memory which does not contain machine instructions.

The line representing the current program counter is highlighted in green. Lines at which breakpoints are set are highlighted as well: an enabled breakpoint in red, a disabled breakpoint in yellow, and a breakpoint that coincides with the current program counter in purple.

Additional Information

For a description of assembly debugging and related commands, and a full explanation of the assembly display, see Debugging in Assembly Mode. For a general overview of techniques used to control debugging information windows, see Using Debugging Information Windows.


Source Windows

Source windows display source files which have been loaded into the debugger. Each source file resides in its own Source window. The title of each Source window is the path and file name of the source file.

Source windows are not opened by any single command. Rather, these windows are opened by the debugger each time it loads a new source file. The currently-open Source windows can be restored or activated by selecting them from the list of windows at the bottom of the Window menu.

Each Source window displays the text of one source file. This file itself cannot be edited in the debugger. See Changing Text Properties for how to change the font and tab settings.

The line representing the current program counter is highlighted in green. Lines at which breakpoints are set are highlighted as well. Enabled breakpoints are red and disabled breakpoints are yellow. If a breakpoint coincides with the current program counter, it is highlighted in purple.

Additional Information

For a description of source debugging and related commands, see Debugging in Source Mode. For a general overview of techniques used to control debugging information windows, see Using Debugging Information Windows.


The Scratch Pad

The Scratch Pad is a visible clipboard that can be used to store blocks of text.

This window can be opened or made active by using the View | Scratch Pad command, pressing the ALT+8 shortcut key, or clicking the following toolbar button:

To type in the Scratch Pad, click the mouse at the desired location and type. Simple text and formatted text can be pasted to or copied from the Scratch Pad.

The contents of the Scratch Pad have no effect on the operation of the debugger; this feature exists solely as an aid in text editing.

If you close the Scratch Pad window, all text in it will be lost.


The File Menu

This section of the reference discusses the items on the File menu of WinDbg.


File | Open Source File

Selecting Open Source File from the File menu allows you to load a specific source file.

This is equivalent to pressing the CTRL+O shortcut key, or clicking the following toolbar button:

Dialog Box

When the Open Source File dialog box appears, use the following procedure to open a file:

To open a file

  1. If the file is in a different directory, select the directory from the Look in list. The current directory is the default.
  2. Select a file type in the Files of Type list. Only files with the chosen extension(s) are displayed in the Open Source File dialog box. You can also use wildcard patterns in the File Name text box to display only files with a certain extension. The new wildcard pattern is retained in a session until you change it. You can use any combination of wildcard patterns, separated by semicolons. For example, entering *.INC; *.H; *.CPP displays all files with these extensions. The maximum number of characters in a line is 251.
  3. Double-click a filename, or click a filename and click Open.

The names of the four most recently opened files are displayed when you point to Recent Files on the File menu. To open one of these files, click its name from the menu.

Click Cancel to discard changes and close the dialog box.

Additional Information

For more details on source files and source paths, and for other ways to load source files, see Setting Paths and Loading Files.


File | Close Current Window

Selecting Close Current Window from the File menu closes the active debugging information window.

This is equivalent to pressing the CTRL+F4 shortcut key.

A debugging information window can also be closed by clicking the Close button in its upper-right corner.


File | Open Executable

Selecting Open Executable from the File menu allows you to start a new user-mode process and debug it.

This is equivalent to pressing the CTRL+E shortcut key. It can only be used when WinDbg is in dormant mode.

Dialog Box

When the Open Executable dialog box appears, enter the full path and name of the executable in the File name text box. Alternatively, you can use the dialog box to locate and select the proper path and file name.

You need to specify the exact path to this program. Whereas the Microsoft® Windows® Start | Run box and the MS-DOS® Command Prompt search the command path for an executable name, the Open Executable dialog box does not.

If you wish to use any command-line arguments with this application, type them in the Arguments text box.

If you wish to change the starting directory from the default, enter the directory path into the Start directory text box.

If you wish WinDbg to attach to any child processes (additional processes launched by the original target process), select Debug child processes also.

When the proper selections have been made, click Open.

If WinDbg is connected to a process server, the Open Executable command cannot be used.

Additional Information

For more details, and for other methods of starting new processes for debugging, see Spawning a New Process (User Mode).


File | Attach to a Process

Selecting Attach to a Process from the File menu allows you to debug a user-mode application that is currently running.

This is equivalent to pressing the F6 shortcut key. It can only be used when WinDbg is in dormant mode.

Dialog Box

When the Attach to Process dialog box appears, select the line containing the proper process ID and name. Alternatively, you can enter the process ID in the Process ID text box.

If you want to attach noninvasively, select the Noninvasive check box.

Then press OK to attach to the process.

If WinDbg is connected to a process server, the dialog box will show processes running on the remote computer. See Activating the Smart Client for details.

Additional Information

For more details, and for other methods of attaching to a process, see Attaching to a Running Process (User Mode) and Noninvasive Debugging (User Mode).


File | Open Crash Dump

Selecting Open Crash Dump from the File menu allows you to open a user-mode or kernel-mode crash dump file and begin to analyze it.

This is equivalent to pressing the CTRL+D shortcut key. It can only be used when WinDbg is in dormant mode.

Dialog Box

When the Open Crash Dump dialog box appears, enter the full path and name of the crash dump file in the File name text box. Alternatively, you can use the dialog box to select the proper path and file name. (Dump files generally end with the extension .dmp or .mdmp.)

When the proper file has been chosen, click Open.

Additional Information

For more details, see Analyzing a User-Mode Dump File with WinDbg or Analyzing a Kernel-Mode Dump File with WinDbg.


File | Connect to Remote Session

Selecting Connect to Remote Session from the File menu allows you to turn WinDbg into a Debugging Client and connect to an active Debugging Server.

This is equivalent to pressing the CTRL+R shortcut key. It can only be used when WinDbg is in dormant mode.

Dialog Box

You can use the Connect to Remote Debugger Session dialog box to enter the remote connection parameters or to browse a list of Debugging Servers. This dialog box cannot be used to connect to a process server.

To specify the remote connection parameters by hand, enter one of the following two strings in the Connection string text box:

tcp:server=Server,port=Socket[,password=Password]
npipe:server=Server,pipe=PipeName[,password=Password]
1394:server=Server,channel=1394Channel[,password=Password]
com:server=Server,port=COMPort,baud=BaudRate,channel=COMChannel[,password=Password]
ssl:server=Server,SSL-Parameters
spipe:server=Server,SPIPE-Parameters

The various parameters have the following possible values:

Server
This is the network name of the machine on which the Debugging Server was created. It should not be preceded with backslashes.
Socket
If TCP protocol is used, Socket is the same socket port number which was used when the server was created.
PipeName
If NPIPE protocol is used, PipeName is the name which was given to the pipe when the server was created.
1394Channel
(Windows XP and Windows .NET Server 2003 only) If 1394 protocol is used, Channel specifies the 1394 channel that was chosen when the server was created.
COMPort
If COM protocol is used, COMPort specifies the COM port to be used. The prefix "COM" is optional — for example, both "com2" and "2" are acceptable.
BaudRate
If COM protocol is used, BaudRate should match the baud rate chosen when the server was created.
COMChannel
If COM protocol is used, COMChannel should match the channel number chosen when the server was created.
SSL-Parameters
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) If SSL protocol is used, SSL-Parameters should match those used when the server was created.
SPIPE-Parameters
(Windows 2000, Windows XP, and Windows .NET Server 2003 only) If SPIPE protocol is used, SPIPE-Parameters should match those used when the server was created.
Password
If a password was used when the server was created, Password must be supplied in order to create the Debugging Client. It must match the original password. Passwords are case-sensitive. If the wrong password is supplied, the error message will specify "Error 0x80004005".

An alternative method is to press the Browse button and use the Browse Remote Servers dialog box.

When the Browse Remote Servers dialog box appears, type the name of the machine which the Debugging Server is running on in the Machine text box. (The two initial backslashes are optional: "MyBox" and "\\MyBox" are both allowed.) Then press the Refresh button.

A list of all Debugging Servers running on that computer will be displayed in the Servers list. Click on any of the listed servers, and then press ENTER or select OK. (You can also just double-click on one of the listed servers.) The proper connection string for the Debugging Server you selected will now appear in the Connection string text box.

If the server is password-protected, the connection string will include "Password=*". The asterisk must be replaced with the actual password.

Press OK to open this connection.

Note that this list can also include servers which no longer exist but which were not shut down properly. Connecting to one of these non-existent servers generates an error message.

Additional Information

For more details, and for other methods of joining a remote debugging session, see Activating the Debugging Client.


File | Kernel Debug

Selecting Kernel Debug from the File menu allows you to begin debugging a target computer in kernel mode.

This is equivalent to pressing the CTRL+K shortcut key. It can only be used when WinDbg is in dormant mode.

Dialog Box

The Kernel Debugging dialog box has three tabs: COM, 1394, and Local. Each of them specifies a different connection method:

  • The COM tab indicates that the connection will use a COM port. In the Baud Rate text box, enter the baud rate. In the Port text box, enter the name of the COM port. For details, see Choosing Kernel Debugging Settings.
  • The 1394 tab indicates that the connection will use 1394. In the Channel text box, enter the 1394 channel number. 1394 debugging is only supported on Windows XP and Windows .NET Server 2003. For details, see Choosing Kernel Debugging Settings.
  • The Local tab indicates that WinDbg will perform local kernel debugging. Local kernel debugging is only supported on Windows XP and Windows .NET Server 2003.

Additional Information

For more details, and for other methods of beginning a kernel debugging session, see Attaching to a Target Computer (Kernel Mode).


File | Symbol File Path

Selecting Symbol File Path from the File menu allows you to display, set, or append to the symbol path.

This is equivalent to pressing the CTRL+S shortcut key.

Dialog Box

When the Symbol Search Path dialog box appears, it will display the current symbol path. If the box is blank, there is no current symbol path.

You can enter a new path, or edit the old path. If more than one directory is to be searched, separate them with semicolons.

Click OK to save changes, or Cancel to discard changes.

Additional Information

For details, and for other ways to change this path, see Setting Paths and Loading Files.


File | Source File Path

Selecting Source File Path from the File menu allows you to display, set, or append to the source path.

This is equivalent to pressing the CTRL+P shortcut key.

Dialog Box

When the Source Search Path dialog box appears, it will display the current source path. If the box is blank, there is no current source path.

You can enter a new path, or edit the old path. If more than one directory is to be searched, separate them with semicolons.

If you are performing remote debugging, the Local box will be available. Select this box to edit your Debugging Client's local source path; clear it to edit the Debugging Server's source path.

Click OK to save changes, or Cancel to discard changes.

Additional Information

For details, and for other ways to change this path, see Setting Paths and Loading Files.


File | Image File Path

Selecting Image File Path from the File menu allows you to display, set, or append to the executable image path.

This is equivalent to pressing the CTRL+I shortcut key.

Dialog Box

When the Executable Image Search Path dialog box appears, it will display the current executable image path. If the box is blank, there is no current executable image path.

You can enter a new path, or edit the old path. If more than one directory is to be searched, separate them with semicolons.

Click OK to save changes, or Cancel to discard changes.

Additional Information

For details, and for other ways to change this path, see Setting Paths and Loading Files.


File | Open Workspace

Selecting Open Workspace from the File menu opens a saved workspace.

This is equivalent to pressing the CTRL+W shortcut key.

Dialog Box

When the Open Workspace dialog box appears, a list of all existing workspace names will appear in the Workspaces list above. (The name which appears in the Workspace text box below is always the first name in the list, not the name of the current workspace.)

Enter the desired name of the workspace into the Workspace text box, click on the desired workspace name in the Workspaces list, or just leave the name which appears in the text box. Then press OK to open the selected workspace, or Cancel to return to the previous status.

Additional Information

For details on the different levels of workspaces and how to use them, see Using Workspaces.


File | Save Workspace

Selecting Save Workspace from the File menu saves the current workspace under its current workspace name.

Additional Information

For details on the different levels of workspaces and how to use them, see Using Workspaces.


File | Save Workspace As

Selecting Save Workspace As from the File menu saves the current workspace under a new workspace name.

Dialog Box

When the Save Workspace As dialog box appears, a list of all existing workspace names will appear in the Workspaces list above. The name of the current workspace will appear in the Workspace text box below.

Enter the desired name of the workspace into the Workspace text box, click on the desired workspace name in the Workspaces list, or just leave the current name as it exists.

Press OK to save the workspace, or Cancel to not save the workspace.

Additional Information

For details on the different levels of workspaces and how to use them, see Using Workspaces.


File | Clear Workspace

Selecting Clear Workspace from the File menu allows you to erase items in the current workspace.

Dialog Box

When the Clear Workspace dialog box appears, use the Clear and Clear All buttons to remove items from the workspace. If you make an error, use the Save and Save All buttons to return items to the workspace.

Press OK to make these changes or Cancel to discard these changes.

Additional Information

For details on the different levels of workspaces and how to use them, see Using Workspaces.


File | Delete Workspaces

Selecting Delete Workspaces from the File menu allows you to delete one or more existing workspaces.

Dialog Box

When the Delete Workspaces dialog box appears, select the desired workspace and press the Delete button.

Press Close to dismiss this dialog box.

Additional Information

For details on the different levels of workspaces and how to use them, see Using Workspaces.


File | Open Workspace in File

Selecting Open Workspace in File from the File menu allows you to load a workspace that was previously saved to a file.

Dialog Box

When the Open Workspace in File dialog box appears, enter the name of the file you wish to load, or navigate to the desired file and select it. Workspace files should use the .wew extension.

Press OK to load the workspace or Cancel to exit.

Additional Information

For details on the different levels of workspaces and how to use them, see Using Workspaces.


File | Save Workspace to File

Selecting Save Workspace to File from the File menu allows you to save the current workspace to a file.

Dialog Box

When the Save Workspace to File dialog box appears, enter the name of the file you wish to save the workspace as. You can navigate to the desired directory, or select a specific file you wish to overwrite. The default file extension is .wew.

Press OK to save the file or Cancel to exit.

Additional Information

For details on the different levels of workspaces and how to use them, see Using Workspaces.


File | Map Network Drive

Selecting Map Network Drive from the File menu allows you to add network connections and assign drive letters to these connections.

Dialog Box

When the Map Network Drive dialog box appears, use the Drive and Folder pull-down menus to choose a server and share and assign a drive letter to it.

This dialog box works exactly like the corresponding feature of Windows Explorer.

The File | Map Network Drive command only affects the network connections of the computer on which WinDbg is running. If WinDbg is being used as a client in a remote debugging session, and you wish to change the network connections of the server, you must use a .shell net use command.

Additional Information

For other ways of accessing the Windows or MS-DOS shell, see Using Shell Commands.


File | Disconnect Network Drive

Selecting Disconnect Network Drive from the File menu allows you to remove network connections.

Dialog Box

When the Disconnect Network Drive dialog box appears, select the connection you wish to remove and press OK.

This dialog box works exactly like the corresponding feature of Windows Explorer.

The File | Disconnect Network Drive command only affects the network connections of the computer on which WinDbg is running. If WinDbg is being used as a client in a remote debugging session, and you wish to change the network connections of the server, you must use a .shell net use command.

Additional Information

For other ways of accessing the Windows or MS-DOS shell, see Using Shell Commands.


File | Recent Files

Pointing the mouse at Recent Files on the File menu will display a list of the four most recently opened source files.

To open one of these files, click its name from the menu.

Additional Information

For more details on source files and source paths, and for other ways to load source files, see Setting Paths and Loading Files.


File | Exit

Selecting Exit from the File menu ends the debugging session and exits the entire WinDbg program.

This is equivalent to pressing the ALT+F4 shortcut key.

Additional Information

For other methods of exiting WinDbg or ending the debugging session, see Ending the Debugging Session.


The Edit Menu

This section of the reference discusses the items on the Edit menu of WinDbg.


Edit | Cut

Selecting Cut from the Edit menu deletes any text you have selected and moves it to the clipboard.

This is equivalent to pressing the CTRL+X or SHIFT+DEL shortcut keys, or clicking the following toolbar button:

Additional Information

For details on selecting, copying, cutting, and pasting text, and an explanation of how these operations vary from window to window, see Cutting and Pasting Text.


Edit | Copy

Selecting Copy from the Edit menu copies any text you have selected to the clipboard.

This is equivalent to pressing the CTRL+C shortcut key, or clicking the following toolbar button:

Additional Information

For details on selecting, copying, cutting, and pasting text, and an explanation of how these operations vary from window to window, see Cutting and Pasting Text.


Edit | Paste

Selecting Paste from the Edit menu pastes text from the clipboard to the current cursor location.

This is equivalent to pressing the CTRL+V shortcut key, or clicking the following toolbar button:

Additional Information

For details on selecting, copying, cutting, and pasting text, and an explanation of how these operations vary from window to window, see Cutting and Pasting Text.


Edit | Select All

Selecting Select All from the Edit menu causes all the text in the active Debugger Command window, Disassembly window, Source window, or dialog box to be selected.

This is equivalent to pressing the CTRL+A shortcut key.

Additional Information

For details on selecting, copying, cutting, and pasting text, and an explanation of how these operations vary from window to window, see Cutting and Pasting Text.


Edit | Write Window Text to File

Selecting Write Window Text to File from the Edit menu causes all the text in the active debugging information window to be saved to a file.

This command is only available if the active window is the Debugger Command window, the Calls window, or the Scratch Pad.

Dialog Box

When the Write Window Text to File dialog box appears, enter the name of the file you wish to save the window text as. You can navigate to the desired directory, or select a specific file you wish to overwrite. The default file extension is .txt.

Press OK to save the file or Cancel to exit.

Additional Information

For details on selecting, copying, cutting, and pasting text, and an explanation of how these operations vary from window to window, see Cutting and Pasting Text.


Edit | Add to Command Output

Selecting Add to Command Output from the Edit menu inserts a comment line into the Debugger Command window.

Type a comment into the Text text box and then press OK.

This text will appear in the Debugger Command window. It will also appear in any open log file. However, it will not appear in any debuggers connected to your session remotely.

Additional Information

For other features of the Debugger Command window, see Using Debugger Commands.


Edit | Clear Command Output

Selecting Clear Command Output from the Edit menu clears all the text from the Debugger Command window, clearing the command history entirely.

Additional Information

For other features of the Debugger Command window, see Using Debugger Commands.


Edit | Find

Selecting Find from the Edit menu will allow you to find text in the active debugging information window. This must be either the Debugger Command window or a Source window.

This is equivalent to pressing the CTRL+F shortcut key.

Dialog Box

When the Find dialog box appears, enter the text you wish to find in the Find what box. Select either Up or Down to determine the direction of your search. The search will begin wherever the cursor is in the window You can place the cursor at any location by using the mouse.

Select Match whole word only if you wish to search for a single whole word. (Choosing this in a search for multiple words always results in a failed search.) Choose Match case to do a case-sensitive search.

This action merely changes the WinDbg display. It does not affect the execution of the target or any other debugger operations.

Additional Information

For other ways of finding text in debugging information windows, see Moving Through a Window.


Edit | Go to Address

Selecting Go to Address from the Edit menu will allow you to jump to an address in the target's virtual address space.

This is equivalent to pressing the CTRL+G shortcut key.

Dialog Box

When the View Code Offset dialog box appears, enter the desired address. This address can be an expression such as a function, symbol, integer memory address, or any valid address expression. If the address is ambiguous, a list box with all ambiguous items is displayed.

After you click OK, the debugger moves the caret to the beginning of the function or address in the Disassembly window or a Source window.

This action can be used regardless of which window is currently active. If the debugger is in disassembly mode, this address will be found in the Disassembly window. If the debugger is in source mode, this will be found in a Source window if possible; if this is not possible, it will be found in the Disassembly window. If the appropriate window is not open, it will be opened.

This action merely changes the WinDbg display. It does not affect the execution of the target or any other debugger operations.

Additional Information

For other ways of finding text in debugging information windows, see Moving Through a Window.


Edit | Go to Line

Selecting Go to Line from the Edit menu allows you to search for a specific line in the currently-active Source window. If the active window is not a Source window, it has no effect.

This is equivalent to pressing the CTRL+L shortcut key.

Dialog Box

When the Go to Line dialog box appears, enter the desired line number and click OK. The debugger will move the caret to that line. If the line number is greater than the last line in the file, the cursor will go to the end of the file.

This action merely changes the WinDbg display. It does not affect the execution of the target or any other debugger operations.

Additional Information

For other ways of finding text in debugging information windows, see Moving Through a Window.


Edit | Go to Current Instruction

Selecting Go to Current Instruction from the Edit menu will activate the debugging information window containing the current instruction and highlight this instruction.

This is equivalent to pressing the ALT+* shortcut key (using the * key on the numerical keypad).

If the current instruction corresponds to a known source file, the Source window containing this source file will be activated. If no such window exists, one will be opened. The current line will then be highlighted.

If the current instruction is not in a known source file, and the Disassembly window is open, it will be activated, and the current line will be highlighted. However, if the Disassembly window has been closed, this command will not open it.

This action merely changes the WinDbg display. It does not affect the execution of the target or any other debugger operations.


Edit | Breakpoints

Selecting Breakpoints from the Edit menu causes the Breakpoints dialog box to appear, which allows you to display or control breakpoints.

This is equivalent to pressing the ALT+F9 shortcut key.

Unless a Source window or the Disassembly window is active, this is also equivalent to pressing the F9 shortcut key, or clicking the following toolbar button:

However, if a Source window or the Disassembly window is active, this button or the F9 key will set a breakpoint on the current line. (If there is already a breakpoint set at the current line, this will remove the breakpoint.)

If a single logical source line spans multiple physical lines, the breakpoint will be set on the last physical line of the statement or call. You should insert the caret on or before the statement to set a breakpoint for the entire logical source line. If the debugger cannot set a breakpoint at the current caret position, it will search in a downward direction for the next allowable position and place the breakpoint there.

Dialog Box

The Breakpoints dialog box displays all current breakpoint information. The information is presented in the following columns:

  • The breakpoint number. This is a decimal number which can be used to refer to the breakpoint in future commands.
  • The breakpoint status: either e (enabled) or d (disabled).
  • The letter u appears if the breakpoint is unresolved (that is, it doesn't match any currently-loaded module address).
  • The virtual address of the breakpoint. If source line number loading has been enabled, the BL command displays file and line number information rather than address offsets. If the breakpoint is unresolved, the address is omitted here and appears at the end of the listing instead (see further in this section).
  • (Data breakpoints only) Type and size information are displayed for data break points. Possible types are e (execute), r (read/write), w (write), or i (input/output). These types are followed with the size of the block, in bytes.
  • The number of passes remaining until the breakpoint activates, followed by the initial number of passes in parentheses. Note that the number of times the program counter will pass through this point without breaking is 1 less than the value of this number; hence this number is never lower than 1. Note also that this only counts times the program executes past this point; stepping over this point does not count. Once the full count has been reached, it can only be reset by clearing and resetting the breakpoint.
  • The associated process and thread are displayed. If thread is given as ***, this indicates that this is not a thread-specific breakpoint.
  • The module and function, with offset, corresponding to the breakpoint address. If the breakpoint is unresolved, the breakpoint address appears here instead, in parentheses. If the breakpoint is set on a valid address but symbol information is missing, this column will be blank.
  • The command string which will be automatically executed when this breakpoint is hit. This command string is displayed in quotation marks. If the breakpoint is hit, the commands in this command string are executed until program execution resumes. Any command which resumes program execution (such as G or T) will terminate the execution of the command list.

The Remove All button will permanently remove all breakpoints.

If you click on any breakpoint, the Remove, Disable, and Enable buttons become active. The Remove button will permanently remove this breakpoint. The Disable button will temporarily deactivate this breakpoint. The Enable button will re-enable a disabled breakpoint.

You can also enter certain commands in the Command text box. There are two possible ways to enter a command in this box:

  • If you enter a BP (Set Breakpoint), BU (Set Unresolved Breakpoint), BA (Break on Access), BC (Breakpoint Clear), BD (Breakpoint Disable), or BE (Breakpoint Enable) command, it will work just as if you were entering it in the Debugger Command window. However, the command itself must be in lowercase. The command also cannot begin with a thread specifier. If you wish to use a thread specifier, place it in the Thread text box, without the initial tilde (~).
  • If you enter any other text, it will be treated as the argument string for a BU (Set Unresolved Breakpoint) command. In other words, the debugger prefixes your entry with "bu" plus a space, and then executes it as a command.

Additional Information

For more details on the use of breakpoints, other breakpoint commands and methods of controlling breakpoints, information on setting breakpoints in user space from a kernel debugger, and an explanation of conditional breakpoints, see Using Breakpoints.


Edit | Open/Close Log File

Selecting Open/Close Log File from the Edit menu allows you to write to a new log file, append to an existing log file, or close an open log file.

Dialog Box

When the Open/Close Log File dialog box appears, it will display the current log file if one is already open.

If the box is blank, you can enter a log file name. If this file already exists, it will be overwritten, unless you select Append. If you specify a file name but no path, it will be placed in the default directory which WinDbg was launched from.

If the box already displays a file name, you can click Close Open Log File to close the file. If you clear the box and enter a new log file name, the old one will be closed.

Click OK to save changes, or Cancel to discard changes.

If you click OK when no log file name appears in the box, it will have no effect: it will neither close a log file nor open a log file.

However, if a log file is already active and you press OK without clearing its name or checking Append, the log file will be erased and a new file with the same name will be used.

Additional Information

For details, and for other ways to write to log files, see Keeping a Log File.


Edit | Properties

Selecting Properties from the Edit menu will allow you to configure the properties of the active debugging information window.

This is equivalent to clicking the following toolbar button:

If the active window has no properties which can be set in this manner, the button and the menu option will appear dimmed.


The View Menu

This section of the reference discusses the items on the View menu of WinDbg.


View | Command

Selecting Command from the View menu opens the Debugger Command window. If this window is already open, it becomes active; if minimized, it is restored.

This is equivalent to pressing the ALT+1 shortcut key, or clicking the following toolbar button:

For a description of this window and its uses, see The Command Window.


View | Watch

Selecting Watch from the View menu opens the Watch window. If this window is already open, it becomes active; if minimized, it is restored.

This is equivalent to pressing the ALT+2 shortcut key, or clicking the following toolbar button:

For a description of this window and its uses, see The Watch Window.


View | Locals

Selecting Locals from the View menu opens the Locals window. If this window is already open, it becomes active; if minimized, it is restored.

This is equivalent to pressing the ALT+3 shortcut key, or clicking the following toolbar button:

For a description of this window and its uses, see The Locals Window.


View | Registers

Selecting Registers from the View menu opens the Registers window. If this window is already open, it becomes active; if minimized, it is restored.

This is equivalent to pressing the ALT+4 shortcut key, or clicking the following toolbar button:

For a description of this window and its uses, see The Registers Window.


View | Memory

Selecting Memory from the View menu opens a new Memory window. Any number of instances of the Memory window can be open at one time. (This behavior differs from that of the other debugging information windows.)

The Memory | View command is equivalent to pressing the ALT+5 shortcut key, or clicking the following toolbar button:

For a description of this window and its uses, see The Memory Window.


View | Call Stack

Selecting Call Stack from the View menu opens the Calls window. If this window is already open, it becomes active; if minimized, it is restored.

This is equivalent to pressing the ALT+6 shortcut key, or clicking the following toolbar button:

For a description of this window and its uses, see The Calls Window.


View | Disassembly

Selecting Disassembly from the View menu opens the Disassembly window. If this window is already open, it becomes active; if minimized, it is restored.

This is equivalent to pressing the ALT+7 shortcut key, or clicking the following toolbar button:

For a description of this window and its uses, see The Disassembly Window.


View | Scratch Pad

Selecting Scratch Pad from the View menu opens the Scratch Pad. If this window is already open, it becomes active; if minimized, it is restored.

This is equivalent to pressing the ALT+8 shortcut key, or clicking the following toolbar button:

For a description of this window and its uses, see The Scratch Pad.


View | Processes and Threads

Selecting Processes and Threads from the View menu displays a windows containing system, process, and thread information, and allows you to change the currently-active system, process, or thread.

This is equivalent to pressing the ALT+9 shortcut key.

Window

The Processes and Threads window displays a list of all processes currently being debugged. Under each process, all of its threads appear. If the debugger has attached to multiple systems, the systems are shown at the top level of the tree, with the processes subordinate to them, and the threads subordinate to the processes.

You can expand or collapse each part of the tree by clicking the + (plus) or - (minus) buttons.

Each system listing includes the server name and the protocol details. The system that the debugger is running on is identified as <Local>.

Each process listing includes the internal decimal process ordinal used by the debugger, the hexadecimal process ID, and the name of the application associated with the process.

Each thread listing includes the internal decimal thread ordinal used by the debugger and the hexadecimal thread ID.

The current or active system, process, and thread appear in bold type.

To make a new system, process or thread active, double-click on it. Click the X button in the upper right corner of this window to close it, or select File | Close Current Window.

Additional Information

For other methods of displaying or controlling systems, see Debugging Multiple Systems. For other methods of displaying or controlling processes and threads, see Controlling Processes and Threads.


View | Verbose Output

Selecting Verbose Output from the View menu toggles verbose mode on and off.

This is equivalent to pressing the CTRL+ALT+V shortcut key. (It is also equivalent to the CTRL+V control key in KD.)

When verbose mode is on, some display commands (such as register dumping) produce more detailed output. Every MODULE LOAD operation which is sent to the debugger will be displayed. And every time a driver or DLL is loaded by the operating system, the debugger will be notified.


View | Show Version

Selecting Show Version from the View menu displays version information for the debugger and all loaded extension DLLs.

This is equivalent to pressing the CTRL+ALT+W shortcut key. (It is also equivalent to the CTRL+W control key in KD.)

This has the same effect as the version (Show Debugger Version) command, except that the latter command displays the Windows® operating system version as well.


View | Toolbar

Checking or unchecking Toolbar on the View menu causes the toolbar to become appear or disappear.

For an overview of the toolbar use, see Using the Toolbar and Status Bar. For a description of each toolbar button, see Toolbar Buttons.


View | Status Bar

Checking or unchecking Status Bar on the View menu causes the toolbar to become visible or invisible.

For an overview of the status bar use, see Using the Toolbar and Status Bar.


View | Font

Selecting Font from the View menu allows you to change the font used in the debugging information windows.

This is equivalent to clicking the following toolbar button:

Dialog Box

When the Font dialog box appears, select the font, style, and size from the appropriate list boxes. Then click OK.

Click Cancel to terminate this operation.

All the available fonts are fixed-pitch, as these are the most useful for viewing code.

Additional Information

For other ways to change the character display of debugging information windows, see Changing Text Properties.


View | Options

Selecting Options from the View menu allows you to change a number of debugger options.

This is equivalent to clicking the following toolbar button:

Dialog Box

The following options can be controlled from the Options dialog box:

Tab Width
This controls how tab characters are displayed in any Source window. In the Tab width text box, enter the number of spaces you wish to have between each tab setting. (The default setting is 8. For more information on text properties, see Changing Text Properties.)
Behavior of ENTER Key
If the Enter repeats last command box is selected, pressing the ENTER key at an empty prompt in the Debugger Command window will cause the previous command to be repeated. If this box is not selected, the ENTER key will simply generate a new prompt.
Automatic Debugger Command Window Scrolling
To turn off the automatic scrolling that occurs when new text is sent to the Debugger Command window, deselect Automatically scroll. See Using Debugger Commands for details.
Text Colors
To change the color scheme for specific types of text, select one of the items from the Colors menu. (The first ten items refer to text in the Disassembly window and thel Source windows; the remaining items refer to text in the Debugger Command window.) Press Change. Select a color, or choose a custom color. Then press OK.
Source Windows in Disassembly Mode
If you wish the appropriate Source windows to appear as you step through a program in disassembly mode, select Activate source windows in disassembly mode.

These changes take effect when you click OK. If you wish to discard these changes, click Cancel.


The Debug Menu

This section of the reference discusses the items on the Debug menu of WinDbg.


Debug | Go

Selecting Go from the Debug menu causes the target to resume (or begin) execution. This execution will continue until a breakpoint is reached, an exception or event occurs, the process ends, or the debugger breaks into the target.

This is equivalent to pressing the F5 shortcut key, or clicking the following toolbar button:

Additional Information

For details on the effects of this action, other methods of issuing this command, and other ways to control program execution, see Controlling the Target.


Debug | Go Unhandled Exception

Selecting Go Unhandled Exception from the Debug menu causes the target to resume execution, but treats the current exception as unhandled.

Additional Information

For details on the effects of this action, other methods of issuing this command, and other ways to control program execution, see Controlling the Target. For more details on exceptions and other events, see Controlling Exceptions and Events.


Debug | Go Handled Exception

Selecting Go Handled Exception from the Debug menu causes the target to resume execution, and treats the current exception as handled.

Additional Information

For details on the effects of this action, other methods of issuing this command, and other ways to control program execution, see Controlling the Target. For more details on exceptions and other events, see Controlling Exceptions and Events.


Debug | Restart

Selecting Restart from the Debug menu halts the target's execution and ends the target process and all of its threads. It then restarts the target execution at the beginning of the process.

This is equivalent to pressing the CTRL+SHIFT+F5 shortcut key, or clicking the following toolbar button:

Additional Information

For details on the effects of this action, other methods of issuing this command, and other ways to control program execution, see Controlling the Target. For other methods of exiting WinDbg or ending the debugging session, see Ending the Debugging Session.


Debug | Stop Debugging

Selecting Stop Debugging from the Debug menu halts the target's execution and ends the target process and all of its threads. This allows you to begin debugging a different target application.

This is equivalent to pressing the SHIFT+F5 shortcut key, or clicking the following toolbar button:

Additional Information

For details on the effects of this action, other methods of issuing this command, and other ways to control program execution, see Controlling the Target.


Debug | Break

Selecting Break from the Debug menu halts the target's execution and returns control to the debugger.

In user mode, this stops the process and its threads, allowing you to regain control of the debugger. In kernel mode, this breaks into the target computer.

This command can also be used while the debugger is active. In this situation, it will cut off long Debugger Command window displays.

This menu selection is equivalent to pressing the CTRL+BREAK shortcut key, or clicking the following toolbar button:

User-Mode Effects

In user mode, the Break command causes the target application to break into the debugger. The target application freezes, the debugger becomes active, and debugger commands can be entered.

If the debugger is already active, Break does not affect the target application. It can be used, however, to terminate a debugger command. For instance, if you have requested a long display and do not wish to see any more of it, Break will end the display and return you to the debugger command prompt.

When performing remote debugging with WinDbg, Break can be pressed on the host computer's keyboard. If you wish to issue a break from the target computer's keyboard, use CTRL+C on an x86 machine.

The F12 key can be used to get a command prompt when the application being debugged is busy. Set the focus on one of the target application's windows and press the F12 key on the target computer.

Kernel-Mode Effects

In kernel mode, the Break command causes the target computer to break into the debugger. This locks the target computer and wakes up the debugger.

When debugging a system that is still running, Break must be pressed on the host keyboard to get the initial command prompt.

If the debugger is already active, Break does not affect the target computer. It can be used, however, to terminate a debugger command. For instance, if you have requested a long display and do not wish to see any more of it, Break will end the display and return you to the debugger command prompt.

Break can also be used to get a command prompt when a debugger command is generating a long display or when the target computer is busy. When debugging an x86 machine, pressing CTRL+C on the target keyboard has the same effect.

SYSRQ (or ALT+SYSRQ on an enhanced keyboard) is similar. It works from the host or target keyboard on any processor. However, it only works if the prompt has been acquired by pressing CTRL+C at least once previously.

The SYSRQ key can be disabled by editing the registry. In the registry key

HKEY_LOCAL_MACHINE\System\CurrentControlSet\i8042prt\Parameters

create a value named BreakOnSysRq, and set it equal to DWORD 0x0. Then reboot. Once this is done, pressing the SYSRQ key on the target computer's keyboard will not break into the kernel debugger.

Additional Information

The corresponding key in KD and CDB is CTRL+C. For more details and information on other ways to control program execution, see Controlling the Target.


Debug | Step Into

Selecting Step Into from the Debug menu causes the target to execute a single instruction. If the instruction is a function call, the debugger will step into the function.

This is equivalent to pressing the F11 or F8 shortcut keys, or clicking the following toolbar button:

Additional Information

For details on the effects of this action, other methods of issuing this command, and other ways to control program execution, see Controlling the Target.


Debug | Step Over

Selecting Step Over from the Debug menu causes the target to execute a single instruction. If the instruction is a function call, the entire function will be executed.

This is equivalent to pressing the F10 shortcut key, or clicking the following toolbar button:

Additional Information

For details on the effects of this action, other methods of issuing this command, and other ways to control program execution, see Controlling the Target.


Debug | Step Out

Selecting Step Out from the Debug menu causes the target to resume running. It will execute the remainder of the current function, and break when the function return is completed.

This is equivalent to pressing the SHIFT+F11 shortcut key, or clicking the following toolbar button:

Additional Information

For details on the effects of this action, other methods of issuing this command, and other ways to control program execution, see Controlling the Target.


Debug | Run to Cursor

Selecting Run to Cursor from the Debug menu causes the target to resume running. If you place the cursor on an instruction in the Disassembly window or a Source window and then execute this action, WinDbg will execute all instructions from the current instruction up to the instruction you have selected.

This is equivalent to pressing the F7 or CTRL+F10 shortcut keys, or clicking the following toolbar button:

Additional Information

For details on the effects of this action, other methods of issuing this command, and other ways to control program execution, see Controlling the Target.


Debug | Source Mode

Checking Source Mode on the Debug menu causes the debugger to switch to source mode. Unchecking Source Mode causes the debugger to switch to assembly mode.

You can also change to source mode or assembly mode by clicking one of the following toolbar buttons:

The left button activates source mode; the right button activates assembly mode.

When source mode is active, the ASM indicator on the status bar appears dimmed. When assembly mode is active, the ASM indicator is visible.

Additional Information

For details on source-mode debugging, see Debugging in Source Mode. For details on assembly-mode debugging, see Debugging in Assembly Mode.


Debug | Event Filters

Selecting Event Filters from the Debug menu opens the Event Filters dialog box. This allows you to configure the break status and handling status of exceptions and events.

Dialog Box

The Event Filters dialog box lists all events that the debugger recognizes. Numbered exceptions can be added to the list, and will be displayed once added.

To change the break status for an event, click on the event and click one of the Execution option buttons (Enabled, Disabled, Output, or Ignore).

To change the handling status for an event, click on the event and click one of the Continue option buttons (Handled or Not Handled).

To add a new numbered exception, click Add. When the Exception Filter dialog box appears, enter the exception code and select the break status and the handling status from the option buttons, then click OK.

To remove a numbered exception, click on the exception and then click Remove. The standard events cannot be removed.

When you set the status for the Load module or Unload module events, you can enter a module name. Click Argument, enter the base address of a module in the Filter Argument dialog box, and then click OK. If no module is specified, the break will occur when any module is loaded/unloaded. (Note that multiple addresses are not permitted.)

If you wish to set automatic commands which will be executed if the event breaks into the debugger, click on the event and then click Commands. The Filter Command dialog box will appear. Enter any desired commands into either the Command or Second-chance Command text boxes. Separate multiple commands with semicolons and do not enclose these commands in quotation marks.

Additional Information

For more information regarding break status and handling status, descriptions of all event codes, a list of the default status for all events, and details on other methods of controlling this status, see Controlling Exceptions and Events.


Debug | Modules

Selecting Modules from the Debug menu causes the current list of loaded modules to be displayed.

Dialog Box

The Module List dialog box lists all modules currently loaded into memory.

The Name column gives the module name. The Start and End columns give the first and last address of the module's memory image. The Timestamp column gives the build date and time for the module. The Checksum column gives the checksum value.

The Symbols column displays information about the symbols used by this module. For an explanation of the values shown in this column, see Symbol Status Abbreviations.

The Symbol file column gives the path and filename of the associated symbol file. If the debugger is unaware of any symbol file, the name of the executable file is given instead.

This dialog box is for information purposes only. You cannot edit or alter any of the information in this display.

Press Close to dismiss this dialog box.


Debug | Kernel Connection | Cycle Baud Rate

Selecting Cycle Baud Rate from the Debug | Kernel Connection sub-menu toggles the baud rate used in the kernel debugging connection.

This is equivalent to pressing the CTRL+ALT+A shortcut key. (It is also equivalent to the CTRL+A control key in KD.)

This command will cycle through all available baud rates for the kernel debugging connection.

Supported baud rates are 19200, 38400, 57600, and 115200. Each time this command is used, the next baud rate will be selected. If the baud rate is already at 115200, it will be reduced to 19200.

You cannot actually use this control key to change the baud rate at which you are debugging. The baud rate of the host computer and the target computer must match, and the baud rate of the target computer cannot be changed without rebooting. Therefore you only need to toggle through the baud rates if the two computers are attempting to communicate at different rates. In this case, you must change the host computer's baud rate to match that of the target computer.

To change the target computer's baud rate, see Configuring Software on the Target Computer.


Debug | Kernel Connection | Cycle Initial Break

Selecting Cycle Initial Break from the Debug | Kernel Connection sub-menu changes the conditions on which the debugger will automatically break into the target computer.

This is equivalent to pressing the CTRL+ALT+K shortcut key. (It is also equivalent to the CTRL+K control key in KD.)

This command causes the kernel debugger to cycle through the following three states:

No break
In this state, the debugger will not break into the target computer unless you press CTRL+BREAK or Debug | Break.
Break on reboot
In this state, the debugger will break into a rebooted target computer after the kernel initializes. This is equivalent to starting WinDbg with the -b command-line option.
Break on first module load
In this state, the debugger will break into a rebooted target computer once the first kernel module is loaded. (This will cause the break to occur earlier than in the "Break on reboot" option.) This is equivalent to starting WinDbg with the -d command-line option.

When this command is used, the new break state is displayed.

Additional Information

For an overview of related commands, and an explanation of how the reboot process affects the debugger, see Crashing and Rebooting the Target Computer.


Debug | Kernel Connection | Resynchronize

Selecting Resynchronize from the Debug | Kernel Connection sub-menu causes the debugger to attempt to reestablish a solid kernel debugging connection with the target computer.

This is equivalent to pressing the CTRL+ALT+R shortcut key. (It is also equivalent to the CTRL+R control key in KD.)

Use this command if the target is not responding.

Additional Information

For other methods of re-establishing contact with the target, see Synchronizing with the Target Computer.


The Window Menu

This section of the reference discusses the items on the Window menu of WinDbg.


Window | Cascade

Selecting Cascade from the Window menu causes all open debugging information windows to be arranged in an overlapped diagonal pattern.

Minimized windows remain minimized, but their icons are moved to the bottom of the WinDbg window.

Additional Information

For other methods of arranging debugging information windows, see Arranging the Windows.


Window | Tile Horizontally

Selecting Tile Horizontally from the Window menu causes all open debugging information windows to be arranged in horizontal strips.

If there are too many open windows, there may be some vertical tiling as well. Minimized windows remain minimized, but their icons are moved to the bottom of the WinDbg window.

Additional Information

For other methods of arranging debugging information windows, see Arranging the Windows.


Window | Tile Vertically

Selecting Tile Vertically from the Window menu causes all open debugging information windows to be arranged in vertical strips.

If there are too many open windows, there may be some horizontal tiling as well. Minimized windows remain minimized, but their icons are moved to the bottom of the WinDbg window.

Additional Information

For other methods of arranging debugging information windows, see Arranging the Windows.


Window | Arrange

Selecting Arrange from the Window menu causes all open debugging information windows to be arranged in a convenient fashion. This can involve both horizontal and vertical tiling.

If Window | Arrange All Windows is not checked, Source windows and the Disassembly window will not be rearranged by this action. Minimized windows remain minimized, but their icons are moved to the bottom of the WinDbg window. This is equivalent to clicking the following toolbar button:

Additional Information

For other methods of arranging debugging information windows, see Arranging the Windows.


Window | Arrange Icons

Selecting Arrange Icons from the Window menu causes all icons representing minimized debugging information windows to be moved to the bottom left of the WinDbg window.

Midsize windows are unaffected.

Additional Information

For other methods of arranging debugging information windows, see Arranging the Windows.


Window | Close All Source Windows

Selecting Close All Source Windows from the Window menu causes all Source windows to be closed.


Window | Auto-Arrange

Checking Auto-Arrange on the Window menu causes all debugging information windows to be automatically arranged every time a window is opened, closed, minimized, or restored. Windows are also rearranged if the font is changed.

This arrangement can involve both horizontal and vertical tiling. If Window | Arrange All Windows is not checked, Source windows and the Disassembly window will not be rearranged by this action. Minimized windows remain minimized, but their icons are moved to the bottom of the WinDbg window.

If you wish to rearrange the debugging information windows manually, you should deselect Auto-Arrange. If you leave this option selected and then frequently rearrange windows anyway, a popup message will appear advising you to deselect Auto-Arrange.

Additional Information

For other methods of arranging debugging information windows, see Arranging the Windows.


Window | Arrange All Windows

Checking Arrange All Windows on the Window menu causes all debugging information windows to be affected by future Window | Arrange or Window | Auto-Arrange actions.

If Arrange All Windows is not checked, Source windows and the Disassembly window are immune from these actions.

Additional Information

For other methods of arranging debugging information windows, see Arranging the Windows.


Window | Overlay Source

Checking Overlay Source on the Window menu causes all Source windows to occupy the same position on the screen.

This does not affect Source windows that are already open.

Additional Information

For other methods of arranging debugging information windows, see Arranging the Windows.


Window | Automatically Open Disassembly

Checking Automatically Open Disassembly on the Window menu causes the Disassembly window to open every time WinDbg begins a debugging session.

If you uncheck this, you can still open the Disassembly window by selecting View | Disassembly, pressing the ALT+7 shortcut key, or clicking the following toolbar button:


List of Open Windows

At the bottom of the Window menu there is a list of all currently-opened debugging information windows. Selecting any window from this list makes it active and midsize or maximized.

For details on the use of each window, see Debugging Information Windows.


The Help Menu

This section of the reference discusses the items on the Help menu of WinDbg.


Help | Contents

Selecting Contents from the Help menu pops up this Help file and selects the Contents tab.

Additional Information

For information about how to use this Help file, see Using the Help File.


Help | Index

Selecting Index from the Help menu pops up this Help file and selects the Index tab.

Additional Information

For information about how to use this Help file, see Using the Help File.


Help | Search

Selecting Search from the Help menu pops up this Help file and selects the Search tab.

Additional Information

For information about how to use this Help file, see Using the Help File.


Help | About

Selecting About from the Help menu displays the version information for the WinDbg binaries you are using.


Toolbar Buttons

Except for the breakpoint button, each button on the toolbar is the exact equivalent of a menu item. For a full description of each button's effects, see the page for the corresponding menu item.

The buttons on the toolbar have the following effects:

Button | Description
 | Opens a source file as a read-only file. Equivalent to File | Open Source File.
 | Removes the selected text from the active window and places it on the clipboard. Equivalent to Edit | Cut.
 | Copies the selected text from the active window to the clipboard. Equivalent to Edit | Copy.
 | Pastes the text on the clipboard at the insertion point. Equivalent to Edit | Paste.
 | Starts or resumes execution. Execution will continue until a breakpoint is reached, an exception or event occurs, the process ends, or the debugger breaks into the target. Equivalent to Debug | Go.
 | Restarts execution at the beginning of the process. Equivalent to Debug | Restart.
 | Stops execution and terminates the target process permanently. Equivalent to Debug | Stop Debugging.
 | In user mode, this stops the process and its threads. In kernel mode, this breaks into the target computer. Control is returned to the debugger. This button is also useful for cutting off long Debugger Command window displays. Equivalent to Debug | Break.
 | Executes a single instruction. If the instruction is a function call, the debugger steps into the function. Equivalent to Debug | Step Into.
 | Executes a single instruction. If the instruction is a function call, the debugger executes the entire function in one step. Equivalent to Debug | Step Over.
 | Executes the remainder of the current function, and breaks when the function return is completed. Equivalent to Debug | Step Out.
 | Executes all instructions from the current instruction up to the instruction marked in the active Disassembly window or Source window. Equivalent to Debug | Run to Cursor.
 | If the active window is a Source or Disassembly window: Places a breakpoint at the current line. (If there is already a breakpoint set at the current line, this button removes the breakpoint.) Otherwise: Displays the Breakpoints dialog box like Edit | Breakpoints.
 | Displays or activates the Command window. Equivalent to View | Command.
 | Displays or activates the Watch window. Equivalent to View | Watch.
 | Displays or activates the Locals window. Equivalent to View | Locals.
 | Displays or activates the Registers window. Equivalent to View | Registers.
 | Displays or activates the Memory window. Equivalent to View | Memory.
 | Displays or activates the Calls window. Equivalent to View | Call Stack.
 | Displays or activates the Disassembly window. Equivalent to View | Disassembly.
 | Displays or activates the Scratch Pad. Equivalent to View | Scratch Pad.
 | Switches between source-mode and assembly-mode debugging. Equivalent to checking or unchecking Debug | Source Mode.
 | Allows you to change the display properties for the active debugging information window. Equivalent to Edit | Properties.
 | Allows you to change the font used in the debugging information windows. Equivalent to View | Font.
 | Displays the Options dialog box. Equivalent to View | Options.
 | Arranges the debugging information windows on the screen. Equivalent to Window | Arrange.


Shortcut Keys

The following shortcut keys can be used instead of the mouse to select menu items. Refer to the individual menu item pages for details:

Keystroke | Menu Equivalent
ALT+F4 | File | Exit
CTRL+F4 | File | Close Current Window
F5 | Debug | Go
SHIFT+F5 | Debug | Stop Debugging
CTRL+SHIFT+F5 | Debug | Restart
F6 | File | Attach to a Process
F7 | Debug | Run to Cursor
F8 | Debug | Step Into
F9 | If the active window is a Source or Disassembly window: Places a breakpoint at the current line. (If there is already a breakpoint set at the current line, this button removes the breakpoint.) Otherwise: Displays the Breakpoints dialog box like Edit | Breakpoints.
ALT+F9 | Edit | Breakpoints
F10 | Debug | Step Over
CTRL+F10 | Debug | Run to Cursor
F11 | Debug | Step Into
SHIFT+F11 | Debug | Step Out
ALT+1 | View | Command
ALT+2 | View | Watch
ALT+3 | View | Locals
ALT+4 | View | Registers
ALT+5 | View | Memory
ALT+6 | View | Call Stack
ALT+7 | View | Disassembly
ALT+8 | View | Scratch Pad
ALT+9 | View | Processes and Threads
CTRL+A | Edit | Select All
CTRL+C | Edit | Copy
CTRL+D | File | Open Crash Dump
CTRL+E | File | Open Executable
CTRL+F | Edit | Find
CTRL+G | Edit | Go to Address
CTRL+I | File | Image File Path
CTRL+K | File | Kernel Debug
CTRL+L | Edit | Go to Line
CTRL+O | File | Open Source File
CTRL+P | File | Source File Path
CTRL+R | File | Connect to Remote Session
CTRL+S | File | Symbol File Path
CTRL+V | Edit | Paste
CTRL+W | File | Open Workspace
CTRL+X | Edit | Cut
ALT+* (number keypad) | Edit | Go to Current Instruction
SHIFT+DELETE | Edit | Cut
CTRL+BREAK | Debug | Break

You can use the following keystrokes to move the caret in most of the debugging information windows:

Caret Movement | Keystroke
One character left | LEFT
One character right | RIGHT
Word left | CTRL+LEFT
Word right | CTRL+RIGHT
Line up | UP
Line down | DOWN
Page up | PGUP
Page down | PGDN
Beginning of current line | HOME
End of line | END
Beginning of file | CTRL+HOME
End of file | CTRL+END

Note In the Debugger Command window, the UP and DOWN keys will browse through the command history. The INSERT key can be used to turn insert mode on and off.

Use the following keystrokes to select text:

Select | Keystroke
Character to the left | SHIFT+LEFT
Character to the right | SHIFT+RIGHT
Word to the left | SHIFT+CTRL+LEFT
Word to the right | SHIFT+CTRL+RIGHT
Current line | SHIFT+DOWN if the caret is in column one
Line above | SHIFT+UP if the caret is in column one
To the end of the line | SHIFT+END
To the beginning of the line | SHIFT+HOME
Screen up | SHIFT+PGUP
Screen down | SHIFT+PGDN
To beginning of file | SHIFT+CTRL+HOME
To end of file | SHIFT+CTRL+END

Use the following keystrokes to delete text:

Delete | Keystroke
Character to right of caret | DELETE
Character to left of caret | BACKSPACE
Selected text | DELETE

The following shortcut keys are equivalent to KD / CDB control keys:

Keystroke | Menu Equivalent | KD / CDB Control Key
CTRL+ALT+A | Debug | Kernel Connection | Cycle Baud Rate | CTRL+A
CTRL+ALT+D |  | CTRL+D (Toggle Debug Info)
CTRL+ALT+K | Debug | Kernel Connection | Cycle Initial Break | CTRL+K
CTRL+ALT+R | Debug | Kernel Connection | Resynchronize | CTRL+R
CTRL+ALT+V | View | Verbose Output | CTRL+V
CTRL+ALT+W | View | Show Version | CTRL+W


Topic Not Found

No matching topic was found. Some possible reasons and remedies are as follows:

  • The file (.chm) that contains the destination topic is not in the expected location.

    Remedy: Rerun the MSDN Library Setup.

  • The file (.chm) that contains the current topic or destination topic is out-of-date and the link is no longer valid.

    Remedy: Install the latest version of the MSDN Library.

  • The MSDN Library CD is not in the CD-ROM drive.

    Remedy: Insert the MSDN Library CD into the CD-ROM drive.