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, people and events depicted herein are fictitious and no association with any real company, organization, product, person 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.

Unpublished work. © 1999-2001 Microsoft Corporation. All rights reserved.

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

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

Built on Monday, May 14, 2001


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, such as Dr. Watson, SymSrv, and SymStore.

These debugging tools are fully capable of running on Microsoft Windows NT® 4.0, Windows 2000, and Windows XP. They are also fully capable of debugging all of these Windows operating systems, as well as all applications, services, and drivers that run on these operating 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 which was 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, this 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 chapter includes:

Types of Debuggers

Terminology


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 NT® and Windows® 2000 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.

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 2000. This documentation may not reflect the current build of the NTSD on your Windows system.

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

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 Windows NT® and Windows® 2000.

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.

KD cannot set breakpoints in user-mode code and cannot be used to examine or deposit paged-out memory. Thus KD is rarely useful for debugging user-mode programs. 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 platform, an Alpha (RISC) platform, or an IA-64 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 names I386KD, AlphaKD, and 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 on Windows NT® and Windows 2000.

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 public function's names and variables 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. It includes a Debugger Command window to issue a wide variety of commands not available through the main window's menu. For kernel-mode debugging, WinDbg typically requires two machines (the host computer and the target computer). It also allows remote debugging of user-mode code.

Note On Windows 9x systems, WinDbg can only be used to debug user-mode drivers and applications. This debugging must be done on two machines, with the Windows 9x system as the target and WinDbg running on Windows NT or Windows 2000 on the host computer.

WinDbg is larger and somewhat slower than CDB / NTSD or KD, but it has additional features, including source-level debugging and the ability to read crash dump files.


Terminology

This section includes:

General Terms

Debugging Terms


General Terms

The following is a list of frequently-used Windows 2000 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
The 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
The 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 the Microsoft® Windows® 2000 operating system exist:

  • The free build (or retail build) 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) 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 processes have permission to access any part of the system, and are not restricted like user-mode processes. They can gain access to any part of any other process running in either user mode or kernel mode. In addition, all kernel-mode processes share the same address space.

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. This computer should run a version of Windows that is at least as recent as the one on 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 chapter 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 provides the same package, including the debuggers WinDbg, KD, CDB, and NTSD, as well as associated modules such as DbgHelp and SymSrv. The installation can be customized to include a variety of additional tools, such as SymStore and AutoDump Plus. Several extension libraries are also available.

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, and Windows XP. This documentation matches the version of NTSD included in this package — it might not match the version of NTSD which 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 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, and it doesn't matter whether it was made on an x86 or an Alpha platform.)
  • If you are performing live kernel-mode debugging, and the target computer is running Windows XP, 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. (This applies to both x86 and Alpha targets.)
  • 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 Tools for Windows do not run on an Alpha host computer. However, they will debug a target computer that is using an Alpha processor.


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® 2000 setup used to perform kernel debugging and diagnose system failures.

Typical Windows 2000 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, or Windows XP.
  • They can debug a target computer that is running on an x86 platform, an IA-64 platform, or an Alpha platform.
  • They can be launched from a host computer that is running Windows NT 4.0, Windows 2000, or Windows XP.
  • They can be launched from a host computer that is on an x86 platform or an IA-64 platform. (However, they cannot be launched from an Alpha host computer.)

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

However, if you are using a 1394 cable connection instead of a null-modem cable connection, the target computer and the host computer must both be running Windows XP. 1394 cable connections are only possible if the target computer is an x86.

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

1394 cable connections are only supported if both the target computer and the host computer are running Windows XP. Moreover, the target computer must be running on an x86 processor.

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

This section includes:

Configuring an x86 Target

Configuring an Alpha Target

Configuring an IA-64 Target


Configuring an x86 Target

The kernel debugger is enabled in the boot.ini file on an x86 computer. You must edit this file to activate the target system for kernel debugging.

This section includes:

Editing the boot.ini File

Boot.ini Parameters

Resolving x86 Boot Problems


Editing the boot.ini File

To configure the target computer, edit the boot.ini file by adding the appropriate debugger options to notify Windows to load the kernel debugger.

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 your Windows installation (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.
  7. If you are using a debug cable, add the following text at the end of this 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 this 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 during host computer setup, 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. Shutdown the computer and restart Windows.

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

Examples

The following boot.ini file can be used with a debug 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 2000 Professional" /fastdetect /debugport=com1 /baudrate=57600

The following boot.ini file can be used with a 1394 cable connection. Here there has been a triple-boot option created. Windows 2000 is installed on partition one. Windows Whister is installed on partition three; it can be selected for debug or without debug. The default boot line specifies partition three. Since there are two operating system specifications for this partition, the first of the two lines becomes the default setting (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 10 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=10 /debugport=COM1 /baudrate=19200

Loss of Reserved Port

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

As a result, 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.


Boot.ini Parameters

The following table lists the boot options that can be used in the boot.ini file to configure the target computer for debugging.

Option | 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.
/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 1394 debugging, Port should be 1394. If this parameter is omitted, the debugger defaults to COM2.
/channel=Channel | Specifies the 1394 channel number to be used. Valid channel numbers are 1 through 62. Channel must match the channel number used during host computer setup, 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 | Specifies a different kernel file than the one located in the default location, typically C:\%WINDIR%\system32. This can be useful in testing Hot Fixes and other patches to the kernel before making a permanent change to the system.
/hal | Specifies a different hardware abstraction level (HAL) file than the one located in the default location, typically C:\%WINDIR%\system32. This can be useful in testing Hot Fixes and other patches to the HAL before making a permanent change to the system.
/maxmem=SizeInMB | Specifies the amount of memory to be made available to the system. For example, you can restrict a 16 MB computer to 10 MB.
/sos | Causes the system loader to display the names of the drivers as they load while Windows is booting.

When you use the /debugport or /baudrate options, the /debug option is automatically assumed and does not need to be specifically included.

You will usually not want to select any of these options on the host computer, because this will tie up a COM port unnecessarily.


Resolving x86 Boot Problems

If kernel debugging has not been enabled on the target computer, you must edit the boot.ini file. However, if the target computer is not booting correctly, 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 2000 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 Alpha Target

To configure an Alpha-based computer for a kernel debugging session, you must change the OS OPTIONS settings in the non-volatile RAM (NVRAM).

This section includes:

Editing Alpha NVRAM Settings

OS OPTIONS Parameters


Editing Alpha NVRAM Settings

The following procedure is used to access and alter the OS OPTIONS settings in the non-volatile RAM (NVRAM) of an Alpha computer.

To Configure the NVRAM Settings on an Alpha Platform

  1. Press F2 (Setup) during BIOS initialization.
  2. In the Alpha BIOS Setup menu, choose Utilities | OS Selection Setup.
  3. Press ENTER.
  4. Select the correct operating system to boot, and then press F6 (Edit).
  5. Add the following line to OS Options:
    /debug /baudrate=19200
  6. Press ENTER to continue, and then F10 to save the changes.
  7. Press ENTER again to confirm.
  8. Press ESC twice to return to BIOS initialization.

The debug option is used to activate debugging. If you are not going to use the default COM port or the default baud rate, you will need to use additional options. There is also an option that enables the kernel debugger only upon system stops, which frees up the COM port during normal use. However, using this option prevents a debugger tool from gaining access to the target system during normal operation. See OS OPTIONS Parameters for a full list of options.

Loss of Reserved Port

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

As a result, 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 in the NVRAM.


OS OPTIONS Parameters

The following table lists the boot options that can be used in the OS OPTIONS settings to configure an Alpha target system for debugging.

Option | 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.
debugport=Port | Specifies the serial port to be used by the kernel debugger. If no serial port is specified, the debugger defaults to COM1 on Alpha computers.
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). The default rate is 19,200 bps. The higher baud rates (greater than 57600) can be unreliable.
kernel | Specifies a different kernel file than the one located in the default location, typically C:\%WINDIR%\system32. This can be useful in testing Hot Fixes and other patches to the kernel before making a permanent change to the system.
hal | Specifies a different hardware abstraction level (HAL) file than the one located in the default location, typically C:\%WINDIR%\system32. This can be useful in testing Hot Fixes and other patches to the HAL before making a permanent change to the system.
maxmem=SizeInMB | Specifies the amount of memory to be made available to the system. For example, you can restrict a 16 MB computer to 10 MB.
sos | Causes the system loader to display the names of the drivers as they load while Windows is booting.

When you use the debugport or baudrate options, the debug option is automatically assumed and does not need to be specifically included.

You will usually not want to select any of these options on the host computer, because this will tie up a COM port unnecessarily.


Configuring an IA-64 Target

To configure an IA-64 (Itanium-based) computer for a kernel debugging session, you must change the OsLoadOptions settings in the non-volatile RAM (NVRAM).

This section includes:

Editing IA-64 NVRAM Settings

OsLoadOptions Parameters


Editing IA-64 NVRAM Settings

The following procedure is used to access and alter the debugger-related settings in the non-volatile RAM (NVRAM) of an IA-64 computer.

To Configure the NVRAM Settings on an Alpha Platform

  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 during host computer setup, 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 Reserved Port

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

As a result, 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 in the NVRAM.


OsLoadOptions Parameters

The following table lists the boot options that can be used in the NVRAM OsLoadOptions value to configure an IA-64 target system for debugging.

Option | 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.
/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 1394 debugging, Port should be 1394. If this parameter is omitted, the debugger defaults to COM2.
/channel=Channel | Specifies the 1394 channel number to be used. Valid channel numbers are 1 through 62. Channel must match the channel number used during host computer setup, 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 | Specifies a different kernel file than the one located in the default location, typically C:\%WINDIR%\system32. This can be useful in testing Hot Fixes and other patches to the kernel before making a permanent change to the system.
/hal | Specifies a different hardware abstraction level (HAL) file than the one located in the default location, typically C:\%WINDIR%\system32. This can be useful in testing Hot Fixes and other patches to the HAL before making a permanent change to the system.
/maxmem=SizeInMB | Specifies the amount of memory to be made available to the system. For example, you can restrict a 16 MB computer to 10 MB.
/sos | Causes the system loader to display the names of the drivers as they load when Windows NT is booting.

When you use the /debugport or /baudrate options, the /debug option is automatically assumed and does not need to be specifically included.

You will usually not want to select any of these options on the host computer, because this will tie up a COM port unnecessarily.


Configuring Software on the Host Computer

Before you can begin kernel debugging, you must install all necessary symbol files, and set certain environment variables.

Installing Symbol Files

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

Configuring Environment Variables

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

If you will be working with the kernel debugger on a regular basis, you might want to create a batch file that includes all of the environment variables that you commonly use.

The following sample batch file could be used with a debug cable connection:

set _NT_SYMBOL_PATH=c:\winnt\symbols
set _NT_DEBUG_PORT=com1
set _NT_DEBUG_BAUD_RATE=19200
set _NT_DEBUG_LOG_FILE_OPEN=c:\DEBUG.LOG

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

set _NT_SYMBOL_PATH=c:\winnt\symbols
set _NT_DEBUG_BUS=1394
set _NT_DEBUG_1394_CHANNEL=44
set _NT_DEBUG_LOG_FILE_OPEN=c:\DEBUG.LOG

For an explanation of each of these environment variables, as well as a full list of useful variables, see the Environment Variables reference section.

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. This is a 1394 virtual driver that allows the debugger to communicate with the target computer. As a result, you must be logged in as an Administrator on the host computer during this debugging session.


User-Mode Setup

This section includes:

Configuring Hardware for User-Mode Debugging

Configuring Software for User-Mode Debugging

Enabling Just-in-Time (JIT) 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.

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

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

Note If you are performing remote debugging, these steps need to be done on both computers.

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.

CDB also attempts on startup to take commands from the file ntsd.ini in the current directory or in the path specified in 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
$u1: value ... $u9 value | Assign values to user-defined pseudo registers. You can specify numeric values n or 0xn or any other string. See Using Pseudo-Registers for full 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 CDB takes commands from at startup. No command-line equivalent.
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 Setting Symbol Options.
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 Just-in-Time (JIT) Debugging

There are a variety of application errors which will cause Windows NT/Windows 2000 a to terminate the application. The most common kinds of errors are deadlocks and access violations. From the operating systems point of view, these are all simply unhandled exceptions.

When an application error occurs, Windows searches for an exception handler. If it does not find an exception handler, the system verifies that the application is not currently being debugged and considers the exception to be unhandled. At this point, there are three possible responses:

  • Windows can end the process immediately.
  • Windows can freeze the process and start a user-mode debugger. This debugger can then be used to examine the application.
  • Windows can run a debugging tool which will create a memory dump file of the application's memory space, and then end the process.

The debugging tool which is used to debug the application or write the dump file is called Just-in-Time (JIT) Debugger, or the post-mortem debugger.

The default JIT debugger is Dr. Watson. When the application throws an unhandled exception, Dr. Watson attaches itself to the application and generates a crash dump file. After it creates the crash dump file, Dr. Watson closes the application and exits.

Any user-mode debugging tool can be selected as the JIT debugger:

  • To change the JIT debugger to WinDbg, run windbg -I. (The I must be capitalized.) When WinDbg is the JIT debugger, WinDbg will be activated whenever an application crashes. See WinDbg Command-Line Options for details.
  • To change the JIT debugger to CDB, you must edit the registry. When CDB is the JIT debugger, CDB will be activated whenever an application crashes.
  • To change the JIT debugger back to Dr. Watson, run drwtsn32 -i. When Dr. Watson is the JIT 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 JIT settings.

If a JIT 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, under \\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AeDebug\. The two relevant keys in this directory are Debugger and Auto.

The Debugger key's value shows the name of the debugger specified to analyze application errors. The Auto key is either zero or one.

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

If the Auto key equals zero and the Debugger value contains the name of a valid debugger (such as WinDbg or CDB), the message box will have two buttons: OK and Cancel. If the OK button is pressed, the application is terminated. If the Cancel button is pressed, the debugger specified in the Debugger key is started.

If the Auto key equals zero, but the Debugger key value is empty, the message box will have only an OK button and no debugger will start.

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

Setting Dr. Watson as the JIT debugger (default):

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

Setting WinDbg as the JIT debugger:

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

Setting CDB as the JIT debugger:

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

In these examples, -p %ld specifies the process ID that CDB will debug, -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.)


Debugger Operation

This chapter includes:

Starting the Debugger

The Debugger Command Window

The WinDbg Graphical Interface

Debugger Configuration

Symbols

Debugger Operation (General)

Debugger Operation (User Mode)

Debugger Operation (Kernel Mode)

Debugger Extensions

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 two other possible ways to begin a debugging session.

You can join a remote debugging session by connecting to a Debugging Server. See Activating the Debugging Client for details.

Or the debugger can also be automatically activated when a user-mode process fails. See Enabling Just-in-Time (JIT) Debugging 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.

(Windows XP 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.


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

On Windows XP, 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 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) command, not by any other method.

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 with the .detach (Detach from Process) or QD (Quit and Detach) commands.) 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=Port,baud=Rate
kd [-y SymbolPath] -k 1394:channel=Channel
kd [-y SymbolPath] -k serial:modem
kd [-y SymbolPath] -kl
kd [-y SymbolPath]

The -k command-line option specifies the connection type. There are four possible connection types:

  1. Specifying the com parameter indicates that the connection will use a COM port. Port should be 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). Rate should be the baud rate.
  2. Specifying the 1394 parameter indicates that the connection will use 1394. Channel must match the 1394 channel used at boot.
  3. Specifying the serial:modem parameter indicates that the connection will use a modem.
  4. Specifying the -kl option indicates that KD will perform local kernel debugging. See Performing Local Kernel Debugging for features peculiar to this technique. (Only users that have debug privileges can start this process.)

If you do not specify the connection options, KD checks to see if the _NT_DEBUG_PORT and _NT_DEBUG_BAUD_RATE environment variables have been set. If not, it defaults to a COM port connection, using COM1 and 19200 baud.

See KD Command-Line Options for the full command-line syntax. A number of other useful options are available. In particular, the symbol path must be set before kernel debugging can be successful. See Setting Paths and Loading Files for details.

WinDbg Command Line

Beginning a kernel debugging session from the WinDbg command line is done in the exact same way as in KD. See the preceding KD Command line subsection for the details; simply use "windbg" instead of "kd" on the command line.

Note that the full WinDbg command-line syntax is not the same as that of KD. See WinDbg Command-Line Options for details.

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:

  • 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. (This can be in the format "com2" or in the format "\\.\com2", but should not simply be a number). Then click OK. If you select OK without entering text, WinDbg checks to see if the _NT_DEBUG_PORT and _NT_DEBUG_BAUD_RATE environment variables have been set. If not, WinDbg defaults to COM1 and 19200 baud.
  • The 1394 tab indicates that the connection will use 1394. In the Channel text box, enter the 1394 channel used at boot. If you do not specify the channel, WinDbg checks to see if the _NT_DEBUG_1394_CHANNEL environment variable has been set.
  • The Local tab indicates that WinDbg will perform local kernel debugging. See Performing Local Kernel Debugging for features peculiar to this technique. (Only users that have debug privileges can perform local kernel debugging.)

The kernel debugging baud rate can be altered after the session has begun by using the CTRL+A control key. This only works in KD, not in WinDbg.

Note that the symbol path must be set before kernel debugging can be successful. See Setting Paths and Loading Files for details.

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. This is a 1394 virtual driver that allows the debugger to communicate with the target computer. You must be logged in as an Administrator on the host computer during this debugging session.


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

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, 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

Using Pseudo-Registers

Using Aliases

Using Shell Commands


Using Debugger Commands

When running 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.

When running 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 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.

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.

The Debugger Command Window Prompt

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

2:005>

In this example, "2" represents the current process and "005" represents the current thread.

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.

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 CTRL+C for an x86 target, or SYSRQ or ALT+SYSRQ for an Alpha target.

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 .cls (Clear Screen) command or the Edit | Clear Command Output menu command to clear all the text from the Debugger Command window, clearing the command history entirely.

You can also 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.

Macros

There are two kinds of text macros available in the Debugger Command window: Pseudo-Registers and Aliases. They are quite similar to each other in use. Pseudo-registers have a more complicated syntax than aliases, but are a bit more powerful.


Using Pseudo-Registers

There are fourteen text macros, known as pseudo-registers, available for use in the Debugger Command window. These can make entering commands quicker.

The pseudo-registers $u0 through $u9 are user-defined and can be set to equal any text string which does not contain the ENTER keystroke.

In addition, there are several pseudo-registers that are automatically set to specific debug information.

Automatic Pseudo-Registers

The following table displays the pseudo-registers that are automatically set:

Pseudo-Register | Description
$ea | The last effective address displayed
$exp | The last expression evaluated
$ra | The return address currently on the stack
$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

User-Defined Pseudo-Registers

The R (Registers) command is used to define the values of $u0 through $u9. When defining these pseudo-registers, place a period (.) before the u. The entire text after the equal sign is taken to be the pseudo-register value; this value can therefore include spaces or semicolons. This text should not be enclosed in quotes (unless quotes are actually desired in the results).

After a pseudo-register is defined, it can be used in any command entry. The register name automatically expands as text. It can therefore be used as an expression or as a macro. If a pseudo-register is used before it is defined, an error results.

Examples

Using pseudo-registers can eliminate the need to type long or complex symbol names:

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

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

0:000> r $.u3=r eax=eax+1; r ebx=ebx+1
0:000> $u3
0:000> $u3

Here is another example using a pseudo-register to simplify typing of commands:

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

The preceding expands to:

bp MyApi "dd esp 14; g"

Here is an example with an automatic pseudo-register. This will set a breakpoint that will be hit every time NtOpenFile is called by the current thread, but not when it is called by other threads:

bp /t @$thread nt!ntopenfile

Recursion

A pseudo-register can be used in the definition of another pseudo-register. Each pseudo-register 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

The following is also permitted, and gives 9:

0:000> r $.u0=2
0:000> r $.u0=7+$u0
0:000> ? $u0

The tools.ini File

CDB (and NTSD) support predefining pseudo-registers in the tools.ini file by adding $u fields to your [NTSD] entry:

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

Pseudo-Registers versus Aliases

Pseudo-registers are more flexible than aliases. However, aliases are more easy to use, and they can be listed quickly. See Using Aliases for details.

Pseudo-register replacement occurs before alias replacement.


Using Aliases

There are an unlimited number of text macros, known as aliases, available for use in the Debugger Command window. These can make entering commands quicker.

The alias consists of two parts: the alias name, which can be any text string that does not contain the ENTER keystroke or spaces, and the alias equivalent, which can be any text string that does not contain the ENTER keystroke and does not begin with leading spaces.

To define or redefine an alias, use the AS (Set Alias) command.

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

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

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. It will expand correctly at any point on a line, even within quote marks. However, it must not be touching any other text. The first character of the alias name must either begin the line, or be preceded by a space, a semicolon, or a quotation mark. The last character of the alias must end the line, or be followed by a space, a semicolon, or a quotation mark.

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

They 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

The preceding expands to:

bp MyApi "dd esp 14; g"

Recursion

An alias cannot be used in the definition of another alias. The text given as the alias equivalent is taken literally: it is not itself checked for aliases (although it is checked for pseudo-registers).

Aliases versus Pseudo-Registers

Aliases are easier to use than pseudo-registers. However, pseudo-registers are slightly more flexible: they can contain leading spaces, and they can be used adjacent to other text. See Using Pseudo-Registers for details.

Pseudo-register replacement occurs before alias replacement.


Using Shell Commands

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

The .shell (MS-DOS Shell) 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.

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 below.)
  • 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 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.


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.

Types of Workspaces

WinDbg has several different workspaces:

  • The base workspace is used when WinDbg is in a dormant state.
  • 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.
  • The default user-mode workspace is used when attaching to a user-mode process (with the -p command-line option or by selecting File | Attach to a Process).
  • 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, Alpha, and AXP64 architectures.

Default Workspaces

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.

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 -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 command or the CTRL+W shortcut key can be used to open and load a named workspace.
  • The File | Save Workspace command can be used to save the current default workspace or the current named workspace.
  • The File | Save Workspace As command can be used to assign a name to the the current workspace and save it.
  • The File | Clear Workspace command allows you to delete specific items and settings from the current workspace.

Information in Workspaces

Each workspace preserves the following information about the WinDbg graphical interface:

  • 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
  • Whether the toolbar and status bar are visible
  • Customization of the Register window, and flags in the Calls window and the Symbol 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

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

  • Breakpoint information (see the following note)
  • All break and handling information for exceptions and events
  • All open source files

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.

Note All kinds of 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. To avoid ambiguity, breakpoints specified by a symbol expression, by a line number, or by using the mouse in a Source window or the Disassembly window are all saved in workspaces, but breakpoints specified by numerical address alone are not saved in workspaces.


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.


Using the Help File

You can bookmark commonly-used pages of this Using Debugging Tools for Windows help file for easy access. To bookmark a page, go to that page, select the Favorites tab, and click Add. It will be added to the "Favorites" list.

To access this help file when WinDbg is running, use the Help | Contents, Help | Index, or Help | Search menu commands. These commands bring up this documentation and select the Contents, Index, or Search tabs, respectively.

A number of dialog boxes have Help buttons on them. These buttons will bring up this documentation and display the relevant page. The .hh (Open HTML Help File) command will also open this file.

This documentation can also be displayed by double-clicking on the debugger.chm file that was installed with the debuggers. A shortcut to this file can be found in Start | Programs | Debugging Tools for Windows | Debugging Help. To open this documentation from an MS-DOS Command Prompt, use the following command:

hh debugger.chm


Debugger Configuration

This section includes:

Keeping a Log File

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


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.

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

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 going to be upgrading your Windows version from time to time, or 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 Setting Symbol Options 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.

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. The Microsoft® Windows® 2000 and Windows NT® operating systems keep track of which exception handlers are associated with a specific process.

How an exception is handled depends on the current status of the process and any debuggers on the system.

Case One: No Debugger is Present on the System

If Windows has not been notified of any debugger existing on the system, it will look for exception handlers in a fixed order. Exception handling within the code itself (such as a try-except mechanism) will get the first chance to handle the exception. If the exception is not handled in any way, the operating system will terminate the process.

Case Two: "Just-in-Time" Debugger is Present

If a debugger has been set up as the Just-in-Time Debugger but is not currently attached to the process, Windows will look for exception handlers in the standard order. If the exception is not handled by any of the standard mechanisms, the JIT debugger will be started and will be given control of the process which threw the exception.

The debugger is then free to analyze the situation and either continue or terminate the process.

Case Three: Debugger is Already Attached to the Process

If an exception occurs in a process which is actively being debugged, Windows will contact debugger before looking for any other exception handler.

At this point, the application will break into the debugger—in other words, 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 the first time it occurs; it can break in only on the second occurrence; 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, execution occurs and the target will break into the debugger.
SXD or -xd | Second chance break (Disabled) | The first time this exception occurs, the debugger will ignore it. The second time it occurs, execution will halt and the target will break into the debugger.
SXN or -xn | Output (Notify) | When this exception occurs, it will not break into the debugger. However, a message informing the user of this exception will be displayed.
SXI or -xi | Ignore | When this exception occurs, it will be ignored by the debugger. 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 events can have their break status controlled by the SX* options. Their default handling status is always "not handled".

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
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
ser | System error | Ignore
sov | Stack overflow | Break

The following events can have their break status controlled by the SX* options. Since they are not actually faults, they do not require any handling.

Event Code | Meaning | Default Break Status
3c | Child application termination | Second-chance break
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[:baseaddr] | Unload module If baseaddr is specified, the break will occur when the DLL 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

The following events can have their break status controlled by the SX* options, as well as by other methods. The SX* options are useful if you want to have commands automatically execute at these points.

Event Code | Meaning | Default Break Status
ibp | Initial break point (This occurs at the beginning of the debug session, as well as after restarting or rebooting.) | In user mode: Enabled. 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 Enabled by a variety of methods; see Crashing and Rebooting the Target Computer for details.

The following events can have their break status and handling status controlled by SX* (except for CTRL+C, which always breaks into the debugger).

Event Code | Meaning | Default Handling
cc | CTRL+C or CTRL+BREAK (Handling status) | Handled
ch | Invalid handle (Break status) | Break
hc | Invalid handle (Handling status) | Not handled
bpe | Break instruction exception (Break status) | Break
bpec | Break instruction exception (Handling status) | Handled
sse | Single-step exception (Break status) | Break
ssec | Single-step exception (Handling status) | Handled


Symbols

This section includes:

Symbol Files: Overview

Installing Windows Symbol Files

Using Symbol Servers and Symbol Stores

Setting Symbol Options


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

Windows NT®, Windows® 2000, and all Windows drivers keep their symbols in files with the extensions .pdb and .dbg.

The Visual C++® 5.0 Linker creates both .pdb and .dbg symbol files. The Visual C++ 6.0 Linker places all symbols into .pdb files.

Windows NT/Windows 2000 and its 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 NT/Windows 2000, 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 Windows NT/Windows 2000, or a driver or application running on Windows NT/Windows 2000, you need to install the proper symbol files.

The symbol files on the host computer are required to match the version of Windows installed on the target computer. This fundamental point cannot be overstressed. If you are planning to do a kernel mode debug of a Windows NT 4.0 target from a Windows 2000 host, you need to install the Windows NT 4.0 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 2000

  1. Make sure you have at least 500 MB of available space on the disk drive of the host computer.
  2. Insert the 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

  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 product 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 SymStore


Using SymSrv

SymSrv (symsrv.dll) can deliver symbol files from a centralized symbol store that contains symbol files from a variety of sources. The symbol store can also contain pointers to symbol files, so the symbol server can retrieve symbol files directly from their sources. The symbol server can also be used to separate a large symbol store into a smaller subset that is appropriate for a specialized debugging task. Finally, the symbol server can obtain symbol files from an HTTP, HTTPS, or FTP source using the logon information provided by the operating system.

Setting the Symbol Path

To use the 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 two ways:

set _NT_SYMBOL_PATH = symsrv*symsrv.dll*\\Server\Share

or

set _NT_SYMBOL_PATH = symsrv*symsrv.dll*LocalDirectory*\\Server\Share

The symsrv keyword indicates that the debugger should look for symbols using a symbol server, and symsrv.dll gives the name of the symbol server DLL. Next portion is the name of the symbol server DLL (Symsrv.dll in this case).

If the first option is used, the debugger will load all symbol files from the specified Server and Share.

If the second option is used, the debugger will first look for a symbol file in the specified LocalDirectory. If the symbol file is not found, the debugger will locate the symbol file from the specified Server and Share, and then copy this symbol file to a subdirectory of the LocalDirectory. The file will be copied to a subdirectory in the tree under LocalDirectory 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 FTP site ftp.microsoft.com/mysymbols to your local directory c:\localsymbols, use:

set _NT_SYMBOL_PATH=symsrv*symsrv.dll*c:\localsymbols*ftp://ftp.microsoft.com/mysymbols

In addition, the symbol path may 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 may provide useful information.


Using SymStore

SymStore (symstore.exe) is a tool that builds a symbol store. It 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.

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\freebuild\symbols\*.* /s \\foo\symsrv /t "Windows 2000" /v "Build 2195 x86 free" /c "Sample add"
symstore add /r /p /f \\BuildServer\BuildShare\freebuild\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:

symstore add /r /p /g \\largeapp\appserver /f \\largeapp\appserver\bins\*.* /x \\hubserver\hubshare\myindex.txt

We have used the /g option to specify that the file prefix "\\largeapp\appserver" might change in the future. Now suppose you move all the symbol files off of the machine \\largeapp\appserver and put them on \\myarchive\appserver. We can now 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

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 defined 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.)

Following are 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 this transaction is deleted, it 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

The symbol store uses the file system itself as a database. For the first directory level under the root, a subdirectory is created for each unique file name. For example, f:\symsrv\foo.dbg, f:\symsrv\foo.pdb. For a .dbg file, the second subdirectory is the time/date stamp followed by the image size. For a .pdb file, the second subdirectory is the signature followed by the age. 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

Thus, the lookup path for the acpi.dbg with time/datestamp of 37cdb0396 and image size of 2040 is \\mybuilds\symsrv\acpi.dbg\37cdb03962040. Three files may exist inside the lookup directory. First, if the file was stored, then acpi.dbg will exist there. Second, if a pointer was stored, then a file called file.ptr will exist and contain the path to the file. Third, a file called refs.ptr contains a list of all the current locations for acpi.dbg with this time/datestamp 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. These contents are

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.


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 | On
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 | Off
0x400 | SYMOPT_EXACT_SYMBOLS | Off
0x80000000 | SYMOPT_DEBUG | Off

Setting the Symbol Suffix

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 is searching for. ASCII and Unicode symbols often have these suffixes, so this aids in symbol matching.

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 variety of other means are available to change these settings.

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.

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.

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.

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 not set, C++ translation is used, and :: is replaced by __ in all symbols.)

This option is on by default. 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 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 off by default. It can be activated by using the -sfce 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_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.

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.


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

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 (Program Step) |  | Debug | Step Over | F10
Step Out | g @$ra |  | Debug | Step Out | SHIFT+F11
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.

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 are more permanent than breakpoints set with BP; see details below.
  • 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 following toolbar button

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

Deferred Breakpoints

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. (Breakpoints set by BP will vanish once the relevant module is unloaded.)

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 the individual command pages and the Syntax Rules reference 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 ( ` ). See Source Line Number Syntax for details.
  • 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; but in the debugger, it is a symbol, and therefore 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. See Expression Syntax for details.
  • 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. Here 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 and Stack Traces on an Alpha

When debugging RISC targets, a breakpoint at a function's symbolic name or anywhere in the function prologue is automatically adjusted to the end of the prologue. However, if you trace into a routine you will step through the prologue instructions. The KB (Display Stack Backtrace) command uses the stack frame to determine which function is executing, and which stack frame is set up in the prologue. Therefore, you should step past the prologue to get an accurate stack trace.

A stack trace after an access violation in a window procedure may be uninformative, because the window procedure is called by a function pointer. If you place a breakpoint in the offending function, you will get a better stack trace.

See Viewing the Call Stack for an overview of stack tracing; see Stack Traces for a more advanced treatment.

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.


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 or write to a physical address, use the !db, !dc, !dd, !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. We then use the D* command to display one double-word at this address. (We 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

Note that here we have used decimal input, since that seems more natural for an integer, and since our default radix is still 10. Note that the output of the D* command will still be 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, IA-64, and Alpha processors each have a different collection 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 (Program 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, but additionally shows the first three parameters passed to the function. (This is not available on Alpha processors, since the Alpha passes arguments in registers rather than on the stack.)
  • The KP (Display Stack Backtrace) command displays the same stack as the KB command, but with additional information about the functions in the stack.
  • The KV (Display Stack Backtrace) command displays the same stack as the KB command, but with additional FPO information. (This is not available on Alpha processors.)
  • 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.
  • The UX (Unassemble BIOS) command can disassemble and display BIOS instructions on an x86 processor.
  • (WinDbg only) The Disassembly window can display 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 this line, the values of any memory locations or registers being accessed are displayed as well.

If you are viewing this 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. Enabled breakpoints are red and disabled breakpoints are yellow. If a breakpoint coincides with the current program counter, it is highlighted 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 Using Breakpoints.


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, 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 the Session but not Exiting

When using WinDbg, you can end the debugging session without exiting the debugger. In user mode, the target application will be terminated; in kernel mode, the target will remain in its current state. This is done by using the Q (Quit) command or selecting the Debug | Stop Debugging menu command. This can also be done by pressing the SHIFT+F5 shortcut key or by using the following button from the toolbar:

When CDB or WinDbg is performing user-mode debugging on Windows XP, it is possible to detach from the target application and leave it running. The .detach (Detach from Process) command will detach the debugger from the target, end the current debugging session, and leave the debugger running in dormant mode. In WinDbg, the QD (Quit and Detach) command will have the same effect. If WinDbg was started with the -pd command-line option, detaching will occur if the session is ended for any reason.

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 or by selecting Debug | Stop Debugging. See Attaching to a Running Process (User Mode) for details.)

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, created processes use a special debug heap. On Windows XP, 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, it may 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 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 Debug | 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 Debug | 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


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. 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 to an existing target application

  1. Determine the process ID of the target application. (If you are unsure about how to do this, 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 kill 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 distribute these events as desired.

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 will continue running. In this case, a second debugger can attach to the target without using the -pe option.)


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.


Changing Contexts

The term context refers to the perspective of the debugger. There are three contexts that can be set while debugging.

The first of these is the process context. This determines how the debugger will interpret virtual addresses. This is closely related to the user-mode address context.

The second is the register context. This 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.

The third of these is the local context. This determines how the debugger will interpret local variables. This is sometimes called the scope.

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 of 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, sp on an Alpha processor, and 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. Often this requires booting to the Windows safe build, replacing the driver binary, and then booting a second time.

However, Windows XP supports a simpler method of replacing driver files. This method can be used whenever WinDbg or KD is attached as a kernel debugger. It can be used to replace any kernel-mode driver (including display drivers), as well as Windows subsystem drivers such as win32k.sys.

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 on 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 the Driver Replacement Map File Format section following 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 old driver on the target computer: this will almost always begin with \SystemRoot\system32\drivers. 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.

For example:

map
\Systemroot\system32\drivers\videoprt.sys
e:\MyNewDriver\binaries\videoprt.sys
map
\Systemroot\system32\win32k.sys
\\myserver\myshare\new_drivers\new_win32k.sys

The driver replacement map file must be a text file, but any file name and extension will be accepted (.ini, .txt, .map, etc.)

Additional Notes

When driver substitution occurs, a message will appear in the kernel debugger.

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. 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 of course 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 (Program 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, .reboot
  • Breakpoint commands (BP, BU, BA, BC, BD, BE, and BL)
  • Register display commands (R and variations)
  • Stack trace commands (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 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; KD and CDB only) 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 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 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.
  • 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, 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:
    User Mode | Kernel Mode
    Windows NT 4.0
    (free build)         		nt4fre \ ntsdexts.dll nt4fre \ kdextx86.dll
    Windows NT 4.0
    (free build)         		nt4chk \ ntsdexts.dll nt4chk \ kdextx86.dll
    Windows 2000
    (free build)         		w2kfre \ ntsdexts.dll w2kfre \ kdextx86.dll
    Windows 2000
    (free build)         		w2kchk \ ntsdexts.dll w2kchk \ kdextx86.dll
    Windows XP | 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 should be an entry point into your DLL. These names must consist entirely of lower-case letters.

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 these extension samples. Each of them includes makefile and sources files to be used with the Build utility.

These sample extensions, and any extensions you develop, should be built by running the Build utility in one of the Build Environment windows that ships 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 Called from Debugger Extensions for a full listing of functions in wdbgexts.h.
    Major version | This indicates whether the target system is running a checked build of Windows NT/Windows 2000 (0x0c) or a free build (0x0f).
    Minor version | This is the Windows NT/Windows 2000 build number of the target system (for example, 1381).

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


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 two computers can be running Windows NT®, Windows® 2000, or later versions of Windows. The two computers do not have to be running the same version of Windows.

Performing remote debugging through a process server allows you to place a very light burden on the server. A very small application called a process server is run on the server. Then CDB, NTSD, or WinDbg is started 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, it 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 an MS-DOS® 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 and Windows XP. The 1394 protocol is only supported on Windows XP.

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. 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 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 and Windows XP only) See the Secure Channel (S-Channel) documentation in the MSDN® for details.
SPIPE-Parameters
(Windows 2000 and Windows XP 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.
-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 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 and Windows XP only) If SSL protocol is used, SSL-Parameters should match those used when the server was created.
SPIPE-Parameters
(Windows 2000 and Windows XP 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) character 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.

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 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 95, Windows 98, or Windows Millennium.

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


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 and Windows XP. The 1394 protocol is only supported on Windows XP.

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". 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 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 and Windows XP only) See the Secure Channel (S-Channel) documentation in the MSDN® for details.
SPIPE-Parameters
(Windows 2000 and Windows XP 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.

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 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 and Windows XP only) If SSL protocol is used, SSL-Parameters should match those used when the process server was created.
SPIPE-Parameters
(Windows 2000 and Windows XP 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.


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 cancel the process by using Task Manager on the server, or by using the .endpsrv (End Process Server) command in the Smart Client.


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 higher versions) 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 Make sure that either this batch file runs in the same folder containing the Remote.exe tool, that the folder containing remote.exe is in the system path, or that the path to remote.exe is explicitly defined in the 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.


Bug Checks (Blue Screens)

This chapter includes:

Blue Screen Data

Bug Check Analysis

Types of Bug Checks

Other Kinds of System Crashes

General Troubleshooting Tips


Blue Screen Data

When Windows NT®/Windows® 2000 encounters a condition that compromises safe system operation, the system halts and displays a blue character-mode screen. This screen is commonly referred to as the blue screen, Stop screen, or bug check. The operating system attempts to display as much information as possible about the current state of the machine when it encountered the error. If crash dumps were enabled on the system, a crash dump file is created that can be used at a later time for more detailed debugging. If a debugger is attached and active, the system causes a break so the debugger can be used to investigate the crash.

The following example of a blue screen contains several blocks of information that will be discussed in detail. These sections are located in the STOP information at the top of the screen: information about the loaded modules in the system, basic stack trace information, and information regarding the status of crash dumps and kernel debugger activity.

                                                 DSR CTS
*** STOP: 0x0000000A (0x00000000,0x0000001a,0x00000000,0x00000000)
IRQL_NOT_LESS_OR_EQUAL

p4-0300 irql:1f  SYSVER:0xf000030e

Dll Base DateStmp - Name             Dll Base DateStmp - Name
80100000 2e53fe55 - ntoskrnl.exe     80400000 2e53eba6 - hal.dll
80010000 2e41884b - Aha154x.sys      80013000 2e4bc29a - SCSIPORT.SYS
8001b000 2e4e7b6b - Scsidisk.sys     80220000 2e53f238 - Ntfs.sys
fe420000 2e406607 - Floppy.SYS       fe430000 2e406618 - Scsicdrm.SYS
fe440000 2e406659 - Fs_Rec.SYS       fe450000 2e40660f - Null.SYS
fe460000 2e4065f4 - Beep.SYS         fe470000 2e406634 - Sermouse.SYS
fe480000 2e42a4a4 - i8042prt.SYS     fe490000 2e40660d - Mouclass.SYS
fe4a0000 2e40660c - Kbdclass.SYS     fe4c0000 2e4065e2 - VIDEOPRT.SYS
fe4b0000 2e53d49d - ati.SYS          fe4d0000 2e4065e8 - vga.sys
fe4e0000 2e406655 - Msfs.SYS         fe4f0000 2e414f30 - Npfs.SYS
fe510000 2e53f222 - NDIS.SYS         fe500000 2e40719b - lance.sys
fe550000 2e406697 - TDI.SYS          fe530000 2e47c740 - nbf.sys
fe560000 2e5279d9 - nwlnkipx.sys     fe570000 2e53a89e - nwlnknb.sys
fe580000 2e494973 - tcpip.sys        fe5a0000 2e5256b8 - afd.sys
fe5b0000 2e5279d3 - netbt.sys        fe5d0000 2e4167f7 - netbios.sys
fe5e0000 2e4066b3 - mup.sys          fe5f0000 2e4f9f51 - rdr.sys
fe630000 2e53f24a - srv.sys          fe660000 2e516062 - nwlnkspx.sys

Address  dword dump   Build [782]                           - Name
ff541e4c fe5105df fe5105df 00000001 ff640128 fe4a8228 000002fe - NDIS.SYS
ff541e60 fe501368 fe501368 00000246 00004002 00000000 00000000 - lance.sys
ff541eb4 fe481509 fe481509 ff6688c8 ff668288 00000000 ff668138 - i8042prt.SYS
ff541ee0 fe481ea8 fe481ea8 fe482078 00000000 ff541f04 8013c58a - i8042prt.SYS
ff541ee4 fe482078 fe482078 00000000 ff541f04 8013c58a ff6688c8 - i8042prt.sys
ff541ef0 8013c58a 8013c58a ff6688c8 ff668040 80405900 00000031 - ntoskrnl.exe
ff541efc 80405900 80405900 00000031 06060606 06060606 06060606 - hal.dll

Restart and set the recovery options in the system control panel
or the /CRASHDEBUG system start option if this message reappears,
contact your system administrator or technical support group.
CRASHDUMP: Initializing miniport driver
CRASHDUMP: Dumping physical memory to disk:     2000
CRASHDUMP: Physical memory dump complete

This blue screen presents a significant amount of information to identify the problem that caused the system to halt. You can use this information, in conjunction with a debugger, to identify the problem.

Bug Check Information

Notice the bug check code, or stop code, labeled STOP at the top of the screen. This code varies, depending on the cause. The bug check code is issued in hexadecimal (in this case, 0x0000000A), and as a descriptive symbolic constant string (IRQL_NOT_LESS_OR_EQUAL).

There are four values that follow the bug check code; these are parameters which often relay valuable information. The parameters are passed to KeBugCheckEx, along with the bug check code itself, when the operating system determines that it can no longer continue to execute safely. In this example, the parameters are 0x0, 0x1A, 0x0, and 0x0.

Under some conditions, the kernel 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.

Recommended User Action

Windows 2000 may provide troubleshooting tips following the bug check information, including custom tips that are relevant to the particular error detected. These tips can be very useful.

Build Information

The next line provides the IRQL at which KeBugCheckEx executed (not the IRQL when the error occured), which is not especially valuable information. The IRQL information is followed by the system version (build number), which begins with 0xC (for a checked build) or 0xF (for a free build). The remainder of the number represents the actual build number in hexadecimal.

Loaded Drivers and Modules

Next, the blue screen displays information is information about each driver or base module that is loaded in the system. This information consists of:

  • The base address where each module is loaded.
  • A hexadecimal representation of the date stamp of the binary image.
  • The name of the driver or base component.

The base address information can be interpreted to determine which driver contains the address where, for example, a faulting instruction was executed. However, this section is generally less informative than bug check code and parameters.

Stack Trace

A brief stack trace follows the list of loaded drivers, which indicates what drivers and routines were being executed when the system failed. However, it is important to note that the last calls are not necessarily the cause of the system failure. The last calls on the stack trace can be system routines attempting to handle or process the error condition.

Debug Port Information

The final information displayed is related to the kernel debugger and crash dump status. This information indicates whether the target side of kernel debugging is active, and whether a crash dump file has been generated.

Finally, additional codes may appear in the upper right corner of the screen. These codes contain information about whether information is being sent to the kernel debugger. In this case, the "DSR CTS" informs the reader that a crash dump file was created and that the kernel debugger is attached.

The debug port information section confirms the communications parameters (the COM port number and transmission rate in bits per second) being used by the kernel debugger, and whether the debugger is enabled. It also indicates whether a memory dump file was saved (if the dump file indicator feature is enabled).

Reading Bug Check Information from the Debugger

You can review any of the blue screen information from within the debugger. To display the bug check code and parameters, use the .bugcheck (Display Bug Check Data) command.


Bug Check Analysis

After a system has bug checked, you can get useful information for further debugging, including obtaining the stack trace, and getting trap frame information.

When the debugger has connected and the system is accessible from the Debugger Command window of the host computer, type kv. This command displays a verbose kernel trace from the target computer, for example:

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

The information from a kernel trace includes the:

  • List of calling routines.
  • Parameters of each call
  • Trap frame address (if the routine stored a trap frame).

If a trap frame was stored, the information that caused the trap can be retrieved by using the .trap (Display Trap Frame) command. In the preceding example, a trap frame was stored by NT!_KiTrap0E (which is very common) at 8013eee8. When the trap frame has been retrieved, the KB (Display Stack Backtrace) command generates a stack trace for that trap frame. If no trap frame is available, then obtaining a stack trace requires a more complex method.

A frequent cause of bug check conditions is taking a page fault at a raised IRQL. This can be caused by many operations, including:

  • A call to a support routine at a higher IRQL level than permitted for the routine.
  • Using incorrect pointers.
  • Touching pageable memory at a raised IRQL.

A page fault condition generally creates a trap frame and a fault situation that requires additional investigation to determine the cause.


Types of Bug Checks

For full details on the various bug check codes, see the Bug Check Codes reference section.

The following sections contain an overview of several common types of bug checks:

General Bug Check Codes

Bug Check Codes During Installation

Bug Check Codes That Occur Only at Executive Initialization

Bug Check Codes Caused by Software Traps

Bug Check Codes Caused by Hardware Errors


General Bug Check Codes

The most common bug check codes are generated during normal operation. In Windows 2000, a driver or the file system can generate a bug check by introducing an unhandled error (exception) in the code, or by performing some illegal operation.

The most common bug check codes are:

Bug Check Code | Definition
0xA | IRQL_NOT_LESS_OR_EQUAL
0x1E | KMODE_EXCEPTION_NOT_HANDLED
0x23 | FAT_FILE_SYSTEM
0x24 | NTFS_FILE_SYSTEM
0x7F | UNEXPECTED_KERNEL_MODE_TRAP


Bug Check Codes During Installation

A bug check can be generated by an unsuccessful attempt to install Windows 2000. If this occurs, make sure that the computer and all of its peripheral hardware are Windows 2000-compatible by checking the latest Windows 2000 Hardware Compatibility List (HCL). Microsoft® compiles the HCL through rigorous component and compatibility testing of computers and peripheral hardware to determine if they work well with Windows 2000.

If your hardware is not listed in the Windows 2000 HCL, contact the hardware manufacturer as a first-line resource for available information, newly tested hardware, and basic input/output system (BIOS) and firmware revisions. Reducing the number of hardware components by removing nonessential peripherals and devices may help pinpoint installation conflicts.


Bug Check Codes That Occur Only at Executive Initialization

Some bug check codes only occur during the relatively short Phase 4 period of the Windows 2000 startup sequence, called Executive initialization. Initialization of the Windows 2000 Executive, a family of software components that provides basic operating system services, is a single step during Phase 4.

Executive initialization includes two distinct phases:

Phase 0
Interrupts are disabled and only a few Executive components, such as the Hardware Abstraction Layer (HAL), are initialized.
Phase 1
The system is fully operational, and the Windows 2000 subcomponents are fully initialized.

Phase 0 Initialization Bug Check Codes

If you get a Phase 0 initialization bug check code, you should run the hardware diagnostics provided by your system manufacturer.

Note In many cases, a hardware failure will manifest itself as an error that generates bug check codes. Therefore, troubleshooting these messages may include running hardware diagnostics on the system.

If no hardware problems are found, reinstall Windows 2000 and try to initialize it again. If you get the same message, contact a support technician. The Phase 0 initialization bug check codes are listed in the following table.

Message ID | Symbolic Name
0x31 | PHASE0_INITIALIZATION_FAILED
0x5C | HAL_INITIALIZATION_FAILED
0x5D | HEAP_INITIALIZATION_FAILED
0x5E | OBJECT_INITIALIZATION_FAILED
0x5F | SECURITY_INITIALIZATION_FAILED
0x60 | PROCESS_INITIALIZATION_FAILED

Phase 1 Initialization Bug Check Codes

If you get a Phase 1 initialization bug check code, you should reinstall Windows 2000 and try to initialize it again. If you get the same message, contact a support technician. The Phase 1 initialization bug check codes are listed in the following table.

Message ID | Symbolic Name
0x32 | PHASE1_INITIALIZATION_FAILED
0x61 | HAL1_INITIALIZATION_FAILED
0x62 | OBJECT1_INITIALIZATION_FAILED
0x63 | SECURITY1_INITIALIZATION_FAILED
0x64 | SYMBOLIC_INITIALIZATION_FAILED
0x65 | MEMORY1_INITIALIZATION_FAILED
0x66 | CACHE_INITIALIZATION_FAILED
0x67 | CONFIG_INITIALIZATION_FAILED
0x68 | FILE_INITIALIZATION_FAILED
0x69 | IO1_INITIALIZATION_FAILED
0x6A | LPC_INITIALIZATION_FAILED
0x6B | PROCESS1_INITIALIZATION_FAILED
0x6C | REFMON_INITIALIZATION_FAILED
0x6D | SESSION1_INITIALIZATION_FAILED
0x6E | SESSION2_INITIALIZATION_FAILED
0x6F | SESSION3_INITIALIZATION_FAILED
0x70 | SESSION4_INITIALIZATION_FAILED
0x71 | SESSION5_INITIALIZATION_FAILED


Bug Check Codes Caused by Software Traps

When the processor detects an erroneous software condition, called a software trap, a bug check may be generated. Software traps generally occur when a processor detects a problem, for example, an instruction that contains invalid operands, causing it to halt execution.

If one of these messages appears, make sure you transcribe the information that is displayed in the bug check information section of the bug check message. Then restart the computer. If the same message is displayed, you should either use a kernel debugger to diagnose the problem, or you should contact a support technician.

Information regarding specific bug checks can be found in the Bug Check Codes reference section.


Bug Check Codes Caused by Hardware Errors

The most common blue screens are those that signal a hardware failure, for example, Non-Maskable Interrupts (NMIs), or a variety of Fatal System Errors (FSEs or Bug checks). The hardware failure bug checks include:

Message ID | Symbolic Name
0x2E | DATA_BUS_ERROR
0x80 | NMI_HARDWARE_FAILURE
0x77 | KERNEL_STACK_INPAGE_ERROR
0x7A | KERNEL_DATA_INPAGE_ERROR
0xFACEFEED |


Other Kinds of System Crashes

This section includes:

Hardware Malfunction Messages

Stops With No Messages


Hardware Malfunction Messages

Hardware malfunction messages are another form of bug checks. Like bug check codes, they are character-mode messages that are generated by a hardware condition which was detected by the processor. The first several lines of a hardware malfunction message may differ from one computer to another, even with the same failed component, based on the hardware abstraction layer (HAL) that is loaded at startup. However, these lines generally convey the same concept, for example, as in the following x86-based computer malfunction message:

Hardware malfunction.
Call your hardware vendor for support.

The installed HAL also determines the format and content of the subsequent lines of each system's message. Therefore, you should contact your onsite support technician to run hardware diagnostics before you proceed with the recommendations included in the hardware malfunction message. This additional information, which is provided after the initial two lines in the message, will help your support technician decide which hardware diagnostics to run. For example, for x86-based ISA bus computers, this information indicates whether it is a memory-parity error or a bus-data error. On x86-based EISA computers, if the hardware problem is in an adapter, the adapter slot number on the system board is displayed.

Important In many cases, a hardware failure will first manifest itself as a bug check. The software that is used with the failing hardware can detect a potential problem when unexpected results occur, often before the hardware has been identified as faulty. Therefore, troubleshooting many of the bug check codes includes running hardware diagnostics on the system.

Under rare circumstances, hardware malfunction messages—specifically driver problems—can be generated by software bugs. For example, if a problematic driver writes to the wrong I/O port, the actual device at the targeted port might generate a hardware malfunction message. However, most errors of this sort are detected and debugged before the software is released.

If you require assistance to interpret this information, you should contact the specific hardware (computer, adapter, or peripheral device) manufacturer.


Stops With No Messages

Finally, sometimes machines will be simply suspended (no mouse or keyboard response, no video update, and so forth) without breaking into the debugger. Press CTRL+C on the debugger to cause a break.

See Debugging a Stalled System for details on how to proceed in this instance.


General Troubleshooting Tips

Many problems can be resolved through 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® 2000 Resource Kit Tools Help might isolate and resolve these issues.

For general troubleshooting of Windows 2000 bug check codes, follow these suggestions:

  • If you recently added hardware to the system, try removing or replacing it.
  • 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 boards are properly seated and all cables are completely connected.
  • Confirm that any new hardware is listed on the Windows 2000 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 2000 Advanced Options menu, choose Safe Mode.

  • Run a Windows 2000 compatible virus detection program. Viruses can infect all types of Windows-formatted hard disks, 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 any recently added software is listed on the HCL. If it is not listed, check with the manufacturer to see if an update or a patch is available. Otherwise, remove the program to see if this resolves the error.
  • Verify that the system has the latest Service Pack installed. To detect which Service Pack, if any, is installed on your system, click Start, point to Run, type winver, and then press ENTER. The About Windows 2000 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.
  • Check the Microsoft Support Web site using the keywords winnt and the full bug check code.

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.


Crash Dump Files

This chapter 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® 2000 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 new features of Windows 2000.

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

The Complete Memory Dump is the largest in size. 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

The 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 2000 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

The Small Memory Dump is a much smaller file 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
  • A list of loaded drivers
  • 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)

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 2000 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:

  1. Forcing a System Crash from the DebuggerDDK_Forcing_a_System_Crash_from_the_Debugger_dbg
  2. Forcing a System Crash from the KeyboardDDK_Forcing_a_System_Crash_from_the_Keyboard_dbg


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 with a bug check code of MANUALLY_INITIATED_CRASH (0xE2). Assuming crash dumps have been enabled, 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 path HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\i8042prt\Parameters, create a key 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 with a bug check code of MANUALLY_INITIATED_CRASH (0xE2). Assuming crash dumps have been enabled, 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 DumpChk and DumpExam tools are obsolete. They are 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. These dump files can be created on x86, IA-64, or Alpha platforms, running either Windows 2000 or Windows NT 4.0

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.

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.

If you are analyzing a Kernel Memory Dump or a Small Memory Dump, you may also 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.

Analyzing the Dump File

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.

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. These dump files can be created on x86, IA-64, or Alpha platforms, running either Windows 2000 or Windows NT 4.0

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.

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.

If you are analyzing a Kernel Memory Dump or a Small Memory Dump, you may also 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.

Analyzing the Dump File

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.

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, go to http://support.microsoft.com/support/kb/articles/Q253/0/66.asp and follow the instructions on that page.


User-Mode Dump Files

This section includes:

Creating a User-Mode Dump File

Reading a Dr. Watson Log File

Analyzing a User-Mode Dump File

There are two sizes of user-mode dump files: full user dump and minidump. For details on minidump files, see the DbgHelp Reference in the Platform SDK.


Creating a User-Mode Dump File

When an application error occurs, Microsoft® Windows® 2000 can respond in several different ways, depending on the just-in-time (JIT) debugging settings. If the JIT settings instruct a debugging tool to create a dump file, a user-mode memory dump file will be created.

In addition, the .dump (Create Dump File) command can be used to create a dump file. It does not cause the target application to terminate. This command can also be used to create a minidump file from a full user dump file.

There are two tools that can create a dump file when an application encounters an error:

  1. Dr. Watson (drwtsn32.exe)
  2. UserDump (userdump.exe)

Both of these tools will create the same kind of user-mode dump files.

The default JIT setting is for a dump file to be written by Dr. Watson. For details on how to alter this, see Just-in-Time (JIT) Debugging.


Dr. Watson

This section includes:

Using Dr. Watson to Create a Dump File

Installing Dr. Watson as the JIT Debugger


Using Dr. Watson to Create a Dump File

The Dr. Watson for Windows 2000 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 and is saved in the %AllUsersProfile%\Documents\DrWatson folder.

This 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 pop-up dialogue warning box is enabled (see Just-in-Time (JIT) debugger), you can copy the symbols when the pop-up box appears. But the symbols should not be copied after the debugger has started.


Installing Dr. Watson as the JIT Debugger

The default registry settings for Windows 2000 install Dr. Watson as the Just-in-Time (JIT) debugger. This means that when an application crashes, Dr. Watson will be activated and will save a memory dump file.

If these settings have been changed, you can reinstall Dr. Watson as the JIT debugger by running Dr. Watson with the -i option:

drwtsn32 -i

For details, see Dr. Watson Command-Line Options.


UserDump

The UserDump tool (userdump.exe) can create user-mode dump files.

UserDump and its documentation are part of the OEM Support Tools package.

To download these tools, go to http://support.microsoft.com/support/kb/articles/Q253/0/66.asp and follow the instructions on that page.


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

This section includes:

Analyzing a User-Mode Dump File with CDB

Analyzing a User-Mode Dump File with WinDbg

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.


Analyzing a User-Mode Dump File with CDB

User-mode memory dump files can be analyzed by CDB. These dump files can be created on Windows 2000 or Windows NT 4.0.

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.

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.

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. These dump files can be created on Windows 2000 or Windows NT 4.0.

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.

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.

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 chapter includes:

Elementary Debugging Techniques

Invalid or Missing Symbols

Stack Traces

Processor Architecture

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.

The easiest way to convert a virtual address to a physical address is to use the !pte extension command.

Converting a virtual address to a physical address

  1. Make sure that you are working in hexadecimal. If necessary, set the current base with the N 16 command.
  2. If you are debugging in kernel mode, make sure the process context is set to the desired process.
  3. Determine the byte index of the address. This number is equal to the lowest twelve bits of the virtual address. For example, the virtual address 0x8095A123 has a byte index of 0x123.
  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 8095a123
8095A123  - PDE at C0300808        PTE at C0202568
          contains 00042163      contains 0095A163
        pfn 42 G-DA--KWV    pfn 95a G-DA--KWV
  5. Look in the last row of the right column. The notation "pfn 95a" appears. Multiply this number by 0x1000, or, equivalently, shift it left 12 bits. This gives the page frame number (PFN) of the PTE: 0x95A000. The PFN is the physical address of the beginning of the page.
  6. Add the byte index to the PFN: 0x95A000 + 0x123 = 0x95A123. This is the desired physical address.
  7. You can verify that this computation was done correctly by displaying the memory at each address. The !dd extension displays memory at a specified physical address. It only accepts arguments ending in 0, so you can use it as follows:
    kd> !dd 0095a120
#      95a120  fffb0616 ef3254e8 75c73bff d720b805
#      95a130  e850757b 0006717e f6204e8b 75013841
#      95a140  .....
  8. The DD (Display Memory) command uses a virtual address as its argument:
    kd> dd 8095a120
8095a120  fffb0616 ef3254e8 75c73bff d720b805
8095a130  e850757b 0006717e f6204e8b 75013841
8095a140  .....
  9. Since the results are the same, this indicates that the physical address 0x0095A123 does indeed correspond to the virtual address 0x8095A123.

Converting Addresses By Hand

Although the !pte extension is the fastest way to convert virtual addresses to physical addresses, this conversion can be done without using this extension. 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 0x8095A123 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 8095a123
Evaluate expression:
  Hex:     8095a123
  Decimal: -2137677533
  Octal:   60045320443
  Binary:  10000000 10010101 10100001 00100011
  Chars:   ...#

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:

0x8095A123  =  0y  1000 0000 10   01 0101 1010   0001 0010 0011

This exposes the three pieces of the virtual address:

  • Page directory index = 0y1000000010 = 0x202
  • Page table index = 0y0101011010 = 0x15a
  • Byte index = 0y000100100011 = 0x123

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
                + 0x202 * 0x1000
                + 0x15a * 4
              = 0xc0202568

This is the address of the PTE. The PTE is a 32-bit DWORD. Examine its contents:

kd> dd 0xc0202568 L1
c0202568  0095a163

This PTE has value 0x0095A163. It is made of two fields:

  • The status flags are the low 12 bits: 0x163. For an explanation of the status flags, see the !pte reference page.
  • The page frame number (PFN) is the same as the PTE with the low 12 bits removed. In this case, it is 0x0095A163 & 0xFFFFF000 = 0x0095A000.

The PFN is the first physical address on the physical page. The byte index is the offset on this page. So the physical address you are looking for is 0x0095A000 + 0x123 = 0x0095A123. This is the same result obtained by the earlier method.


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. If possible, identify the thread as well.
  2. Attach WinDbg or CDB to this process.
  3. Identify which thread is causing the problem. It is very likely that when you break in with the debugger you will break into the offending thread, since this thread is using nearly 100% of the CPU time. To verify this, break in several times and use the !teb extension each time. Look at the line that says "Client ID":
    0:000> !teb
TEB at 7FFDD000
.....
    ClientId:         4cc.520

    In this case, the process ID is 0x4CC, and the thread ID is 0x520. You can use the .formats (Show Number Formats) command or the Calculator to convert these numbers to decimal.

  4. Use the KB (Display Stack Backtrace) command to obtain a stack trace of this thread:
    0:000> 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
  5. 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:000> g BuggyProgram!OpenDestFileStream+0xb3
  6. If this breakpoint is hit, repeat the process. For example, suppose this breakpoint is hit. The following steps should be taken:
    0:000> 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:000> g BuggyProgram!SaveMsgToDestFolder+0xb3

    If this is hit, we continue:

    0:000> 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:000> g BuggyProgram!DispatchToConn+0xa4
  7. Finally you will find a breakpoint which is not hit. In this case, we will 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.
  8. 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:000> bp BuggyProgram!SaveMsgToDestFolder+0xb3

0:000> g

0:000> g
  9. Use the P (Program 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.


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.


Invalid or Missing Symbols

This section includes:

Verifying Symbols

Reading Symbols from Paged-Out Headers

Debugging User-Mode Processes Without Symbols


Verifying Symbols

If the debugger does not seem to be loading symbols correctly, the following procedures can help:

The first thing to do is to check the symbol path:

kd> .sympath
Current Symbol Path is: d:\nt\bin\chk\i386\symbols\retail

If your symbol path is wrong, fix it, reload symbols (.reload modulename) and see if it works. If you are using the kernel debugger make sure your local %WINDIR% is not on your symbol path.

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.

kd> !sym noisy
kd> .reload nt
 1: Kernel Version 2081 MP Checked
 2: Kernel base = 0x80400000 PsLoadedModuleList = 0x80506fa0
 3: DBGHELP: FindExecutableImageEx-> Looking for D:\nt\bin\chk\i386\ntkrnlmp.exe...mismatched timestamp
 4: DBGHELP: No image file available for ntkrnlmp.exe
 5: DBGHELP: FindDebugInfoFileEx-> Looking for
 6: d:\nt\bin\chk\i386\symbols\retail\symbols\exe\ntkrnlmp.dbg... no file
 7: DBGHELP: FindDebugInfoFileEx-> Looking for
 8: d:\nt\bin\chk\i386\symbols\retail\symbols\exe\ntkrnlmp.pdb... no file
 9: DBGHELP: FindDebugInfoFileEx-> Looking for d:\nt\bin\chk\i386\symbols\retail\exe\ntkrnlmp.dbg... OK
10: DBGHELP: LocatePDB-> Looking for d:\nt\bin\chk\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 you are trying to load (lines three and four). The image itself is not always necessary, but if we find an incorrect one, the symbol handler will often fail. These lines show that we found an image at D:\nt\bin\chk\i386\ntkrnlmp.exe, but the time-date stamp didn't match. Because the time-date stamp didn't match, we continue on. We then search for a .dbg file and .pdb file that match the loaded image. These are on lines from 6 through 10. Line 11 warns us 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, we 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 standard Windows NT®/Windows® 2000 builds, 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, we interleave searching through the foo and bar directories, but in the .pdb search we do not.

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 either renaming your hal*.dbg and ntkrnlmp.dbg to hal.dbg and ntoskrnl.dbg, or by using the -mp and -h: options for KD or WinDbg.

To check symbol integrity, the first thing to do is dump out the build number with the following command: dd NtBuildNumber L1. The result should be a hexadecimal number where the first digit is either 'f' for free or 'c' for checked. The rest of the number should be the hexadecimal representation of the build number. Use a ? <rest of number> command to see the decimal representation.

Here's how to check what build is installed on the test system:

kd> version
Kernel Version 2003 UP Free
!vKernel base = 0x80400000 PsLoadedModuleList = 0x8046e4a0
debugger version: 5.0.8, built: Tue Mar 16 11:20:34 1999
    [name: d:\debug\2003\kd.exe]
dbghelp version: 5.0.8, built: Tue Mar 16 15:44:35 1999
    [path: d:\debug\2003\dbghelp.dll]
Extension DLL chain:
    kdextx86: version: 5.0.5, bu88ilt Tue Mar 16 14:19:20 1999
        [path: D:\debug\2003\kdextx86.dll]
Free Extension dll for Build 2003 debugging Free kernel for Build 0
    userkdx: version: 5.0.5, built Tue Mar 16 11:20:43 1999
        [path: D:\debug\2003\userkdx.dll]

This prints the version of the kernel you're debugging along with information about the debugging files themselves. In this example, the test system has Build 2003 Free installed. Notice how this information is more helpful than winver.exe because it lists whether the build is free or checked. Use !version to verify a tool match:

kd> !version
Free Extension dll for Build 2003 debugging Free kernel for Build 0

Another way to check the symbols is with the following commands:

kd> dd ntbuildnumber l1    // Note: this is L1, not eleven.
804628d4  f00007f4    // The f stands for Free.  C stands for checked.
kd> ? 00007f4    // This converts the hexadecima; number to a decimal number.
Evaluate expression: 2036 = 0x000007f4    // This is build 2036.

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 is required to find out anything useful about 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 above 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 which is essential to the debugging process, it can be a critical problem.

The following procedure can be used to solve this problem:

Acquiring 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. If you wish more verbose symbol output, use the !sym noisy extension command. If this is used, then 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 match the version used on the target computer.

This technique is only needed for kernel-mode debugging. The operating system is capable of paging in any headers needed 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 or Alpha) 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.


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 example is done with an Intel system, the process is essentially the same on RISC systems, just the register names are different, and there is a return address register on RISC.)

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 Intel, sp on MIPS and Alpha, and r1 on PPC) 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 Alpha 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

Unlike in the Alpha architecture, 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

Unlike the Alpha architecture, 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 | 0 1 |  |
iopl | I/O Privilege Level | 0 1 |  |

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 Alpha Processor

This section includes:

The Alpha Architecture

The Alpha Instructions

Sample Alpha Instructions

Stack Tracing on the Alpha Processor

Annotated Alpha Disassembly


The Alpha Architecture

Registers

Architecturally, the Alpha has 32 integer registers (r0 through r31), but they are assigned the following names and meanings by the Microsoft® Win32® calling convention.

Register | Win32 Register Name
v0 | accumulator (function return values go here)
t0 ... t12 | temporary registers (can be trashed by function)
s0 ... s5 | saved registers (must be preserved across call)
fp | frame pointer (s6)
a0 ... a5 | function arguments (can be trashed by function)
ra | return address
at | assembler temp register (for long jumps)
gp | global pointer
sp | stack pointer
zero | always zero

All integer registers are 64-bit. If you use a 32-bit instruction on them, then the 32-bit result is sign-extended to a 64-bit result and stored into the destination register. This is different from the Intel 16-bit alias registers like ax. On Intel®, storing to ax leaves the high word alone. On the Alpha, storing a 32-bit value to the 64-bit v0 register sign-extends the result to a full 64 bits. It also means that there is no 32-bit mode for the Alpha; you are always in 64-bit mode.

The following are non-integer registers, in addition to the ones mentioned in the preceding table.

Register | Win32 Register Name
f0 ... f31 | floating point registers (f31 always zero)
fzero | alternate name for f31
fir | program counter (instruction pointer)
lock_flag | (see the following Locked Loads section)
phys_locked | (see the following Locked Loads" section)

The traditional name for the program counter register is pc, but the debugger calls it fir which stands for the "fault instruction register."

Note that there is no flags register.

When using the ? (Evaluate Expression) command, registers should be prefixed with an at (@) sign. For example, you should use ? @a0 rather than ? a0. Without the @" sign, this register name will be interpreted first as a hexadecimal number, then as a symbol, and finally as a register.

However, the @ sign is not needed in the R (Registers) command. For instance, r a0 = 5 will always be interpreted correctly.

Since the Alpha cannot perform a relative branch to a target more than 128KB away, any jump/call to a far-away label needs to get patched by the linker. The linker generates a tiny stub that loads the at register with the actual address of the target and then performs an indirect jump through at. The linker places the stub near the instruction that wants to perform the jump/call and patches the jump/call to jump to/call the stub, which in turn jumps to the ultimate destination. So you can think of the at register as a register even more volatile than the regular volatile registers. Not only can it be trashed by a subroutine call, it can even be trashed by a jump instruction.

Debugger Register Dump

The following is a debugger register dump.

  v0=00000000 00000016   t0=00000000 00000000   t1=00000000 00000000
  t2=00000000 00000000   t3=00000000 00000009   t4=00000000 00000001
  t5=00000000 0006f9d0   t6=00000000 00000008   t7=00000000 00000000
  s0=00000000 00000001   s1=00000000 00000000   s2=00000000 00081eb0
  s3=00000000 77fc0000   s4=00000000 00081dec   s5=00000000 77fc0000
  fp=00000000 7ffde000   a0=00000000 750900c8   a1=00000000 00000001
  a2=00000000 00000009   a3=00000000 0006f9d0   a4=00000000 00000001
  a5=00000000 00000001   t8=00000000 0000004c   t9=00000000 00000001
 t10=00000000 0000004c  t11=ffffffff c00ea124   ra=00000000 77f4df08
 t12=00000000 00000001   at=00000000 77f548f0   gp=00000000 00000000
  sp=00000000 0006f9e0 zero=00000000 00000000 fpcr=08000000 00000000
softfpcr=00000000 00000000  fir=77f63bf4
 psr=00000003
mode=1 ie=1 irql=0

The extra registers not mentioned yet are:

  • fpcr and softfpcr, which are the floating point control registers
  • psr which is the processor status register
  • mode is 1 for user mode or 0 for kernel mode
  • ie is the interrupt enable flag
  • irql is the interrupt request level

None of these are particularly meaningful for user-mode debugging.

Conditions

The following table lists conditions along with their descriptions.

Name | Description
EQ | if zero
GE | if greater than or equal to zero
GT | if greater than zero
LBC | if low bit clear (even) — integer only, not FP
LBS | if low bit set (odd) — integer only, not FP
LE | if less than or equal to zero
LT | if less than zero
NE | if nonzero

Notation

The following table lists notations along with their descriptions.

Name | Description
Ra, Rb, Rc... | registers
#n | immediate unsigned byte value n (0 through 255)
Rb/#b | a register or an immediate unsigned byte value
disp16 | 16-bit immediate signed byte displacement
disp20 | 20-bit relative signed long displacement (for near jumps)
(r) | value stored at r
n(r) | value stored at r+n
x | L (long) or Q (quad)
w | B (byte) or W (word)
cc | A condition code listed under preceding Conditions section.

Data Types

  • byte: 8 bits
  • word: 16 bits
  • long: 32 bits
  • quad: 64 bits
  • various floating point types (F, G, S, T)

Addressing Modes

Unlike the x86 instruction set, which has more addressing modes than you can shake a stick at, the Alpha instruction set has only one addressing mode: indexed indirect. The notation for indexed indirect is n(r) which means "the value stored at memory location r+n." The expression inside the parentheses is always a register, and the expression outside the parentheses is always a number.

Pipelining

Alpha chips can be quad-issue. This means that it can do up to four things in one clock tick. The optimizer will try to group independent instructions in chunks of four so they can all execute simultaneously. Even if an instruction is speculative and might not actually end up being used, grouping it with an existing group of simultaneously-issuable instructions essentially executes it "for free." (The Pentium has the same effect with u/v pipelining. If you can reorder an instruction into an otherwise-empty v-slot, you basically execute it "for free.")

If you try to access a result before it is ready — for example, if you start a MUL instruction and try to read the result at the next clock tick — the Alpha will stall. So it's to the compiler's benefit to put as much distance between the computation or loading of a value and its use of the result. Doing so minimizes stalling, but it also makes the assembly harder to read because a single line of code can get spread out and interleaved with other stuff.

Unlike other RISC processors, the Alpha does not have jump delay slots.

Locked Loads

When a locked load occurs, the CPU memorizes the physical address. If another CPU accesses that address (or an address that is "near" that address — allowed for CPU optimization), then the lock flag is cleared. The lock flag is also cleared if an exception, interrupt, or some other unexpected event occurs.

If the same CPU accesses memory in any manner other than a store conditional, the lock flag state is unpredictable.

If the same CPU executes a branch instruction, the lock flag state is unpredictable.

Branches not taken do not affect the lock flag.

If the same CPU performs floating point, the lock flag state is unpredictable. (It may have trapped into emulation.)

It is an incorrect assumption that more than 40 instructions can be executed without an interrupt.

Since branches are predicted backwards taken, you need to be careful when writing LDx_L/STx_C code to avoid prefetch mispredictions.


The Alpha Instructions

Instructions marked with an asterisk (*) are particularly important.

Instructions marked with a plus (+) are new to EV56 and are emulated on older processors. They are typically generated only by the Microsoft® Win64™ compiler.

The general notation for instructions is to put the source registers on the left and the destination on the right. There are exceptions, however, most notably the load and jump class of instructions.

Arithmetic instructions are typically three-register with two source registers and one destination.

Effective Address

* | LDA | Ra, disp16(Rb) | load effective address
 |  | Ra = Rb + disp16 |
* | LDAH | Ra, disp16(Rb) | load effective address high
 |  | Ra = Rb + disp16 * 65536 |

Memory Access (Aligned)

* | LDx | Ra, disp16(Rb) | load long/quad into Ra
* | STx | Ra, disp16(Rb) | store Ra to long/quad
+ | LDwU | Ra, disp16(Rb) | load byte/word unsigned into Ra
+ | STw | Ra, disp16(Rb) | store Ra to byte/word

Memory Access (Synchronized)

LDx_L Ra, disp16(Rb) load long/quad locked

Load the value at address disp16(Rb) into register Ra and set the lock_flag.

STx_C Ra, disp16(Rb) store long/quad conditional

If the address monitored by the lock_flag has not been accessed by another processor, then store Ra to disp16(Rb) and set Ra to 1. Otherwise, store nothing and set Ra to 0.

Note that the Alpha compiler inlines the Interlocked Xxx functions, so don't be surprised to see these strange instructions when you expected an interlocked function call. See Interlocked Operations section in Sample Alpha Instructions for details.

Unaligned Memory Access

See sample code snippets below for examples.

LDQ_U | Ra, disp16(Rb) | load quad unaligned
 | Ra = (Rb+disp16 and not 7) |
STQ_U | Ra, disp16(Rb) | store quad unaligned
 | (Rb+disp16 and not 7) = Ra |

These instructions load and store a quad from a potentially unaligned address. Aligns the address (but not the value) before loading.

EXTxd Ra,Rb/#b,Rc extract subitem to Rc

The various EXTxd commands are:

EXTBL | extract byte low
EXTWL | extract word low
EXTLL | extract long low
EXTQL | extract quad low
EXTWH | extract word high
EXTLH | extract long high
EXTQH | extract quad high

  • if d = L, then shift Ra right Rb/#b bytes and extract low x
  • if d = H, then shift Ra left 8-Rb/#b bytes and extract high x

These instructions are used after performing an unaligned load to extract the low (or high) parts of the unaligned data. See Sample Unaligned Memory Access section in Sample Alpha Instructions for details.

INSxd Ra,Rb/#b,Rc insert sub-item

The various INSxd instructions are:

INSBL | insert byte low
INSWL | insert word low
INSLL | insert long low
INSQL | insert quad low
INSWH | insert word high
INSLH | insert long high
INSQH | insert quad high

  • if d = L, then shift Ra right Rb/#b bytes and erase all but the low x
  • if d = H, then shift Ra left 8-Rb/#b bytes and erase all but the high x

Prepare to store an unaligned value by shifting Ra by the amount necessary to store the low (or high) part at the address Rb, putting the result into Rc. All bits not affected by the unaligned object are zeroed. See Sample Unaligned Memory Access section in Sample Alpha Instructions for details.

MSKxd | Ra,Rb/#b,Rc | mask sub-item
 | Rc = Ra ZAP (mask SHL Rb/#b) |

Zero a bunch of bytes in Ra corresponding to the location of an x shifted left by Rb/#b bytes.

This is the other half of preparing to store an unaligned value. Ra is the current value of the memory, Rb is the address it came from, and Rc receives the result of zeroing out the parts of Ra that will be overwritten by the new data. See Sample Unaligned Memory Access section in Sample Alpha Instructions for details.

Control Flow

* Bcc Ra, disp20 branch if Ra meets condition

Conditional branches backwards are predicted taken. Conditional branches forward are predicted not taken.

* | BR | Ra, disp20 | unconditional branch (not expected to return)
* | BSR | Ra, disp20 | unconditional branch (expected to return)

Ra receives return address. Functionally equivalent, but BSR pushes Ra onto prediction stack; BR doesn't.

* | JMP | Ra, (Rb), hint16 | computed jump (not expected to return)
* | JSR | Ra, (Rb), hint16 | computed jump (expected to return)
* | RET | Ra, (Rb), hint16 | computed jump (end of subroutine)
 | JSR_CO | Ra, (Rb), hint16 | computed jump (coroutine transition)

Ra receives return address. Functionally equivalent, but affect prediction logic differently based on top two bits of hint:

00 JMP | no change to prediction stack,
 | low 14 bits of hint predict low 16 bits of target
01 JSR | push Ra onto prediction stack,
 | low 14 bits of hint predict low 16 bits of target
10 RET | pop one entry off prediction stack,
 | predict returning to popped address
11 JSR_CO | replace top of prediction stack with Ra,
 | predict returning to replaced address

In RET and JSR_COROUTINE, low 14 bits of hint are ignored by hardware, but reserved by Digital as follows:

0000 | nonprocedure return
0001 | procedure return

Arithmetic

* | ADDx | Ra,Rb/#b,Rc | Rc = Ra + Rb/#b
 | SnADDx | Ra,Rb/#b,Rc | Rc = Ra*n + Rb/#b (n=4,8)
* | CMPEQ | Ra,Rb/#b,Rc | Rc = 1 if Ra == Rb/#b, else 0
* | CMPLT | Ra,Rb/#b,Rc | Rc = 1 if Ra < Rb/#b, else 0
* | CMPLE | Ra,Rb/#b,Rc | Rc = 1 if Ra <= Rb/#b, else 0
* | CMPULT | Ra,Rb/#b,Rc | Rc = 1 if Ra <U Rb/#b, else 0
* | CMPULE | Ra,Rb/#b,Rc | Rc = 1 if Ra <=U Rb/#b, else 0
* | MULx | Ra,Rb/#b,Rc | Rc = Ra * Rb/#b
 | UMULH | Ra,Rb/#b,Rc | Rc = HIDWORD(Ra *U Rb/#b)
* | SUBx | Ra,Rb/#b,Rc | Rc = Ra - Rb/#b
 | SnSUBx | Ra,Rb/#b,Rc | Rc = Ra*n - Rb/#b (n=4,8)

Note No integer divide.

Bits

* | AND | Ra,Rb/#b,Rc | Rc = Ra and Rb/#b
* | BIC | Ra,Rb/#b,Rc | Rc = Ra and not Rb/#b "bit complement"
* | BIS | Ra,Rb/#b,Rc | Rc = Ra or Rb/#b "bit sum"
 | EQV | Ra,Rb/#b,Rc | Rc = Ra eqv Rb/#b
 | ORNOT | Ra,Rb/#b,Rc | Rc = Ra or not Rb/#b
* | XOR | Ra,Rb/#b,Rc | Rc = Ra xor Rb/#b
* | SLL | Ra,Rb/#b,Rc | Rc = Ra SHL Rb/#b (mod 64)
* | SRA | Ra,Rb/#b,Rc | Rc = Ra SAR Rb/#b (mod 64)
* | SRL | Ra,Rb/#b,Rc | Rc = Ra SHR Rb/#b (mod 64)
* | CMOVcc | Ra,Rb/#b,Rc | Rc = Rb/#b if Ra meets condition

You can also think of "bis" as "bit set" and "bic" as "bit clear". For example, "bis a,#1,c" sets the bottom bit and "bic a,#1,c" clears it.

Bit Counting

+ | CTLZ | Rb/#b,Rc | Rc = number of leading (high-order) zero bits in Rb
+ | CTTZ | Rb/#b,Rc | Rc = number of trailing (low-order) zero bits in Rb
+ | CTPOP | Rb/#b,Rc | Rc = number of set bits in Rb

Bytes

CMPBGE Ra,Rb/#b,Rc parallel compare byte greater or equal

Compare Ra and Rb/#b bytewise, storing result in Rc bit by bit.

ZAP | Ra, Rb/#b, Rc | zero out bytes
ZAPNOT | Ra, Rb/#b, Rc | zero out all bytes except

Rb/#b is a bitmask of bytes. ZAP zeroes them; ZAPNOT saves them from being zeroed.

Conversion

+ SEXTx Rb/#b, Rc sign-extend byte/word in Rb to Rc

If you read the information in this section you know that there is already a SEXTL instruction in the basic Alpha instruction set:

ADDL zero,Rb/#b, Rc sign-extend long in Rb to Rc

There are no zext x instructions for zero-extending a value because you can use the zap instruction.

Float

LDf | Fa,disp16(Fb)
STf | Fa,disp16(Fb)

Values for f: F, G, S, T

FBcc Fa,disp20 floating point conditional branch

(Several additional float instructions exist, but they are very rare.)

Multimedia Extensions

+ | MINUB8 | Ra, Rb/#b, Rc | bytewise unsigned minimum
+ | MINSB8 | Ra, Rb/#b, Rc | bytewise signed minimum
+ | MINUW4 | Ra, Rb/#b, Rc | wordwise unsigned minimum
+ | MINSW4 | Ra, Rb/#b, Rc | wordwise signed minimum
+ | MAXUB8 | Ra, Rb/#b, Rc | bytewise unsigned maximum
+ | MAXSB8 | Ra, Rb/#b, Rc | bytewise signed maximum
+ | MAXUW4 | Ra, Rb/#b, Rc | wordwise unsigned maximum
+ | MAXSW4 | Ra, Rb/#b, Rc | wordwise signed maximum

These instructions treat the registers as eight bytes or four words, and perform element by element min/max.

+ PERR Ra, Rb/#b, Rc Rc = pixel error of Ra and Rb/#b

The sources are treated as eight bytes and the absolute value of their differences is summed and stored into Rc

+ | PKLB | Rb/#b, Rc | pack longs into bytes
+ | PKWB | Rb/#b, Rc | pack word into bytes

Treat the sources as two longs or four words and contract them down into two bytes or four bytes, truncating as necessary. Use ZAP to pack a quad.

+ | UNPKBL | Rb/#b, Rc | unpack bytes to longs
+ | UNPKBW | Rb/#b, Rc | unpack bytes to words

Take the bottom two or four bytes of the source and expand them into two longs or four words, zero-extending as necessary. Use ZAP to unpack into a quad.

Miscellaneous

 | IMB |  | flush instruction prefetch
 | FETCH | 0(Rb) | prefetch data at Rb for read
 | FETCH_M | 0(Rb) | prefetch data at Rb for modify
+ | WH64 | Rb | hint that 64 bytes will be overwritten

These instructions let you announce your intentions to the processor so it can prepare memory for you. The wh64 instruction tells the processor that you will be overwriting this memory, so it does not need to save the old value. For example, you can use it when you're doing a large block copy.

* MB memory barrier (multiprocessor sync)

Ensure that all pending memory access is completed before starting new memory access. Used by the Interlocked functions to update shared memory in a multiprocessor-predictable manner.

+ WMB write memory barrier

Same as MB but only flushes memory writes. Memory reads are unaffected.

RPCC Ra read processor cycle counter

Actual count is LODWORD(Ra) + HIDWORD(Ra).

* TRAPB trap barrier

Ensure that all things that might trap do trap before proceeding. It does not force the operations to run to completion, only long enough to check whether or not a trap will occur. For example, a LDL instruction will execute far enough to verify that the memory is readable but doesn't wait for the data actually to arrive before allowing execution to proceed past the TRAPB.

You will see these when structured exception handling is going on. They make sure that the exception is raised before the code leaves the protected block.

+ | AMASK | Rb/#b,Rc | query processor instruction set support
+ | IMPLVER | Rc | query processor implementation version

AMASK tells you which instructions will trap into emulation. Use it to decide whether or not to use new instructions.

IMPLVER tells you how fast the architecture is. Use it to decide how aggressively to interleave instructions.

RDTEB v0 = current TEB pointer

Idioms

* | BIS | zero,zero,zero | NOP
 | CPYS | fzero,fzero,fzero | FNOP
* | BIS | zero,zero,Ra | CLR — store zero to register
 | CPYS | fzero,fzero,Fa | FCLR — store zero to register
* | BIS | zero,#b,Rc | load immediate small integer
* | SUBx | zero,#b,Rc | load immediate small negative integer
* | LDA | Ra,disp16(zero) | load 16-bit signed integer
* | BIS | Ra,Ra,Rc | MOV Rb,Rc (recommended by DEC)
* | BIS | zero,Ra,Rc | MOV Rb,Rc (generated by compiler)
 | CPYS | Fb,Fb,Fc | FMOV Fb,Fc
 | SUBx | zero,Rb,Rc | NEGx Rb,Rc
 | SUBx | zero,Fb,Fc | NEGx Fb,Fc (might trap)
 | CPYSN | fzero,Fb,Fc | FNEG Fb,Fc (never traps)
 | ORNOT | zero,Rb,Rc | NOT Rb,Rc
 | CPYS | zero,Fb,Fc | FABS Fb,Fc
* | BR | zero,disp20 | BR disp20 (unconditional jump)
 | ADDL | zero,Rb,Rc | Rc = sign extend Rb to 64-bits

Loading a 32-bit Constant

The way to load a 32-bit constant depends on whether bit 15 is set, and what range the high word of the 32-bit value is located in.

Let XXXXYYYY be the value you want to load.

Let XXX1 = XXXX + 1.

Let WWWW = ~XXXX = 0x10000 - XXXX.

Let WWW1 = ~XXX1 = 0x10000 - (XXXX + 1) = 0xFFFF - XXXX. You will be loading WWW1 with the LDAH instruction, so the result of the load will be

LDAH | Ra, -WWW1(zero) | Ra = -(0x10000 - XXXX - 1) * 65536
 |  | Ra = FFFFFFFF`XXXX0000 + 0x10000

Let VVVV = ~VVVV = 0x10000 - VVVV.

Shortcut Cases

If XXXX = 0 and YYYY is less than 0x8000, then the value can be loaded in one instruction:

LDA Ra, YYYY(zero) Ra = 00000000`0000YYYY

Similarly, if XXXX = 0xFFFF and YYYY is greater than or equal to 0x8000, you can load it by subtracting from zero:

LDA | Ra, -VVVV(zero) | Ra = -VVVV
 |  | Ra = -(0x10000 - YYYY)
 |  | Ra = 00000000`00000000 - 0x10000 + YYYY
 |  | Ra = FFFFFFFF`FFFF0000 + YYYY
 |  | Ra = FFFFFFFF`FFFFYYYY

The Easiest Case

If both XXXX and YYYY are less than 0x8000:

LDAH | Ra, XXXX(zero) | Ra = 00000000`XXXX0000
LDA | Ra, YYYY(Ra) | Ra = 00000000`XXXXYYYY

A Slightly Harder Case

If XXXX < 0x7FFF and YYYY >= 0x8000, this means that both XXX1 and VVVV are less than 0x8000, so you start with a value that is 0x10000 too large, then subtract down to the value you want.

LDAH | Ra, XXX1(zero) | Ra = 00000000`XXXX0000 + 0x10000
LDA | Ra, -VVVV(Ra) | Ra = 00000000`XXXX0000 + 0x10000 - VVVV
 |  | Ra = 00000000`XXXX0000 + 0x10000 - (0x10000 - YYYY)
 |  | Ra = 00000000`XXXX0000 + YYYY
 |  | Ra = 00000000`XXXXYYYY

A Much Harder Case

If XXXX is 0x7FFF and YYYY >= 0x8000, our task becomes harder because XXX1 = 0x8000, which will be sign-extended.

LDAH | Ra, -32768(zero) | Ra = FFFFFFFF`80000000
LDA | Ra, -VVVV(Ra) | Ra = FFFFFFFF`80000000 - VVVV
 |  | Ra = FFFFFFFF`80000000 - (0x10000 - YYYY)
 |  | Ra = FFFFFFFE`7FFF0000 + YYYY
 |  | Ra = FFFFFFFE`7FFFYYYY
ADDL | zero, Ra, Ra | Ra = 00000000`7FFFYYYY

Recall that the last instruction is shorthand for "sign-extend the Ra register from a 32-bit value to a 64-bit value."

A Special Case

However, if the number you want to load is 0x7FFFFFFF, you can get by with just two instructions instead of three.

LDA | Ra, -1(zero) | Ra = FFFFFFFF`FFFFFFFF
SRL | Ra, #33, Ra | Ra = 00000000`7FFFFFFF

Loading Negative Numbers by Subtracting Twice

If both XXXX and YYYY are greater than or equal to 0x8000, then you can subtract twice.

LDAH | Ra, -WWW1(zero) | Ra = FFFFFFFF`XXXX0000 + 0x10000
LDA | Ra, -VVVV(zero) | Ra = FFFFFFFF`XXXX0000 + 0x10000 - VVVV
 |  | Ra = FFFFFFFF`XXXX0000 + 0x10000 - (0x10000 - YYYY)
 |  | Ra = FFFFFFFF`XXXX0000 + YYYY
 |  | Ra = FFFFFFFF`XXXXYYYY

Loading Negative Numbers by Subtracting and Adding

Finally, if XXXX is greater than or equal to 0x8000 but YYYY is less than 0x8000, then you should subtract first and then add.

LDAH | Ra, -WWWW(zero) | Ra = FFFFFFFF`XXXX0000
LDA | Ra, YYYY(zero) | Ra = FFFFFFFF`XXXX0000 + YYYY
 |  | Ra = FFFFFFFF`XXXXYYYY

Things You May Have Noticed

You may have noticed that Win32® DLLs are always loaded on 64K boundaries. After seeing the Alpha instruction set, the reason for this becomes more clear: By always choosing a 64K boundary, it means that the loader never has to fix up the LDA part of an LDAH/LDA pair. If DLLs could be loaded at off-64K boundaries, then the loader would also have to fix all the lda instructions In addition to that, if the DLL moved from below the 32K boundary to above the 32K boundary, the loader would also have to modify the ldah instructions. This action can in turn cause trouble if the compiler had optimized the access, since it knew that two variables were in the same 64K chunk, but relocation moved them into separate chunks.

This also explains why there is a 64K "noman's land" near the 2GB boundary where DLLs cannot be loaded. As you noticed, loading addresses close to 2GB sometimes takes three instructions, so if a DLL got relocated into that zone, the loader would have to insert instructions into the DLL, which is hard to do.


Sample Alpha Instructions

Sample Sub-DWORD Memory Access

Bytes

    ;
    ;   Load an unsigned byte from r0 into r1.
    ;
    LDQ_U   r1, (r0)                    Load the entire quadword
    EXTBL   r1,r0,r1                    Extract the byte

    ;
    ;   Load a signed byte from r0 into r1, where the alignment of r0
    ;   is not known.
    ;
    LDQ_U   r1, (r0)                    Load the entire quadword
    LDA     r2, 1(r0)                   Adjust by one (sneaky trick coming)
    EXTQH   r1,r2,r1                    Extract the desired byte into the top byte
    SRA     r1,#56,r1                   Signed shift right 56 positions

If the alignment of r0 is known, then the "LDA/EXTQH" can be combined into one instruction.

    ;
    ;   Load a signed byte from r0 into r1, where r0 is known to be on
    ;   a QWORD boundary.
    ;
    LDQ     r1, (r0)                    Load the entire quadword (will trap if not aligned)
    EXTQH   r1,#1,r1                    Extract the desired byte into the top byte
    SRA     r1,#56,r1                   Signed shift right 56 positions

    ;
    ;   Store a byte in r1 to r0.
    ;
    LDQ_U   r2,(r0)
    INSBL   r1,r0,r3
    MSKBL   r2,r0,r4
    BIS     r2,r4,r2
    STQ_U   r5,(r0)

If you know you are on a processor with the extended instructions, these are much simpler to do:

    ;
    ;   Load a byte from r0 into r1.
    ;
    LDBU    r1, (r0)                    Load an unsigned byte
    SEXTB   r1, r1                      Optional sign extension

    ;
    ;   Store a byte in r1 to r0.
    ;
    STB     r1, (r0)

Words

    ;
    ;   Load an aligned word from r0 into r1.
    ;
    LDQ_U   r1, (r0)
    EXTWL   r1,r0,r1
    SLL     r1,#48,r1                   These two instructions
    SRA     r1,#48,r1                   perform sign extension

    ;
    ;   Store an aligned word in r1 to r0.
    ;
    LDQ_U   r2,(r0)
    INSWL   r1,r0,r3
    MSKWL   r2,r0,r4
    BIS     r2,r4,r2
    STQ_U   r5,(r0)

Again, if you know you are on a processor with the extended instructions, these are much simpler to do:

    ;
    ;   Load a word from r0 into r1.
    ;
    LDWU    r1, (r0)                    Load an unsigned word
    SEXTW   r1, r1                      Optional sign extension

    ;
    ;   Store a word in r1 to r0.
    ;
    STW     r1, (r0)

Sample Unaligned Memory Access

Reading Unaligned Memory

    ;
    ;   Load an unaligned dword at r0 into r1.
    ;
    LDQ_U   r1, (r0)                    r1 = CBAx xxxx
    LDQ_U   r2, 3(r0)                   r2 = yyyy yyyD
    EXTLL   r1,r0,r1                    r1 = 0000 0CBA
    EXTLH   r2,r0,r2                    r2 = 0000 D000
    BIS     r2,r1,r1                    r1 = 0000 DCBA

And more generally:

    ;
    ;   Load an unaligned x (x = B/W/L/Q) at r0 into r1.
    ;
    LDQ_U   r1, (r0)
    LDQ_U   r2, n(r0)                   not needed if x = B; n = sizeof(x)-1
    EXTxL   r1,r0,r1
    EXTxH   r2,r0,r2                    not needed if x = B
    BIS     r2,r1,r1                    not needed if x = B

Storing Unaligned Memory

    ;
    ;   Store an unaligned dword in r5 to r0.
    ;
    LDQ_U   r2,3(r0)                    r2 = yyyy yyyD
    LDQ_U   r1,(r0)                     r1 = CBAx xxxx
    INSLH   r5,r0,r4                    r4 = 0000 000d
    INSLL   r5,r0,r3                    r3 = cba0 0000
    MSKLH   r2,r0,r2                    r2 = yyyy yyy0
    MSKLL   r1,r0,r1                    r1 = 000x xxxx
    BIS     r2,r4,r2                    r2 = yyyy yyyd
    BIS     r1,r3,r1                    r1 = cbax xxxx
    STQ_U   r2,3(r0)                    must store high then low
    STQ_U   r1,(r0)                     in case r0 was aligned

And more generally:

    ;
    ;   Store an unaligned x (x = B/W/L/Q) in r5 to r0.
    ;
    LDQ_U   r2,n(r0)                    not needed if x = B; n = sizeof(x)-1
    LDQ_U   r1,(r0)
    INSxH   r5,r0,r4                    not needed if x = B
    INSxL   r5,r0,r3
    MSKxH   r2,r0,r2                    not needed if x = B
    MSKxL   r1,r0,r1
    BIS     r2,r4,r2                    not needed if x = B
    BIS     r1,r3,r1
    STQ_U   r2,n(r0)                    not needed if x = B
    STQ_U   r1,(r0)

Interlocked Operations

    ;
    ;   Inline InterlockedExchange of a0 with the dword at v0,
    ;   putting the previous value in a1.
    ;
Again:
    MB                                  memory barrier
    BIS     a0, zero, a2                a2 = potential new value
    LDL_L   a1, 0(v0)                   get old value
    STL_C   a2, 0(v0)                   store new value conditional
    BEQ     a2, failed                  jump if failed
    MB                                  memory barrier
    ... continue with previous value in a1 ...

    ;
    ;   The failure case is an out-of-line forward jump because
    ;   forward jumps are predicted not taken, and there is rarely
    ;   a collision on interlocked instructions.
    ;
failed:
    BR      zero, Again                 retry


Stack Tracing on the Alpha Processor

This section includes:

Reading a Dump of Alpha Registers

Stack Traces on an Alpha

Tracking Down Function Parameters on an Alpha


Reading a Dump of Alpha Registers

Compaq/Digital Alpha systems behave differently on the kernel debugger because their processors utilize a Reduced Instruction Set Computer (RISC) architecture instead of the Complex Instruction Set Computer (CISC) architecture found in Intel x86 processors. You can use many of the same debugging commands from x86 systems on alpha systems. Just be prepared for some different output. Here's a register dump from an Alpha Miata. Notice that the familiar x86 registers and pointers – EAX, EBP, ESP – aren't present on Alpha systems:

kd> r
  v0=00000000 00000016   t0=ffffffff 8010cd10   t1=ffffffff 80140000
  t2=00000000 00000001   t3=00000000 00000005   t4=00000000 00000000
  t5=00000000 00000000   t6=ffffffff 80ae0950   t7=00000000 00000001
  s0=ffffffff 80ae0000   s1=ffffffff 810f86a0   s2=ffffffff 80ae0950
  s3=ffffffff 80ae0628   s4=ffffffff 80ae06d0   s5=ffffffff 81121280
  fp=ffffffff 80abbd60   a0=00000000 00000001   a1=00000000 0000001f
  a2=ffffffff 80140c30   a3=00000000 00000000   a4=00000000 0001312d
  a5=00000000 00000000   t8=ffffffff 80ae0020   t9=00000000 c5d7423e
 t10=00000000 00000500  t11=00000000 0000a4b9   ra=ffffffff 8066db2c
 t12=00000000 00000200   at=00000000 7fffffff   gp=ffffffff 801489e0
  sp=ffffffff 80abbd50 zero=00000000 00000000 fpcr=08000000 00000000

v0 = return value

t(x) = temporary registers which don't need to be restored

s(x) = scratch registers which need to be restored

a(x) = arguments (unlike x86 machines, these are not pushed on to the stack)

Here's an actual break on the Miata system:

*** Fatal System Error: 0x000000d1
                       (0x00000000,0x00000005,0x00000000,0x00000000)

AlphaKD: A fatal system error has occurred.
AlphaKD: Debugger entered on first try; Bugcheck callbacks have not been invoked
.
AlphaKD: A fatal system error has occurred.

ntoskrnl!RtlpBreakWithStatusInstruction:
8010cd14 : 000000ad callkd
  v0=00000000 00000016   t0=ffffffff 80000003   t1=000a0a29 70257830
  t2=ffffffff 80abb3da   t3=ffffffff 80abb3db   t4=00000000 0000006b
  t5=00000000 00000000   t6=00000000 00000200   t7=00000000 0a000000
  s0=00000000 00000003   s1=ffffffff 800bcf00   s2=ffffffff 80ae0950
  s3=ffffffff 80138950   s4=ffffffff 80143438   s5=00000000 00000000
  fp=ffffffff 80abbb50   a0=00000000 00000003   a1=ffffffff 80abb630
  a2=00000000 0000006a   a3=00000000 00000000   a4=00000000 0000006a
  a5=10020600 06030010   t8=ffffffff 80abb370   t9=00000100 06000006
 t10=00000000 00000000  t11=00000000 00000001   ra=ffffffff 800bce98
 t12=80000000 00000004   at=80abb370 0000006a   gp=ffffffff 801489e0
  sp=ffffffff 80abb590 zero=00000000 00000000 fpcr=08000000 00000000
softfpcr=00000000 00000000  fir=8010cd14
 psr=00000016
mode=0 ie=1 irql=5
ntoskrnl!RtlpBreakWithStatusInstruction:
8010cd14 : 000000ad callkd

Callee-SP   Arguments to Callee                 Call Site

 80abb590 : 00000003 80abb630 0000006a 00000000 ntoskrnl!RtlpBreakWithStatusInst
ruction [Note that a function call - RtlpBreakWithStatusInstruction - is still present on alphas stack traces.]
 80abb590 : 00000003 80abb630 0000006a 00000000 ntoskrnl!KiBugCheckDebugBreak+0x
34
 80abb5d0 : 00000003 80abb630 0000006a 00000000 ntoskrnl!KeBugCheckEx+0x4ac
 80abbb50 : 00000003 80abb630 0000006a 00000000 ntoskrnl!KiMemoryManagementExcep
tion+0x120
80143420  000000d1 00000000 00000005 00000000
80143430  00000000
kd> kv

Callee-SP Return-RA  Call Site

 80abb590 800bce94 : ntoskrnl!RtlpBreakWithStatusInstruction
 80abb590 800bd64c : ntoskrnl!KiBugCheckDebugBreak+0x34
 80abb5d0 800c7b5c : ntoskrnl!KeBugCheckEx+0x4ac
 80abbb50 00000000 : ntoskrnl!KiMemoryManagementException+0x120 [80abbb50 is the trap frame.]
kd> .trap 80abbb50
v0 = 00000000 00000016     a0 = 00000000 00000001
t0 = ffffffff 8010cd10     a1 = 00000000 0000001f
t1 = ffffffff 80140000     a2 = ffffffff 80140c30
t2 = 00000000 00000001     a3 = 00000000 00000000
t3 = 00000000 00000005     a4 = 00000000 0001312d
t4 = 00000000 00000000     a5 = 00000000 00000000
t5 = 00000000 00000000     t8 = ffffffff 80ae0020
t6 = ffffffff 80ae0950     t9 = 00000000 c5d7423e
t7 = 00000000 00000001    t10 = 00000000 00000500
                          t11 = 00000000 0000a4b9
                           ra = 00000000 00000000
                          t12 = 00000000 00000200
                           at = 00000000 7fffffff
                           gp = ffffffff 801489e0
fp = ffffffff 80abbd60     sp = ffffffff 80abbd50
fir= 00000000 00000000
+0x0
00000000 ???????????????


Stack Traces on an Alpha

A Warning About the KB Command

Since parameters on the Alpha are passed in registers, when you repeat the KB (Display Stack Backtrace) command, you will just see the same arguments over and over again (namely, the current values in registers a0 through a5).

Reconstructing the Call Stack

When you are debugging an Alpha and the K (Display Stack Backtrace) command is not giving a decent stack trace, you'll have to reconstruct the call stack by hand. Fortunately, it's not very difficult, because the Microsoft® Win32® calling convention imposes rules on what the Alpha call stack must look like.

Suppose the K command is giving the following output:

kd> k
Callee-SP Return-RA  Call Site
 0235d380 777b63e4 : comctl32!TB_OnSysColorChange+0x60

Clearly that isn't very useful. You need to unwind the stack. To do this, you have to keep track of the stack pointer depth and watch where the compiler stashed the return address. You can do this by going forwards or backwards.

Here is an example of "going backwards." This is useful, since you are in the middle of the function and don't know where it ends. Subtract the offset 0x60 which appeared in the last code sample:

kd> u .-60
comctl32!TB_OnSysColorChange:
777b6380 : 23deffe0 lda    sp,-20(sp)
777b6384 : b53e0000 stq    s0,0(sp)
777b6388 : b55e0008 stq    s1,8(sp)
777b638c : b75e0010 stq    ra,10(sp)

This shows that this function uses 0x20 bytes of stack and stores the return address at offset 0x10. Use this offset of 0x10 in a DD (Display Memory) command:

kd> dd @sp+10 l1
0235d390  7773b4e8

This shows that the return address is 7773b4e8, and that the caller's stack begins at @sp+20. Use the U (Unassemble) command:

kd> u 7773b4e8
comctl32!ToolbarWndProc+1f58:
7773b4e8 : a20b0040 ldl    a0,40(s2)
7773b4ec : 47ef0411 bis    zero,fp,a1
7773b4f0 : 47ed0412 bis    zero,s4,a2
7773b4f4 : 47ec0413 bis    zero,s3,a3
7773b4f8 : e61ff989 beq    a0,0000000077739b20 comctl32!ToolbarWndProc+590
7773b4fc : d3407858 bsr    ra,0000000077759660 comctl32!SendMessageD
7773b500 : 47ff0400 bis    zero,zero,v0
7773b504 : c3e00122 br     zero,000000007773b990 comctl32!ToolbarWndProc+2400

Referring to the source code, you can discover that the last line is a jump to the exit code. Now work forwards, using the address 7773b990 from that last line:

kd> u 7773b990
comctl32!ToolbarWndProc+2400:
7773b990 : a75e0048 ldq    ra,48(sp)
7773b994 : a57e0020 ldq    s2,20(sp)
7773b998 : a59e0028 ldq    s3,28(sp)
7773b99c : a5be0030 ldq    s4,30(sp)
7773b9a0 : a5de0038 ldq    s5,38(sp)
7773b9a4 : a53e0010 ldq    s0,10(sp)
7773b9a8 : a55e0018 ldq    s1,18(sp)
7773b9ac : a5fe0040 ldq    fp,40(sp)
7773b9b0 : 63ff0000 trapb
7773b9b4 : 23de01b0 lda    sp,1b0(sp)
7773b9b8 : 6bfa8001 ret    zero,(ra),1  comctl32!TB_OnSysColorChange+60

This function keeps its return address at offset 0x48. Since the stack was already offset by 0x20 by ToolbarWndProc, the combined offset from @sp is:

kd> dd @sp+20+48 l1
0235d3e8  77c9a028

By repeating this procedure, you can obtain as much of the call stack as you need:

kd> u 77c9a028
user32!CallWindowProcAorW+1d8:
77c9a028 : b01e0040 stl    v0,40(sp)
77c9a02c : 43e00000 addl   zero,v0,v0
77c9a030 : a75e0030 ldq    ra,30(sp)
77c9a034 : a53e0008 ldq    s0,8(sp)
77c9a038 : a55e0010 ldq    s1,10(sp)
77c9a03c : a57e0018 ldq    s2,18(sp)
77c9a040 : a59e0020 ldq    s3,20(sp)
77c9a044 : a5be0028 ldq    s4,28(sp)
77c9a048 : 23de0060 lda    sp,60(sp)
77c9a04c : 6bfa8001 ret    zero,(ra),1  comctl32!TB_OnSysColorChange+60
kd> dd @sp+20+1b0+30 l1
0235d580  77cb64c0
kd> u 77cb64c0
user32!CallWindowProcW+10:
77cb64c0 : a75e0000 ldq    ra,0(sp)
77cb64c4 : 23de0010 lda    sp,10(sp)
77cb64c8 : 6bfa8001 ret    zero,(ra),1  comctl32!TB_OnSysColorChange+60
kd> dd @sp+20+1b0+60+0 l1
0235d5b0  777a7c04

You have successfully reconstructed the call stack as:

comctl32!TB_OnSysColorChange+0x60
comctl32!ToolbarWndProc+1f58
user32!CallWindowProcAorW+1d8
user32!CallWindowProcW+10

Continue until you have found what you need.


Tracking Down Function Parameters on an Alpha

On a RISC system (Alpha, MIPS, PowerPC), parameters are stored in registers instead of on the stack. This means that in most cases additional detective work is necessary to determine the value of the parameters passed to a function in the stack trace. The parameters will only be accessible if they were saved on the stack before the parameter register (and any copies) were altered. This is almost always the case, but there may be cases where the value of the parameters will be unattainable.

On Alpha and MIPS, parameters are passed in order (first parameter to last) in the registers A0, A1, A2, and so on. On a MIPS system, there are four such registers (A0-A3) and on an Alpha system there are six (A0-A5). Should there be more parameters for a function than A# registers, additional parameters are placed in the registers T0-T7 on both systems. On PPC systems, the parameters are passed in order from first to last in the registers R3, R4, R5,...,R31.

Finding the values passed in these registers will require some knowledge of the assembly code for each platform type, as the movement of the value of a parameter will have to be tracked from register to register and eventually onto the stack, where it can be accessed. The first step in finding the parameter values is to disassemble the beginning of the function. The function should be disassembled up to the point where a memory location containing the value can be identified, or to a point where the next function call on the stack occurred without the register being saved. (Note that this is not necessarily a fatal condition in finding the parameters' values.)

When debugging unoptimized code, the kb (Display Stack Backtrace) command will often give the correct parameters because the parameter registers are immediately written to the stack. When debugging optimized modules, such as Windows 2000 system modules, the problem becomes far less trivial, as optimization of a module will in most cases remove the convenient method of saving off parameters. Take the following (partial) stack from an Alpha system, for instance, which has hit a user-defined breakpoint in NT!ExAllocatePoolWithTag:

kd> kb
Callee-SP   Arguments to Callee                 Call Site
 80075a80 : 00000000 00000005 2074624e 28002a00 NT!ExAllocatePoolWithTag+0x28
 80075ae0 : 00000000 00000005 2074624e 28002a00 netbt!TcpSendSessionResponse+0x38
 80075b20 : 00000000 00000005 2074624e 28002a00 netbt!CompleteSessionSetup+0xc4
 80075b50 : 00000000 00000005 2074624e 28002a00 netbt!Inbound+0x4b8
 80075bd0 : 00000000 00000005 2074624e 28002a00 netbt!TdiReceiveHandler+0x74c
 80075c60 : 00000000 00000005 2074624e 28002a00 tcpip!IndicateData+0xc0

Note that it is apparent in this examples that the arguments listed in the backtrace are incorrect. To find the values of the parameters which were passed to netbt!TdiReceiveHandler, the first step is to find the code for the module and to determine the number of parameters and their types:

NTSTATUS
TdiReceiveHandler (
    IN  PVOID                ReceiveEventContext,
    IN  PVOID                ConnectionContext,
    IN  USHORT               ReceiveFlags,

    IN  ULONG                BytesIndicated,
    IN  ULONG                BytesAvailable,
    OUT PULONG               BytesTaken,
    IN  PVOID                pTsdu,
    OUT PIRP                 *ppIrp
    );

With this information, disassemble the function in the debugger. Only the key pieces of the disassembly are included in the following code example. From the preceding prototype, you know that you must be concerned (on Alpha) with the registers A0-A5 and T0-T1. The first mention of these in the disassembly is as follows:

kd> u netbt!TdiReceiveHandler+0x24
netbt!TdiReceiveHandler+0x24:
fb220824: 47f3040a bis     zero,a3,s1
fb220828: b21e0070 stl     a0,70(sp)
fb22082c: 47f4040b bis     zero,a4,s2
fb220830: a27e0098 ldl     a3,98(sp)
fb220834: 43f10014 addl    zero,a1,a4
fb220838: 47f5040c bis     zero,a5,s3

The bis instruction is a bit-wise OR which is frequently used on RISC architectures with zero to copy a value from one location to another. The instruction bis zero,a3,s1 copies the A3 register to the S1 register, indicating that the instruction ldl a3,98(sp) (which loads the register A3 from memory) has not ruined the chance of finding the parameter value, since the value is now stored in S1. The best part about the preceding fragment, is that the A0 register gets saved directly to memory, and so is accessible to us:

kd> dd 80075bd0+70 l1   /*  ReceiveEventContext from register a0 */
80075c40  80844040

Frequently it is possible to determine a parameter value by looking at the assembly code for the calling function directly before the call, to determine where it loaded the values of the different registers from. Applying this method, noting that netbt!TdiReceiveHandler was called from tcpip!IndicateData+0xc0 (that is, the function at an offset of hexadecimal C0), you would disassemble the instructions prior to the call to determine where the registers A0-A5, T0, and T1 came from.

kd> u tcpip!IndicateData+0xb8
tcpip!IndicateData+0xb8:
fb1c11c8: 47ec0414 bis     zero,s3,a4
fb1c11cc: 22be0058 lda     a5,58(sp)
fb1c11d0: 6b4e4000 jsr     ra,(s5),0   /* tcpip!IndicateData+0xc0: this is the call */

Now you know that the sixth parameter (BytesTaken in register A5) is stored at location 58 relative to the frame pointer for tcpip!IndicateData. At first, the instruction bis zero,s3,a4 seems of no particular value, until you note that the instruction copies the value into register A4, leaving the value in S3 as well, and that the value of the S3 register is saved to the stack at the top of netbt!TdiReceiveHandler:

kd> u netbt!TdiReceiveHandler
netbt!TdiReceiveHandler:
fb220800: 23deff70 lda     sp,-90(sp)
fb220804: b53e0010 stq     s0,10(sp)
fb220808: b55e0018 stq     s1,18(sp)
fb22080c: b57e0020 stq     s2,20(sp)
fb220810: b59e0028 stq     s3,28(sp)

Thus, you can determine the values of the fifth and sixth parameters to TdiReceiveHandler (BytesAvailable and BytesTaken in registers A4 and A5) in the following manner:

kd> dd 80075bd0+28 l1    /*  BytesAvailable in register a4  */

80075bf8  00000048
kd> dd 80075c60+58 l1    /*  BytesTaken in register a5  */
80075cb8  00000048

It is also useful in many cases to trace upward in the stack. If a parameter that was passed to netbt!TdiReceiveHandler was in turn passed on to netbt!Inbound then you can attempt to determine where the value came from at the time of the second call. In TdiReceiveHandler, Inbound is in fact called by pointer in the following way:

status = (*pLowerConn->CurrentStateProc)(ReceiveEventContext,
                                         pLowerConn,
                                         ReceiveFlags,
                                         BytesIndicated,
                                         BytesAvailable,
                                         BytesTaken,
                                         pTsdu,
                                         ppIrp);

Note that ReceiveFlags, BytesIndicated, pTsdu, and ppIrp (four of the parameters to TdiReceiveHandler that you have yet to determine) are passed to the function Inbound in the registers A2, A3, T0, and T1 respectively. Thus, you wish to find the values of these registers at the time of the call to Inbound through the pointer pLowerConn->CurrentStateProc. Note the following disassembly fragment, which as the stack trace above informs us, represents the instructions leading up to the call to Inbound:

kd> u netbt!TdiReceiveHandler+0x71c ld
netbt!TdiReceiveHandler+0x71c:
fb220f1c: 47ea0413 bis     zero,s1,a3
fb220f20: a03e0090 ldl     t0,90(sp)
fb220f24: 47eb0414 bis     zero,s2,a4
fb220f28: a5fe0080 ldq     fp,80(sp)
fb220f2c: 47ec0415 bis     zero,s3,a5
fb220f30: a0090058 ldl     v0,58(s0)
fb220f34: b43e0000 stq     t0,0(sp)
fb220f38: a05e0098 ldl     t1,98(sp)
fb220f3c: 49e07632 zapnot  fp,#3,a2
fb220f40: b45e0008 stq     t1,8(sp)
fb220f44: a21e0070 ldl     a0,70(sp)

fb220f48: a23e0074 ldl     a1,74(sp)
fb220f4c: 6b404000 jsr     ra,(v0),0

The registers T0 and T1 are loaded from locations based on SP (90 and 98, respectively) in the instructions at fb220f20 and fb220f38, respectively. Getting these values is then easy:

kd> dd 80075bd0+90 l1    /* pTsdu from register t0 */
80075c60  808494dc
kd> dd 80075bd0+98 l1    /* ppIrp from register t1 */
80075c68  80075cb4

The values of the register A3 (BytesIndicated) is not explicitly stored here, but its value resides in S1 as well as A3. You can get its values by looking ahead at the disassembly of the function netbt!Inbound:

kd> u netbt!Inbound
netbt!Inbound:
fb22a480: 23deff80 lda     sp,-80(sp)
fb22a484: b53e0018 stq     s0,18(sp)
fb22a488: b55e0020 stq     s1,20(sp)

Note that the value of the S1 register is stored almost immediately relative to the SP register (the stack pointer) for this function. Thus, by using this stack pointer (indicated in the stack backtrace) you can determine what the value of the S1 register (and indirectly the A3 register) was at the time of the call:

kd> dd 80075b50+20 l1    /*  BytesIndicated from a3 register */
80075b70  00000048

At this point you have determined the values of ReceiveEventContext, BytesIndicated, BytesAvailable, BytesTaken, pTsdu, ppIrp. All that remains are the values of ConnectionContext and ReceiveFlags to complete the parameters passed to TdiReceiveHandler. The values of these parameters were in the registers A1 and A2 respectively at the time of the function call. If you delve further into TdiReceiveHandler itself, you find the following:

kd> u netbt!TdiReceiveHandler l 15
netbt!TdiReceiveHandler:
fb220800: 23deff70 lda     sp,-90(sp)
fb220804: b53e0010 stq     s0,10(sp)
fb220808: b55e0018 stq     s1,18(sp)
fb22080c: b57e0020 stq     s2,20(sp)
fb220810: b59e0028 stq     s3,28(sp)
fb220814: b5be0030 stq     s4,30(sp)
fb220818: b5de0038 stq     s5,38(sp)
fb22081c: b5fe0040 stq     fp,40(sp)
fb220820: b75e0048 stq     ra,48(sp)
fb220824: 47f3040a bis     zero,a3,s1
fb220828: b21e0070 stl     a0,70(sp)

fb22082c: 47f4040b bis     zero,a4,s2
fb220830: a27e0098 ldl     a3,98(sp)
fb220834: 43f10014 addl    zero,a1,a4
fb220838: 47f5040c bis     zero,a5,s3
fb22083c: 22b4000c lda     a5,c(a4)
fb220840: b3f30000 stl     zero,0(a3)
fb220844: b23e0074 stl     a1,74(sp)
fb220848: b2be0078 stl     a5,78(sp)
fb22084c: 223e0060 lda     a1,60(sp)
fb220850: b65e0080 stq     a2,80(sp)

The instructions at fb220844 and fb220850 store the registers A1 and A2 to location relative to SP before these registers are changed. It is important to note that if some sort of operation had been performed on these registers that would cause their value to be changed, the value at the given memory location would be invalid for the sought parameter. Parameters can be easily misinterpreted and results incorrectly analyzed due to an overlooked instruction which alters the value of the register prior to its storage in memory. In this case, the value for ConnectionContext and ReceiveFlags turns out to be:

kd> dd 80075bd0+74 l1    /*  ConnectionContext from register a1  */
80075c44  8087a948
kd> dd 80075bd0+80 l1    /*  ReceiveFlags from register a2  */
80075c50  00000e20

To summarize, your analysis of the situation would be as follows: the function TdiReceiveHandler was called with the following parameters:

ReceiveEventContext = 80844040
ConnectionContext   = 8087a948
ReceiveFlags        = 00000e20
BytesAvailble       = 00000048
BytesIndicated      = 00000048

BytesTaken          = 00000048
pTsdu               = 808494dc
ppIrp               = 80075cb4

A quick way to spot check the results achieved is to determine what kind of variable each parameter should be and see if the results look possible. For instance, does ReceiveEventContext look like a pointer as the function prototype indicates (it does) and do BytesIndicated and BytesTaken look like a count of bytes (they do).

In practical usage, it is almost never necessary to find the values of all parameters passed to a function as was illustrated here. In the case of a failure, only one or two of the parameters are genuinely useful in the effort of determining the cause (but will undoubtedly, according to Murphy's Law, be the hardest to track). Other methods of determining parameter values are possible (such as reversing operations performed on a register by hand or hand walking lists) but are beyond the scope of this document. With a little imagination and some patience there is almost no parameter whose value cannot be determined.


Annotated Alpha 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 a0 through a5. Remember that for C++ functions, the first parameter is the secret "this" pointer. Therefore, on entry to CUserView::CloseView, the registers are:

a0 = this
ra = return address

Note Parameters are passed in a0 through a5. The ra contains the function return address.

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

sample!CUserView__CloseView:

The following instruction illustrates one of the problems of the Alpha register naming convention: The registers a0 through a5 look like valid hexadecimal values.

    if (m_fDestroyed)
6774f940 : a05000a0 ldl    t1,a0(a0)        ; t1 = a0->m_fDestroyed

Note The ldl r,B expression means "load LONG (int32) into register r from location B." The n(r)expression means "the memory n bytes after the address pointed to by register r." Registers v0 and t0 through t12 are scratch registers.

Interleave the initial instruction with some standard function entry manipulations.

  • Reserve 0x30 bytes of stack space.
  • Save registers that need to be preserved (the s registers).
  • Save the return address.

Every function entry looks like this. It's required by the Win32® calling convention in order to support structured exception handling.

Registers s0 through s5 must be preserved by the function.

Notice that these are saved as quads (stq); that's just part of the rules for Alpha. You must preserve the full 64-bits of all callee-save registers.

6774f944 : 23deffd0 lda    sp,-30(sp)       ; sp -= 0x30
6774f948 : b53e0000 stq    s0,0(sp)         ; sp[0] = s0
6774f94c : b55e0008 stq    s1,8(sp)         ; sp[8] = s1
6774f950 : b57e0010 stq    s2,10(sp)        ; sp[10] = s2
6774f954 : b75e0018 stq    ra,18(sp)        ; sp[18] = ra

lda r,n(B) means "r = n + B".

lda is the Alpha version of the Intel lea instruction.

stq r,B means "store QUAD (int64) from register r to location B."

Since you will be calling ReleaseAndNull a lot, you should cache a pointer to it in s1. Unfortunately, the compiler will notcache the actual value; you'll see that you keep loading ReleaseAndNull from memory over and over.

6774f958 : 255f6767 ldah   s1,6767(zero)    ; s1 = 0x67670000
6774f95c : 214a25b4 lda    s1,25b4(s1)      ; s1 = 0x676725b4
                                            ; s1 = &__imp__ReleaseAndNull

Zero is a register whose value is always zero. ldah A,n(B) means "A = B + n * 65536".

The only time you see ldah is when the compiler wants to load up a 32-bit value. There is no "load 32-bit immediate" on the Alpha; you have to load it 16 bits at a time.

Therefore, when you see an ldah, the B register is usually zero, because you're just loading the high word of an address. The low word either gets added explicily through an upcoming lda (as in this case), or the half-finished register is indirected through to get at some global variable (as you'll see later in this section).

You can now save your "this" pointer into a non-volatile register (s0) because it is important.

6774f960 : 47f00409 bis    zero,a0,s0       ; s0 = a0 = this

Bis A,B,C means "C = A | B" ("bit sum" or "bit set"). Bis zero,A,B is an idiom for "B = A". Op A,B,C generally means "C = A op B".

Precompute &this->m_pdtgt because it's the argument to the upcoming call to ReleaseAndNull.

6774f964 : 221000b4 lda    a0,b4(a0)        ; a0 = &a0->m_pdtgt

Meanwhile, see how m_fDestroyed is doing. Remember that you loaded this->m_fDestroyed into t1.

    if (m_fDestroyed) return S_OK;
6774f968 : f4400092 bne    t1,6774fbb4  Return_S_OK

Bne r, addr means "branch if r != 0".

Other popular branch conditions are eq (equal to zero) and gt (greater than zero). Same as Intel.

The execution of the next two lines is interleaved.

    BOOL fViewObjectChanged = FALSE;
    ReleaseAndNull(&m_pdtgt);

The difficulty here is that you are calling ReleaseAndNull yet the function name appears nowhere. This is characteristic of the Alpha processor. You load ReleaseAndNull and call indirect through it. Remember that s1 = &__imp__ReleaseAndNull.

6774f96c : a00a0000 ldl    v0,0(s1)         ; v0 = ReleaseAndNull
6774f970 : b3fe0024 stl    zero,24(sp)      ; fViewObjectChanged = 0

Recall that you already set up a0 = &this->m_pdtgt, so the parameters are all set.

6774f974 : 6b404000 jsr    ra,(v0),0        ; call v0

Jsr ra,(r) means "call the function whose address is in register r."

    if (m_psv) {
6774f978 : a0290070 ldl    t0,70(s0)        ; t0 = this->m_psv
6774f97c : 47ff0411 bis    zero,zero,a1     ; a1 = FALSE (anticipatory)

Notice that bis zero,zero,r is a handy way to zero a register.

6774f980 : e4200073 beq    t0,6774fb50   No_Psv
        m_psb->EnableModelessSB(FALSE);

Remember that s0 = "this" and that a1 = FALSE from above, so all that's left to set up are a0 and the method address.

6774f984 : a2090034 ldl    a0,34(s0)        ; a0 = this->m_psb
6774f988 : a0500000 ldl    t1,0(a0)         ; t1 = m_psb->lpVtbl
6774f98c : a0020024 ldl    v0,24(t1)        ; v0 = lpVtbl->EnableModelessSB
6774f990 : 6b404000 jsr    ra,(v0),0        ; call EnableModelessSB

The above pattern is a telltale sign of a COM method call.

COM method calls are widely used, so you should 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, Release = 8.

        if(m_pws) m_pws->ViewReleased();
6774f994 : a2090108 ldl    a0,108(s0)       ; a0 = this->m_pws
6774f998 : e6000003 beq    a0,6774f9a8 NoWS ; Skip if NULL

6774f99c : a0300000 ldl    t0,0(a0)         ; t0 = m_pws->lpVtbl
6774f9a0 : a001000c ldl    v0,c(t0)         ; v0 = lpVtbl->ViewReleased
6774f9a4 : 6b404000 jsr    ra,(v0),0        ; call ViewReleased

NoWS:

Notice that you went quite a ways without seeing any new instructions. Believe it or not, you've already learned most of the Alpha instruction set by now.

        HWND hwndCapture = GetCapture();

Again, you are calling an imported function without ever mentioning its name. This time, you have to use __imp__GetCapture, which happens to be at address 0x67672b60.

6774f9a8 : 241f6767 ldah   v0,6767(zero)    ; v0 = 0x67670000
6774f9ac : a0002b60 ldl    v0,2b60(v0)      ; v0 = dword ptr [v0+0x2b60]
6774f9b0 : 6b404000 jsr    ra,(v0),0        ; call GetCapture

This is the other case where you'll see an ldah: when the half-finished register is indirected through in the ldl, you end up loading the DWORD at location 0x676726B0.

ldah followed by ldl usually means the loading of a global variable. ldah followed by ldl and then jsr usually means the calling of an imported function.

This last trick is particularly useful when you're investigating a crashed machine. Look for the ldah / ldl / jsr, dump the DWORD that the code is trying to call, then IN that DWORD. 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);
        }
6774f9b4 : e4000009 beq    v0,6774f9dc No_Capture ; returned NULL

The function return value is placed in the v0 register.

6774f9b8 : a2090040 ldl    a0,40(s0)        ; a0 = this->m_hwnd

Anticipate the need to call SendMessage by setting up all the parameters.

Bis zero, #1f, a1 is an idiom for "a1 = 0x1F"; literally, it means "a1 = 0 | 0x1f".

6774f9bc : 245f6767 ldah   t1,6767(zero)    ; t1 = 0x67670000
6774f9c0 : 47e3f411 bis    zero,#1f,a1      ; a1 = 0x1F = WM_CANCELMODE
6774f9c4 : 47ff0412 bis    zero,zero,a2     ; a2 = 0
6774f9c8 : 47ff0413 bis    zero,zero,a3     ; a3 = 0
6774f9cc : 401005a0 cmpeq  v0,a0,v0         ; v0 = (a0 == v0)

Cmpeq A,B,C compares A == B and sets C = 1 if the previous expression is TRUE.

There are analogous instructions like cmpne and cmpgt.

6774f9d0 : e4000002 beq    v0,6774f9dc No_Capture ; different; skip
6774f9d4 : a0022b80 ldl    v0,2b80(t1)      ; v0 = __imp__SendMessage
6774f9d8 : 6b404000 jsr    ra,(v0),0        ; call SendMessage

No_Capture:

Notice how the ldah / ldl / jsr combo to call an imported function has been interleaved with other computations. Stay alert!

Now you get to see how difficult it is to clear and set bitfields on Alpha. Bitfields m_fHandsOff and m_fRecursing correspond to the values 0x00000001 and 0x00008000 (respectively) and are stored at offset 0x0100, which will be called "bitmask1" for expository purposes.

Notice that there is no way to load the value 0x00008001 into a register all at one go; it needs to be broken up into two parts.

The compiler has also interleaved the preparations for the call to NotifyClients, so keep alert.

        m_fHandsOff = TRUE;
        m_fRecursing = TRUE;
        NotifyClients(m_psv, NOTIFY_CLOSING);
6774f9dc : a0290100 ldl    t0,100(s0)       ; t0 = this->bitmask1
6774f9e0 : 245f0001 ldah   t1,1(zero)       ; t1 = 0x00010000
6774f9e4 : 22090020 lda    a0,20(s0)        ; a0 = (CNotifySource*)this
6774f9e8 : 20428001 lda    t1,-7fff(t1)     ; t1 = t1 - 0x7FFF
                                            ; i.e., t1 = 0x00008001
6774f9ec : 47e09412 bis    zero,#4,a2       ; a2 = 4 = NOTIFY_CLOSING
6774f9f0 : 44220401 bis    t0,t1,t0         ; t1 = t1 | t0
6774f9f4 : b0290100 stl    t0,100(s0)       ; this->bitmask = t0
                                            ; m_fRecursing = TRUE

6774f9f8 : a0890020 ldl    t3,20(s0)        ; t3 = (CNotifySource*)this.vtbl
6774f9fc : a004000c ldl    v0,c(t3)         ; v0 = lpVtbl->NotifyClients
6774fa00 : a2290070 ldl    a1,70(s0)        ; a1 = this->m_psv
6774fa04 : 6b404000 jsr    ra,(v0),0        ; call NotifyClients

Notice how complicated it is to clear a bit on an Alpha.

        m_fRecursing = FALSE;
6774fa08 : a0290100 ldl    t0,100(s0)       ; t0 = this->bitmask1
6774fa0c : 245fffff ldah   t1,-1(zero)      ; t1 = 0xFFFF0000
6774fa10 : 20427fff lda    t1,7fff(t1)      ; t1 = t1 + 0x00007FFF
                                            ; i.e., t1 = 0xFFFF7FFF
6774fa14 : 47ff0411 bis    zero,zero,a1     ; a1 = 0 = SVUIA_DEACTIVATE
6774fa18 : 44220001 and    t0,t1,t0         ; t0 = t0 & t1
6774fa1c : b0290100 stl    t0,100(s0)       ; this->bitmask1 = t0
        m_psv->UIActivate(SVUIA_DEACTIVATE);
6774fa20 : a2090070 ldl    a0,70(s0)        ; a0 = this->m_psv
6774fa24 : a0700000 ldl    t2,0(a0)         ; t2 = a0->lpVtbl
6774fa28 : a003001c ldl    v0,1c(t2)        ; v0 = t2->UIActivate
6774fa2c : 6b404000 jsr    ra,(v0),0        ; call UIActivate
        psv = m_psv;
6774fa30 : a1690070 ldl    s2,70(s0)        ; s2 = this->m_psv
        m_psv = NULL;
        ReleaseAndNull(&_pctView);
6774fa34 : 22090068 lda    a0,68(s0)        ; a0 = &his->_pctView
6774fa38 : b3e90070 stl    zero,70(s0)      ; this->m_psv = 0
6774fa3c : a00a0000 ldl    v0,0(s1)         ; v0 = ReleaseAndNull
6774fa40 : 6b404000 jsr    ra,(v0),0        ; call v0
        if (m_pvo) {
6774fa44 : a209009c ldl    a0,9c(s0)        ; a0 = this->m_pvo
6774fa48 : 47ff0411 bis    zero,zero,a1     ; a1 = NULL
6774fa4c : 47ff0412 bis    zero,zero,a2     ; a2 = NULL
6774fa50 : 227e0020 lda    a3,20(sp)        ; a3 = &pSink
6774fa54 : e600001b beq    a0,6774fac4 No_Pvo
            if (SUCCEEDED(m_pvo->GetAdvise(NULL, NULL, &pSink)) && pSink) {
6774fa58 : a0300000 ldl    t0,0(a0)         ; t0 = m_pvo->lpVtbl
6774fa5c : a0010020 ldl    v0,20(t0)        ; v0 = lpVtbl->GetAdvise
6774fa60 : 6b404000 jsr    ra,(v0),0        ; call GetAdvise
6774fa64 : e8000012 blt    v0,6774fab0 No_Advise ; if v0 < 0, goto No_Advise

6774fa68 : a03e0020 ldl    t0,20(sp)        ; t0 = pSink
6774fa6c : 20690014 lda    t2,14(s0)        ; t2 = (IAdviseSink *)this
6774fa70 : e420000f beq    t0,6774fab0 No_Advise ; if t0 == 0, goto No_Advise
                if (pSink == (IAdviseSink *)this)

These next two 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 ViewState.

6774fa74 : 2049ffec lda    t1,-14(s0)       ; t1 = -(IAdviseSink*)this
6774fa78 : 445f0483 cmoveq t1,zero,t2       ; if t1 == 0 then t2 = 0

Cmoveq A,B,C means "if A == 0, then C = B".

You can guess what cmovne and cmovgt mean, knowing that cmov means "conditional move."

Anticipate the upcoming call to SetAdvise(). Remember that t0 = pSink.

6774fa7c : 47ff0411 bis    zero,zero,a1     ; a1 = 0
6774fa80 : 47ff0412 bis    zero,zero,a2     ; a2 = 0
6774fa84 : 47ff0413 bis    zero,zero,a3     ; a3 = NULL
6774fa88 : 402305a1 cmpeq  t0,t2,t0         ; t0 = (t0 == t2)
6774fa8c : e4200004 beq    t0,6774faa0 No_SetAdvise ; if t0 == 0, goto No_SetAdvise
                    m_pvo->SetAdvise(0, 0, NULL);
6774fa90 : a209009c ldl    a0,9c(s0)        ; a0 = this->m_pvo
6774fa94 : a0d00000 ldl    t5,0(a0)         ; t5 = m_pvo->lpVtbl
6774fa98 : a006001c ldl    v0,1c(t5)        ; v0 = lpVtbl->SetAdvise
6774fa9c : 6b404000 jsr    ra,(v0),0        ; call SetAdvise

No_SetAdvise:
                pSink->Release();
6774faa0 : a21e0020 ldl    a0,20(sp)        ; a0 = pSink
6774faa4 : a0300000 ldl    t0,0(a0)         ; t0 = pSink->lpVtbl
6774faa8 : a0010008 ldl    v0,8(t0)         ; v0 = lpVtbl->Release
6774faac : 6b404000 jsr    ra,(v0),0        ; call Release

No_Advise:

All these COM method calls should look familiar.

            fViewObjectChanged = TRUE;
6774fab0 : a00a0000 ldl    v0,0(s1)         ; v0 = ReleaseAndNull
6774fab4 : 47e03401 bis    zero,#1,t0       ; t0 = TRUE
6774fab8 : b03e0024 stl    t0,24(sp)        ; fViewObjectChanged = t0
            ReleaseAndNull(&m_pvo);
6774fabc : 2209009c lda    a0,9c(s0)        ; a0 = &his->m_pvo
6774fac0 : 6b404000 jsr    ra,(v0),0        ; call ReleaseAndNull

No_Pvo:
        if (psv) {
6774fac4 : e5600011 beq    s2,6774fb0c No_Psv   ; if s2 == 0, jump
            psv->SaveViewState();
6774fac8 : a02b0000 ldl    t0,0(s2)         ; t0 = psv->lpVtbl
6774facc : 47eb0410 bis    zero,s2,a0       ; a0 = psv
6774fad0 : a0010034 ldl    v0,34(t0)        ; v0 = lpVtbl->SaveViewState
6774fad4 : 6b404000 jsr    ra,(v0),0        ; call SaveViewState

            psv->DestroyViewWindow();
6774fad8 : a00b0000 ldl    v0,0(s2)         ; v0 = psv->lpVtbl
6774fadc : 47eb0410 bis    zero,s2,a0       ; a0 = psv
6774fae0 : a0000028 ldl    v0,28(v0)        ; v0 = lpVtbl->DestroyViewWindow
6774fae4 : 6b404000 jsr    ra,(v0),0        ; call DestroyViewWindow
            psv->Release();

Is this a compiler bug? All of a sudden, the compiler determines that psv is unaligned.

You don't need to understand the next six instructions; consider them the magic glue to do an unaligned DWORD fetch. This is an example of the dangers of not keeping your data aligned. The aligned version is just ldl v0,0(s2).

6774fae8 : 2c4b0003 ldq_u  t1,3(s2)         ; magic unaligned fetch
6774faec : 2c2b0000 ldq_u  t0,0(s2)         ;
6774faf0 : 47eb0410 bis    zero,s2,a0       ;
6774faf4 : 482b04c1 extll  t0,s2,t0         ;
6774faf8 : 484b0d42 extlh  t1,s2,t1         ;
6774fafc : 44220400 bis    t0,t1,v0         ;
6774fb00 : 43e00000 addl   zero,v0,v0       ; Sign extend LODWORD(v0) to 64 bits
                                            ; End result: v0 = s3->lpVtbl

Now the compiler returns to more standard behavior:

6774fb04 : a0000008 ldl    v0,8(v0)         ; v0 = lpVtbl->Release
6774fb08 : 6b404000 jsr    ra,(v0),0        ; call Release

No_Psv:
        m_hwndView = NULL;
6774fb0c : b3e90078 stl    zero,78(s0)      ; this->m_hwndView = NULL
        m_fHandsOff = FALSE;
6774fb10 : a0090100 ldl    v0,100(s0)       ; v0 = &this->bitmask1
6774fb14 : 243f6767 ldah   t0,6767(zero)    ; t0 = 0x67670000
6774fb18 : 44003100 bic    v0,#1,v0         ; v0 &= ~1
6774fb1c : b0090100 stl    v0,100(s0)       ; this->bitmask = v0

Bic A,B,C means "C = A and not B" ("bit clear").

if (m_pcache) {

6774fb20 : a209006c ldl    a0,6c(s0)        ; a0 = this->m_pcache
6774fb24 : e6000003 beq    a0,6774fb34 No_Cache ; jump if zero
            GlobalFree(m_pcache);
6774fb28 : a0012404 ldl    v0,2404(t0)      ; v0 = __imp__GlobalFree
6774fb2c : 6b404000 jsr    ra,(v0),0        ; call GlobalFree

This is a call to an imported function (the Idah, lda, jsr trick).

            m_pcache = NULL;
6774fb30 : b3e9006c stl    zero,6c(s0)      ; this->m_pcache = NULL

No_Cache:
        m_psb->EnableModelessSB(TRUE);
6774fb34 : 47e03411 bis    zero,#1,a1       ; a1 = TRUE
6774fb38 : a2090034 ldl    a0,34(s0)        ; a0 = this->m_psb
6774fb3c : a0100000 ldl    v0,0(a0)         ; v0 = m_psb->lpVtbl
6774fb40 : a0000024 ldl    v0,24(v0)        ; v0 = lpVtbl->EnableModelessSB
6774fb44 : 6b404000 jsr    ra,(v0),0        ; call EnableModelessSB
        CancelPendingActions();

In order to call CancelPendingActions(), you have to move from (ViewState*)this to (CUserView*)this.

6774fb48 : 2209ffec lda    a0,-14(s0)       ; a0 = (CUserView*)this
6774fb4c : d3400070 bsr    ra, CUserView::CancelPendingActions ; call

Bsr ra, addr means "call addr".

ReleaseAndNull(&_psf);

No_Psv:
6774fb50 : a00a0000 ldl    v0,0(s1)         ; v0 = ReleaseAndNull
6774fb54 : 22090074 lda    a0,74(s0)        ; a0 = &his->_psf
6774fb58 : 6b404000 jsr    ra,(v0),0        ; call ReleaseAndNull
    if (fViewObjectChanged)
6774fb5c : a15e0024 ldl    s1,24(sp)        ; s1 = fViewObjectChanged
6774fb60 : 2209ffec lda    a0,-14(s0)       ; a0 = (CUserView*)this
6774fb64 : 47e03411 bis    zero,#1,a1       ; a1 = DVASPECT_CONTENT
6774fb68 : e5400004 beq    s1,6774fb7c NoNotifyViewClients ; skip if FALSE
       NotifyViewClients(DVASPECT_CONTENT, -1);
6774fb6c : a049ffec ldl    t1,-14(s0)       ; t1 = ((CUserView*)this)->lpVtbl
6774fb70 : 225fffff lda    a2,-1(zero)      ; a2 = -1
6774fb74 : a0220024 ldl    t0,24(t1)        ; t0 = lpVtbl->NotifyViewClients
6774fb78 : 6b414000 jsr    ra,(t0),0        ; call NotifyViewClients

NoNotifyViewClients:
    if (m_pszTitle)
6774fb7c : a209007c ldl    a0,7c(s0)        ; a0 = this->m_pszTitle
6774fb80 : 255f6767 ldah   s1,6767(zero)    ; s1 = 0x67670000
6774fb84 : e6000003 beq    a0,6774fb94 No_Title
        LocalFree(m_pszTitle);
6774fb88 : a00a23e0 ldl    v0,23e0(s1)      ; v0 = LocalFree
6774fb8c : 6b404000 jsr    ra,(v0),0        ; call LocalFree
        m_pszTitle = NULL;
6774fb90 : b3e9007c stl    zero,7c(s0)      ; this->m_pszTitle = NULL

No_Title:
    SetRect(&m_rcBounds, 0, 0, 0, 0);

Is this another compiler bug? Register s1 already has this value.

6774fb94 : 255f6767 ldah   s1,6767(zero)    ; s1 = 0x67670000
6774fb98 : a00a2a98 ldl    v0,2a98(s1)      ; v0 = SetRect
6774fb9c : 220900f0 lda    a0,f0(s0)        ; a0 = &this->m_rcBounds
6774fba0 : 47ff0411 bis    zero,zero,a1     ; a1 = 0
6774fba4 : 47ff0412 bis    zero,zero,a2     ; a2 = 0
6774fba8 : 47ff0413 bis    zero,zero,a3     ; a3 = 0
6774fbac : 47ff0414 bis    zero,zero,a4     ; a4 = 0
6774fbb0 : 6b404000 jsr    ra,(v0),0        ; call SetRect
    return S_OK;
Return_S_OK:

Now unwind your stack frame.

6774fbb4 : a75e0018 ldq    ra,18(sp)        ; restore return address
6774fbb8 : a53e0000 ldq    s0,0(sp)         ; restore non-volatile register
6774fbbc : a55e0008 ldq    s1,8(sp)         ; restore non-volatile register
6774fbc0 : a57e0010 ldq    s2,10(sp)        ; restore non-volatile register
6774fbc4 : 47ff0400 bis    zero,zero,v0     ; v0 = S_OK
6774fbc8 : 23de0030 lda    sp,30(sp)        ; restore stack frame
6774fbcc : 6bfa8001 ret    zero,(ra),1      ; return


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 is just like the Alpha bic instruction: It 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.


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.

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

Displays the PCI configuration space for a device. (In this example, the SCSI controller — bus 1, device 9, function 0.)

Example

kd> !dcs 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

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

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.

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.

Example

kd> !drvobj serial

Driver object (ff0ba630) is for:
 \Driver\Serial
Driver Extension List: (id , addr)

Device Object list:
ffba3040  ff0b4040  ff0b59e0  ff0b5040

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.

Examples

Display 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

Display the devices for the secondary bus (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

!pcitree

Displays information on PCI device objects, including child PCI buses and CardBus buses, as well as the devices attached to them.


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 (d00-ffff 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 D000-DFFFF 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 3ec-3ef is owned by ff0d0b50, 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 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\CurrentControlSet\Control\SessionManager in seconds.


Resource Timeouts

During a resource timeouts, 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, 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 Dual-Boot Machines

How should you respond when the alternate operating system doesn't start on a dual-boot machine?

Check that the boot.ini points to the correct path for the other operating system. Also check that boosect.ini (unhide with attrib -r -s -h boosect.ini) which contains the boot record for the other operating system exists. Here is a sample boot.ini:

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT35
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINNT35="Windows NT Workstation Version 4.00"
multi(0)disk(0)rdisk(0)partition(1)\WINNT35="Windows NT Workstation Version 4.00 [VGA mode]" /basevideo /sos
c:\="MS-DOS"

Things are somewhat different on an Alpha machine. You will need to navigate through a series of menus that the BOIS will present when the machine starts in order add/delete/modify boot entries that the BIOS stores. These entries correspond to entries in boot.ini that you see on x86 machine.

Getting to each of these options is usually straightforward, but differs from machine to machine.

Once you get to the point where you are going to modify boot entries, you will have four fields you need to know about.

  1. The first one is usually Boot Name. This is the name of the entry that will appear on the startup screen when you are offered boot selections.
  2. The next one is Boot File. This entry points to a file called osloader.exe. This file must reside on a File Allocation Table (FAT) partition, and its purpose is to load the operating system and boot. For example:
    Disk 0, Partition 2        \os\winnt\osloader.exe
  3. Then there is OS Path, the pointer to where the operating system is. For example:
    Disk 0, Partition 1        \winnt
  4. Last is OS Options. These are exactly the same as the /options in boot.ini.


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

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 -g

The -d option passes control to the kernel debugger, and 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; this will allow you to set any initial breakpoints.)

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 NT®/Windows® 2000 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 just-in-time (JIT) debugging feature of Windows NT.

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 JIT Debugging

Use the following steps to debug a service using the JIT 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 Software Development Kit (SDK) documentation.)
  2. Install WinDbg as the JIT debugger.
  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 2000® 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.


Reference

This reference chapter includes:

Command-Line Options

Environment Variables

Debugger Commands

Debugger Extension Commands

Routines Called From Debugger Extensions

WinDbg Graphical Interface Features

Bug Check Codes


Command-Line Options

This reference section includes:

CDB Command-Line Options

KD Command-Line Options

WinDbg Command-Line Options

Dr. Watson Command-Line Options

SymStore Command-Line Options


CDB Command-Line Options

The CDB command line uses the following syntax:

cdb  [ -server ServerOptions | -remote ClientOptions ]
[ -premote SmartClientOptions ]
[-?] [-2] [-d] [-g] [-G] [-hd] [-lines] [-myob]
[-n] [-o] [-robp] [-s] [-v] [-w] [-c "command"]
[-r BreakErrorLevel]  [-t PrintErrorLevel]
[ -x{e|d|n|i} event ] [-x] [-clines lines]
[-i ImagePath]  [-y SymbolPath] [-srcpath SourcePath]
[-aDllName] [-failinc] [-noio] [-ses] [-sicv] [-snul]
[-e event] [-pd] [-pe] [-pt Seconds] [-pv]
[ -- | -p pid  | -pn name | -z DumpFile | executable ]

cdb -QR Server

cdb -wake pid

The NTSD command-line syntax is identical to that of CDB:

ntsd  [ -server ServerOptions | -remote ClientOptions ]
[ -premote SmartClientOptions ]
[-?] [-2] [-d] [-g] [-G] [-hd] [-lines] [-myob]
[-n] [-o] [-robp] [-s] [-v] [-w] [-c "command"]
[-r BreakErrorLevel]  [-t PrintErrorLevel]
[ -x{e|d|n|i} event ] [-x] [-clines lines]
[-i ImagePath]  [-y SymbolPath] [-srcpath SourcePath]
[-aDllName] [-failinc] [-noio] [-ses] [-sicv] [-snul]
[-e event] [-pd] [-pe] [-pt Seconds] [-pv]
[ -- | -p pid  | -pn name | -z DumpFile | executable ]

ntsd -QR Server

ntsd -wake pid

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]

The following table describes the CDB and NTSD command-line options. 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; thus 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.

Option | Action
-server | Creates a Debugging Server that can be accessed by other debuggers. For an explanation of the possible ServerOptions, see Activating the Debugging Server.
-remote | 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 | Creates a Smart Client, and connects to a process server that is already running. For an explanation of the possible SmartClientOptions, see Activating the Smart Client.
-? | Displays a command-line help text.
-a DllName | 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.
-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. See Controlling the User-Mode Debugger from the Kernel Debugger for details. (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.
-e event | Signals the debugger that the specified event has occurred. This option is only used when starting the debugger programmatically.
-failinc | Causes the debugger to ignore any questionable symbols. When debugging a user-mode minidump or a kernel-mode minidump, 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 Setting Symbol Options.
-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 only) Specifies that the debug heap should not be used. See Behavior of Spawned Processes for details.
-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 Setting Symbol Options.
-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 Setting Symbol Options.
-noio | (Debugging Server only) Specifies that the Debugging Server shall only perform its input and output remotely. For more details, see Activating the Debugging Server.
-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).
-pd | (Windows XP only) Specifies that the target application will not be terminated at the end of the debugging session. See Ending the Debugging Session for details.
-pe | (Windows XP only) Specifies that the target application is already being debugged. See Re-attaching to the Target Application for details.
-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).
-r BreakErrorLevel | Specifies the error level to break on. See the error level information following this table.
-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, see Setting Symbol Options.
-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 Setting Symbol Options.
-sfce | Causes the debugger to suppress File access error dialog boxes during symbol load. For details and for other methods of controlling this, see Setting Symbol Options.
-sicv | Causes the symbol handler to ignore the CV record. For details and for other methods of controlling this, see Setting Symbol Options.
-snul | Disables automatic symbol loading for unqualified names. For details and for other methods of controlling this, see Setting Symbol Options.
-t PrintErrorLevel | Specifies the error level to display. See the error level information following this table.
-v | Enables verbose output from the debugger.
-w | Specifies to debug 16-bit applications in a separate VDM.
-x{e|d|n|i} event | Controls the debugger's behavior when the specified event occurs. The event 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.
-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.
-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.
-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.
-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.
-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).
-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).
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).
-z DumpFile | Specifies the name of a crash dump file to debug. If the path and filename contain spaces, this must be surrounded by quotation marks. For details, see Analyzing a User-Mode Dump File with CDB.
-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.
-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 be the only parameter used. This command will not actually start CDB.
-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 be the only parameter used. This command will not actually start CDB.

When you are starting the debugger from the MS-DOS® Command Prompt, specify arguments for the target application after the application's filename. For instance:

cdb myexe arg1 arg2

The -r and -t Options

The -r and -t options are followed by an error level. This is a decimal number equal to 0, 1, 2, or 3. It is only functional in checked builds of Microsoft® Windows® 2000. Possible values are as follows:

Value | Constant | Meaning
0 | NONE | Does not report any errors.
1 | ERROR | Act on ERROR level debugging events.
2 | MINORERROR | Act on MINORERROR and ERROR level debugging events.
3 | WARNING | Act on WARNING, MINORERROR, and ERROR level debugging events.

The default value is 1.


KD Command-Line Options

The KD command line uses the following syntax.

kd [ -server ServerOptions | -remote ClientOptions ]
[-?] [-b | -x] [-d] [-m] [-myob] [-lines] [-n] [-r] [-s]
[-v] [-clines lines] [-failinc] [-noio]
[-ses] [-sfce] [-sicv] [-snul] [-aDllName]
[-i ImagePath] [-y SymbolPath]  [-srcpath SourcePath]
[-k[x] ConnectType | -kl] [-z DumpFile] [-c "command"]

kd -QR Server

kd -wake pid

The following table describes the KD command-line options. 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; thus 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.

Option | Action
-server | Creates a Debugging Server that can be accessed by other debuggers. For an explanation of the possible ServerOptions, see Activating the Debugging Server.
-remote | 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.
-? | Displays a command-line help text.
-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.
-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.
-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.)
-k[x] ConnectType | Tells the debugger how to connect to the target. If the x is included, this indicates that the debugger is connecting to an eXDI driver. The connection can use a modem, a COM port, or a 1394 channel. See the following table for the syntax used to specify each connection type.
-kl | (Windows XP only) Starts a kernel debugging session on the same machine as the debugger. For more details, see Attaching to a Target Computer (Kernel Mode).
-a DllName | Sets the default extension DLL. The default is kdextx86.dll or kdextalp.dll. 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.
-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.
-failinc | Causes the debugger to ignore any questionable symbols. When debugging a user-mode minidump or a kernel-mode minidump, 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 Setting Symbol Options.
-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 Setting Symbol Options.
-m | Serial port is a modem; watch for carrier detect
-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 Setting Symbol Options.
-noio | (Debugging Server only) Specifies that the Debugging Server will only perform its input and output remotely. For more details, see Activating the Debugging Server.
-r | Displays registers.
-s | Disables lazy symbol loading. This will slow down process startup. For details and for other methods of controlling this, see Setting Symbol Options.
-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 Setting Symbol Options.
-sfce | Causes the debugger to suppress file access error dialog boxes during symbol load. For details and for other methods of controlling this, see Setting Symbol Options.
-sicv | Causes the symbol handler to ignore the CV record. For details and for other methods of controlling this, see Setting Symbol Options.
-snul | Disables automatic symbol loading for unqualified names. For details and for other methods of controlling this, see Setting Symbol Options.
-v | Generates verbose messages for loads, deferred loads, and unloads.
-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.
-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.
-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.
-z DumpFile | Specifies the name of a crash dump file to debug. If the path and filename contain spaces, this must be surrounded by quote marks. For details, see Analyzing a Kernel-Mode Dump File with KD.
-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.
-QR Server | Lists all Debugging Servers running on the specified network server. The two backslashes (\\) preceding Server are optional. See Searching for Debugging Servers for details. The -QR parameter must be the only parameter used. this command will not actually start KD.
-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 be the only parameter used. This command will not actually start KD.

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 names I386KD, AlphaKD, and IA64KD) is obsolete.

The -k Option

The following connection types can be used with the -k option:

Option | Meaning
serial:modem | The connection will be use a modem.
com:port=Port,baud=Rate | The connection will use a COM port. Port should be the name of the COM port. Rate should be the baud rate.
1394:channel=Channel | The connection will use 1394. Channel must match the 1394 channel used at boot.

The following are examples of the -k option:

kd -k serial:modem
kd -k com:port=com2,baud=57600
kd -k com:port=\\.\com2,baud=115200
kd -k 1394:channel=20


WinDbg Command-Line Options

The WinDbg command line uses the following syntax:

windbg [ -server ServerOptions | -remote ClientOptions ]
[ -premote SmartClientOptions ]
[-?] [-clines lines] [-b] [-d] [-e event] [-failinc]
[-g] [-G] [-hd] [-j] [-n] [-o] [-Q] [-robp]
[-ses] [-sfce] [-sicv] [-snul] [-T Title] [-v]
[-i ImagePath] [-y SymbolPath] [-srcpath SourcePath]
[-k[x] [ConnectType] | -kl] [-c "command"]
[-pd] [-pe] [-pt Seconds] [-pv] [-W Workspace] [-WX]
[ -p pid | -pn name | -z DumpFile | executable ]

windbg -I

The following table describes the WinDbg command-line options. All comand-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.

Option | Action
-server | Creates a Debugging Server that can be accessed by other debuggers. For an explanation of the possible ServerOptions, see Activating the Debugging Server.
-remote | 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 | Creates a Smart Client, and connects to a process server that is already running. For an explanation of the possible SmartClientOptions, see Activating the Smart Client.
-? | Pops up this HTML Help window.
-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.
-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.
-j | Allow journaling.
-k[x] [ConnectType] | (Kernel mode only) Starts a kernel debugging session. If the x is included, this indicates that the debugger is connecting to an eXDI driver. The optional ConnectType information tells the debugger how to connect to the target. The connection can use a modem, a COM port, or a 1394 channel. See the following table for the syntax used to specify each connection type.
-kl | (Windows XP 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).
-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.
-failinc | Causes the debugger to ignore any questionable symbols. When debugging a user-mode minidump or a kernel-mode minidump, 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 Setting Symbol Options.
-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 only, user mode only) Specifies that the debug heap should not be used. See Behavior of Spawned Processes for details.
-n | Noisy symbol load: Enables verbose output from symbol handler. For details and for other methods of controlling this, see Setting Symbol Options.
-noio | (Debugging Server only) Specifies that the Debugging Server will perform all input and output remotely. For more details, see Activating the Debugging Server.
-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).
-pd | (Windows XP only, user mode only) Specifies that when the debugging session ends, the target application will not be terminated. See Ending the Debugging Session for details.
-pe | (Windows XP only, user mode only) Specifies that the target application is already being debugged. See Re-attaching to the Target Application for details.
-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. 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.)
-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 Setting Symbol Options.
-sfce | Causes the debugger to suppress file access error dialog boxes during symbol load. For details and for other methods of controlling this, see Setting Symbol Options.
-sicv | Causes the symbol handler to ignore the CV record. For details and for other methods of controlling this, see Setting Symbol Options.
-snul | Disables automatic symbol loading for unqualified names. For details and for other methods of controlling this, see Setting Symbol Options.
-T Title | Sets WinDbg window title.
-v | Enables verbose output from debugger.
-W Workspace | Loads the given workspace. 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.
-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.
-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.
-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.
-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.
-e event | Signals the debugger that the specified event has occurred. This option is only used when starting the debugger programmatically.
-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).
-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).
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).
-z DumpFile | Specifies the name of a crash dump file to debug. If the path and filename contain spaces, this must be surrounded by quotation marks. For details, see Analyzing a User-Mode Dump File with WinDbg or Analyzing a Kernel-Mode Dump File with WinDbg.
-I | Install WinDbg as the Just-in-Time Debugger. The -I parameter must be the only parameter used. This command will not actually start WinDbg.

When you are running the debugger from the command line, specify arguments for the target application after application's filename. For instance:

windbg myexe arg1 arg2

The -k Option

The following connection types can be used with the -k option:

Option | Meaning
serial:modem | The connection will be use a modem.
com:port=Port,baud=Rate | The connection will use a COM port. Port should be the name of the COM port. Rate should be the baud rate.
1394:channel=Channel | The connection will use 1394. Channel must match the 1394 channel used at boot.

The following are examples of the -k option:

windbg -k serial:modem
windbg -k com:port=com2,baud=57600
windbg -k com:port=\\.\com2,baud=115200
windbg -k 1394:channel=20

For other methods of specifying a kernel debugging connection, see Attaching to a Target Computer (Kernel Mode).


Dr. Watson Command-Line Options

The Dr. Watson command line uses the following syntax:

drwtsn32 [-i] [-g] [-p pid] [-e event] [-?] [/?]

Option | Description
-i | Install Dr. Watson as the Just-in-Time (JIT) debugger.
-g | Ignored. Provided for compatibility with WinDbg and CDB.
-p pid | Process ID to debug.
-e event | Event to signal for process attach completion.
-? | Display command-line option help.
/? | Pop up options screen.


SymStore Command-Line Options

The following syntax forms are supported for SymStore transactions. The first parameter must always be add or del, but the order of the other parameters is immaterial.

symstore add [/r] [/p] [/l] /f File /s Store /t Product [/v Version] [/c Comment]
symstore add [/r] [/p] [/l] /g Share /f File /x IndexFile [/a]
symstore add /y IndexFile /g Share /s Store [/p] /t Product [/v Version] [/c Comment]
symstore del /i ID /s Store
symstore /?

Parameter | Meaning
/f File | Network path of files or directories to add.
/g Share | 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 | Transaction ID string.
/l | Allows the file to be in a local directory rather than a network path. (This option is only used with the /p option.)
/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 | Root directory for the symbol store.
/t Product | Name of the product.
/v Version | Version of the product.
/c Comment | Comment for the transaction.
/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.


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 | The path that the debugger will first search for extension DLLs. This 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 | The path containing the binary executable files. This 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 | The path containing the source files for the target. This 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 | The root of a directory tree containing the symbol files. This 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 | An alternate symbol path searched before _NT_SYMBOL_PATH. Useful for keeping private versions of symbol files. This path can contain a drive letter followed by a colon (:). Separate multiple directories with semicolons (;). For details, see Setting Paths and Loading Files.
_NT_DEBUG_HISTORY_SIZE = number | The approximate number of commands in the command history that can be accessed during remote debugging. For details, and for other ways to change this number, see Using Debugger Commands.
_NT_DEBUG_LOG_FILE_OPEN = filename | (CDB and KD only) Name of 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) Name of 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.
_NO_DEBUG_HEAP | (Windows XP 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 = port | Name of the debug computer port through which the debugger computer and the target computer are connected. The full name should be given, not just a number (for example, _NT_DEBUG_PORT=COM2). The default is COM1. There is no command line equivalent.
_NT_DEBUG_BAUD_RATE = baud | The baud rate at which debugging will occur across the serial port. This can be 19200, 38400, 57600, or 115200. The default is 19200.
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 | Sets 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_BUS = 1394 | Specifies that debugging will be done over a 1394 cable connection.
_NT_DEBUG_1394_CHANNEL = Channel | Specifies the channel number to be used over the 1394 bus. Valid channel numbers are 1 through 62. Channel must match the number used during target computer setup, but does not depend on the physical 1394 port, chosen on the adapter.
_NT_DEBUG_OPTIONS | This has two possible 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 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 square brackets are optional: [ xxx ]. Square brackets with vertical lines indicate that any one, or none, of the enclosed parameters can be used: [ xxx | yyy ]. Curled braces with vertical lines indicate that exactly one of the enclosed parameters must be used: { xxx | yyy }.

This reference section describes the following commonly-used parameter types:

Expression Syntax

Symbol Syntax

Source Line Number Syntax

Address Syntax

Register Syntax

Process and Thread Syntax

Multiprocessor Syntax


Expression Syntax

Any command that accepts a numerical expression as a parameter will also accept a numerical expression containing various arguments and operators. Such an expression will evaluate to an 8, 16, 32, or 64-bit value.

The N (Set Number Base) command sets the default radix to 16, 10, or 8. Numerical expressions will be understood to be 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).

The ? (Evaluate Expression) command is especially useful in evaluating numerical expressions. This command displays the value of the expression in both decimal and hexadecimal format.

Hexadecimal 64-bit values may be entered in the xxxxxxxx`xxxxxxxx format, or the grave accent ( ` ) may be omitted.

An expression can combine any symbol, number, or address with any of the unary and binary operators in the tables below. All unary operators have the highest precedence. Binary operators follow fixed precedence rules.

Since symbols and source line expressions are hexadecimal numbers, they can be used in expressions as well. See Symbol Syntax and Source Line Number Syntax for details.

Unary Operators

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. Use parentheses to override this order.

For symbols with the same character sequence as reserved words (for example, register names and operators), prefix the symbol name with the module name and an exclamation point (!) to force symbol access.

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 64-bit WOW debugging, this represents pointers of the appropriate size.

Binary Operators

The binary operators are listed in the following table. Note that an illegitimate operation (such as division by zero) results in an "Operand error" being returned to the Debugger Command window.

The + and - operators have equal precedence; the three shift operators have equal precedence; the %, *, and / operators have equal precedence. In cases of equal precedence, operators associate from left to right.

In all other cases, the operators listed higher in this table take precedence over those listed lower.

Parentheses can be used to override these rules.

Operator | Meaning
* | Multiplication
/ | Integer division
mod (or %) | Modulus (remainder)
+ | Addition
- | Subtraction
<< | Left shift
>> | Logical right shift
>>> | Arithmetic right shift
and (or &) | Bitwise Boolean AND
xor (or ^) | Bitwise Boolean exclusive OR
or (or |) | Bitwise Boolean OR

The following binary comparisons are also supported. They generate 1 for true, or zero for false.

Operator | Meaning
< | Less than
> | Greater than
== (or =) | Equal to
!= | Not equal to

Examples

Comparison operators can be used to create conditional breakpoints. (See Using Breakpoints for full details.) Note the 0n prefix to force the number 20 to 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. But the debugger treats the symbol MyVar as an address, so you have to dereference it with the poi operator.

The following command prints the value of ecx if eax is greater than ebx, prints -1 if eax is less than ebx, and prints -2 if eax equals ebx. Note that the double-equal sign of C (==) is not required:

0:000> ? (eax>ebx)*ecx - (eax<ebx) + -2*(eax=ebx)


Symbol Syntax

A symbol is a name representing the address of a global variable, function, or segment. This name is interpreted as an address.

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.

However, it should be remembered that the debugger treats the symbols main and MyInt as addresses. This allows such commands as bp main+5 or dd MyInt+0x20 L1, to be understood correctly. The ? (Evaluate Expression) command can be used to determine the address value of a symbol.

Unlike C-style pointer arithmetic, numbers added to a symbol are not re-scaled in any manner. Thus MyInt+0x20 is always an offset of 32 bytes higher than the offset MyInt, regardless of the size of any data types. Expressions such as main+3*MyInt are also allowed (though of course rarely useful). See Expression Syntax for a list of all allowable operators.

Symbol Matching

A symbol consists of one or more characters, but always begins with a letter, underscore (_), question mark (?), or dollar sign ($). For some 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 DLL name. An exclamation mark (!) separates the DLL name from the symbol (for instance, mymodule!main). If no DLL name is used, the symbol can still be prefixed with an exclamation mark.

A 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. Exact match (Sym, sym, SYm).
  2. Match with leading underscore (_Sym, _sym, _SYm).
  3. If suffix-matching is on, match with trailing A or W (SymA, symA, SYmA, or SymW, symW, SYmW). Suffix matching is set with the SS (Set Suffix) command.


Source Line Number Syntax

Source file line numbers can be specified whenever an address can be used in a command. These expressions evaluate to the offset of the executable code corresponding to this source line.

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 Syntax

There are several ways to specify addresses in CDB, KD, and WinDbg.

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.

On RISC platforms only flat addressing is supported.

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.

Note that you can also use the poi unary operator to dereference any pointer. For example, if the pointer at address 00123456 points to address location 00420000, the following two commands are equivalent:

dd 00420000
dd poi(00123456)

To specify the current program counter location, you can use a period (.) instead of the entire address.

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  L 8

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  L 2

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.


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 which can control registers.

When entering a register name in a debugger command, it is best to precede it with an "at" sign (@). This signals the debugger that the following text is the name of a register.

The x86, Alpha, and IA-64 processors each have different sets of registers. The rules for register syntax also vary depending on the target processor.

On an x86, the most common register names (eax, ebx, ecx, edx, esi, edi, ebp, eip, efl) will always be understood as registers. Moreover, the R (Registers) command will always understand its argument to be a register.

In any other case, 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 it matches no known symbols, it will be interpreted as a register. So the "@" sign is needed in most instances to make sure the debugger understands that you are referring to a register.

On any processor, a single period (.) serves as a synonym for the instruction pointer ("eip" on x86, "fir" on Alpha, "iip" on IA-64.) This can be used anywhere a register is expected.

See Processor Architecture for information on the registers and instructions peculiar to each processor.

Flags on the x86

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 are stored 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.


Process and Thread Syntax

Many debugger commands have process identifiers or thread specifiers as their parameters.

In user mode, you can specify a process or thread in these commands, and you can change the current process and the current thread.

In kernel mode, processes and threads cannot be controlled in this manner. For a description of how to access process-specific and thread-specific information in kernel mode, see Changing Contexts.

Process Identifiers

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.

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, but they cannot attach to multiple unrelated processes.

Thread Identifiers

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.

Thread identifiers usually appear as command prefixes. Note that not all wildcards are available in all commands using thread identifiers.

Note The tilde (~) character is used to specify threads in CDB and in WinDbg (user-mode). In KD and WinDbg (kernel-mode) it is used to specify processors. See Multiprocessor Syntax for more information.


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 CDB and user-mode WinDbg, the tilde is used to specify threads. See Thread Identifiers for more information.

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 noncurrent processor 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.


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 | x86, IA-64, Alpha

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) character and then hit 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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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) character.

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 | x86, IA-64, Alpha

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 the expression or symbol in the context of the current thread and process.

Note that a question mark by itself (?) displays command help. The ? expression syntax evaluates the given expression.

Syntax

? expression

Parameters

expression
Expression to be evaluated with the expression evaluator. See Expression Syntax for details. The C++ expression evaluator cannot calculate expressions that use the conditional operator (?:).

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

Comments

The number is displayed in the current radix. To change the radix, use the N (Set Number Base) command.

See Also

.formats (Show Number Formats)


# (Search for Disassembly Pattern)

Searches for the specified pattern in the disassembly code.

Syntax

# [pattern] [address]

Parameters

pattern
The pattern to search for in the Disassembly window. Spaces before the pattern are ignored; spaces within the pattern are illegal. The question mark (?) wildcard matches any single character, and the asterisk (*)wildcard matches zero or more characters. 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
The address at which the search will begin. For more information, see Address Syntax. If the # command has been previously used and address is omitted, the search begins where the previous search ended.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

Comments

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.


| (Process Status)

Prints status for the specified process, or for all processes currently being debugged.

Syntax

| Process

Parameters

Process
The process to be displayed. If this is omitted, all processes being debugged are displayed. For more information, see Process and Thread Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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), or ~S (Set Current Thread) commands.

Syntax

[Process] s
| s

Parameters

Process
The process to be activated. For more information, see Process and Thread Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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 current 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 more information, see Process and Thread Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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 more information, see Process and 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 | x86, IA-64, Alpha

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, 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 more information, see Process and Thread Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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 more information, see Process and Thread Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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 more information, see Process and Thread Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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.

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 more information, see Process and Thread Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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, or the S (Search Memory) command.

Syntax

[Thread] s
~ s

Parameters

Thread
The thread to be activated. For more information, see Process and Thread Syntax.

Environment

Modes | user mode only
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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.

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, 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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 information, see Address Syntax.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

Additional Information

For an explanation of how to use aliases, see Using Aliases.


AL (List Aliases)

Displays a list of all currently-defined aliases.

Syntax

al

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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.

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 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 more information, see Process and 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. See Expression Syntax for more details.
Access
The type of access which will satisfy the breakpoint:
Option | Action
e (execute) | (x86 and IA-64 only) Breakpoint trap when the CPU fetches an instruction from the specified address.
r (read/write) | (x86 and IA-64 only) Breakpoint trap when the CPU reads or writes a byte, word, or double-word at the specified address.
w (write) | (x86 and IA-64 only) Breakpoint trap when the CPU writes a byte, word, or double-word at the specified address.
i (i/o) | (Windows XP only, kernel-mode only, x86 only) Size must be four.

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. 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.
EProcess
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
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.) For more information, see Address 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 (Program 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 | x86 and IA-64 only

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 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 is an example of the BA command. The following command sets a breakpoint for read access on four bytes of the variable var:

0:000> ba r4 &var

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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. See Expression Syntax for more details.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | x86, IA-64, Alpha

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 (Set Breakpoint)

Sets a breakpoint. You can combine locations, conditions, and options to set different kinds of breakpoints.

Syntax

User-Mode Syntax

[Thread] bp[ID] Address [Passes] ["CommandString"]
[Thread] bu[ID] Address [Passes] ["CommandString"]

Kernel-Mode Syntax

bp[ID] [/p EProcess | /t EThread] Address [Passes] ["CommandString"]
bu[ID] [/p EProcess | /t EThread] Address [Passes] ["CommandString"]

Parameters

Thread
The thread that the breakpoint will apply to. For more information, see Process and 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. See Expression Syntax for more details.
EProcess
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
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. For more information, see Address 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.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | x86, IA-64, Alpha

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.

The ID number is used to refer to the breakpoint when altering it in future actions.

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 information, see Address Ranges.
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 information, see Address Syntax.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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 information, see Address Ranges. 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 | x86, IA-64, Alpha

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 if the target computer's processor has 32-bit architecture, and equivalent to dq if the target computer's processor has 64-bit architecture. 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 information, see Address Ranges. 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 | x86, IA-64, Alpha

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 selector

Parameters

selector
Specifies the hexadecimal selector value.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64

Comments

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

The !sel extension can be used to display a complete list of all selectors. It displays a slightly different selection of information than the DG command does.

Here is an example of the two commands:

kd> !sel
0028  Bas=803cc000 Lim=000020ab Bytes DPL=0  P TSS32    B
0030  Bas=ffdff000 Lim=00000001 Pages DPL=0  P Data  RW A
0038  Bas=7ffde000 Lim=00000fff Bytes DPL=3  P Data  RW A
0040  Bas=00000400 Lim=0000ffff Bytes DPL=3  P Data  RW
0048  Bas=00000000 Lim=00000000 Bytes DPL=0 NP
0050  Bas=80162b00 Lim=00000068 Bytes DPL=0  P TSS32    A
0058  Bas=80162b68 Lim=00000068 Bytes DPL=0  P TSS32    A
0060  Bas=00022ee0 Lim=0000ffff Bytes DPL=0  P Data  RW A
0068  Bas=000b8000 Lim=00003fff Bytes DPL=0  P Data  RW
0070  Bas=ffff7000 Lim=000003ff Bytes DPL=0  P Data  RW
0078  Bas=80400000 Lim=0000ffff Bytes DPL=0  P Code  RE
0080  Bas=80400000 Lim=0000ffff Bytes DPL=0  P Data  RW
0088  Bas=00000000 Lim=00000000 Bytes DPL=0  P Data  RW
0090  Bas=00000000 Lim=00000000 Bytes DPL=0 NP
0098  Bas=00000000 Lim=00000000 Bytes DPL=0 NP
00a0  Bas=827f06e8 Lim=00000068 Bytes DPL=0  P TSS32    A

kd> !sel 38
0038  Bas=7ffde000 Lim=00000fff Bytes DPL=3  P Data  RW A

kd> dg 38
Selector   Base     Limit   Type  DPL   Size  Gran
-------- -------- -------- ------ --- ------- ----
  0038   7ffde000 00000fff  Data   3    Big   Byte


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 information, see Address 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 | x86, IA-64, Alpha

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.

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 information, see Address Syntax. If omitted, the last address used in a display command is assumed.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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 [-SearchOpts] [module!]NAME [[-SearchOpts] Field] [Address] [-l List] [-DisplayOpts]
dt Address [-l List] [-DisplayOpts]
dt -h

Kernel-Mode Syntax

[Processor] dt [-SearchOpts] [module!]NAME [[-SearchOpts] Field] [Address] [-l List] [-DisplayOpts]
dt Address [-l List] [-DisplayOpts]
dt -h

Parameters

Processor
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.
SearchOpts
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
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 (.), all subfields of this field will be displayed as well.
Address
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).
DisplayOpts
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.
-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.

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 | x86, IA-64, Alpha

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.

Here are some examples:

0:000> dt mt1                    Use DT on a global
   +0x000 a                : 10
   +0x004 b                : 98 'b'
   +0x006 c                : 0xdd
   +0x008 d                : 0xabcd
   +0x00c gn               : [6] 0x1
   +0x024 ex               : 0x0

0:000> dt mt1 -a gn              Dump the array field "gn"
   +0x00c gn :
    [00] 0x1
    [01] 0x2
    [02] 0x3
    [03] 0x4
    [04] 0x5
    [05] 0x6

0:000> dt mcl1 m_t1 dpo          Dump some subfields of a variable
   +0x010 dpo  : DEEP_ONE
   +0x070 m_t1 : MYTYPE1

0:000> dt mcl1 m_t1.             Dump subfields of a field
   +0x070 m_t1  :
      +0x000 a     : 0
      +0x004 b     : 0 ''
      +0x006 c     : 0x0
      +0x008 d     : 0x0
      +0x00c gn    : [6] 0x0
      +0x024 ex    : 0x0

0:000> dt 0x0100297c MYTYPE1     Type name at address
   +0x000 a                : 22
   +0x004 b                : 43 '+'
   +0x006 c                : 0x0
   +0x008 d                : 0x0
   +0x00c gn               : [6] 0x0
   +0x024 ex               : 0x0

0:000> dt types!l*               Enumerate the types and globals
010029b8  types!lt4
01002990  types!lt2
010029a4  types!lt3
0100297c  types!lt1

0:000> dt types!MY*
          types!MYCLASS1
          types!MYCLASS2
          types!MYCLASS3
          types!MYTYPE3::u
          types!MYTYPE1
          types!MYTYPE3
          types!MYTYPE3
          types!MYFLAGS

0:000> dt -ca10 ULONG 01002be0   Dump an array of ULONG at address
[0] 0x1001098
[1] 0x1
[2] 0xdead
[3] 0x7d0
[4] 0x1
[5] 0xcd
[6] 0x0
[7] 0x0
[8] 0x0
[9] 0x0

0:000> dt -ca4 . 01002d00        Don't have to re-type "ULONG"
Using sym ULONG
[0] 0x12
[1] 0x4ac
[2] 0xbadfeed
[3] 0x2

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"

ActiveProcessLinks.Flink at 0x81358030
---------------------------------------------
UniqueProcessId : 0x000000d0
ImageFileName : [16] "services.exe"

ActiveProcessLinks.Flink at 0x81357790
---------------------------------------------
UniqueProcessId : 0x000000dc
ImageFileName : [16] "lsass.exe"

ActiveProcessLinks.Flink at 0x81331af0
---------------------------------------------
UniqueProcessId : 0x00000188
ImageFileName : [16] "svchost.exe"

ActiveProcessLinks.Flink at 0x81327b30
---------------------------------------------
UniqueProcessId : 0x000001a8
ImageFileName : [16] "spoolsv.exe"

ActiveProcessLinks.Flink at 0x813082f0
---------------------------------------------
UniqueProcessId : 0x000001e0
ImageFileName : [16] "svchost.exe"

ActiveProcessLinks.Flink at 0x812fb950
---------------------------------------------
UniqueProcessId : 0x00000208
ImageFileName : [16] "regsvc.exe"

ActiveProcessLinks.Flink at 0x812f9d70
---------------------------------------------
UniqueProcessId : 0x00000218
ImageFileName : [16] "mstask.exe"

ActiveProcessLinks.Flink at 0x812aab50
---------------------------------------------
UniqueProcessId : 0x00000318
ImageFileName : [16] "explorer.exe"

ActiveProcessLinks.Flink at 0x81273030
---------------------------------------------
UniqueProcessId : 0x00000344
ImageFileName : [16] "cmd.exe"

ActiveProcessLinks.Flink at 0x81249d70
---------------------------------------------
UniqueProcessId : 0x000003c4
ImageFileName : [16] "cmd.exe"

ActiveProcessLinks.Flink at 0x81242950
---------------------------------------------
UniqueProcessId : 0x00000348
ImageFileName : [16] "winmgmt.exe"

ActiveProcessLinks.Flink at 0x8122c770
---------------------------------------------
UniqueProcessId : 0x0000037c
ImageFileName : [16] "crash.exe"

ActiveProcessLinks.Flink at 0x81225950
---------------------------------------------
UniqueProcessId : 0x00000308
ImageFileName : [16] "winmgmt.exe"

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 | x86, IA-64, Alpha

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, EQ, EU, EW (Enter Values)

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 | x86, IA-64, Alpha

Comments

This command exists in the following forms. The second character of the command is 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).
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).

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 information, see Address Ranges.
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. For information on specifying virtual memory ranges, see Address Ranges.
Pattern
Specifies one or more byte values with which to fill memory.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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

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 more information, see Process and 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. See Address Syntax for more details.
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. See Address Syntax for more details.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | x86, IA-64, Alpha

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 more information, see Process and 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. See Address Syntax for more details.
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. See Address Syntax for more details.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | x86, IA-64, Alpha

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 more information, see Process and 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. See Address Syntax for more details.
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. See Address Syntax for more details.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | x86, IA-64, Alpha

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 and Alpha 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. See Expression Syntax for more details.
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 | x86, IA-64, Alpha

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] [FrameCount]
[Thread] k[b|p|v][n] = BasePtr [FrameCount]
[Thread] k[b|p|v][n] = BasePtr StackPtr InstructionPtr
[Thread] kd [WordCount]

Kernel-Mode Syntax

[Processor] k[b|p|v][n] [FrameCount]
[Processor] k[b|p|v][n] = BasePtr [FrameCount]
[Processor] k[b|p|v][n] = 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 more information, see Process and 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
(x86 and IA-64 processors only) Causes the display to include the first three parameters passed to each function.
p
Causes the display to include detailed symbol information about each function called in the stack trace.
v
(x86 and IA-64 processors only) Causes the display to include FPO information.
n
Causes the display to include frame numbers.
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 | K: x86, IA-64, Alpha KB: x86, IA-64 KD: x86, IA-64, Alpha KP: x86, IA-64, Alpha KV: x86, IA-64

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, detailed information regarding each function used in the stack trace is displayed. This includes all information available through symbols, such as the parameters expected by each function. This command may be slow, and will not give full details of Windows routines which are not exposed in public symbols.

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 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 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 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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 lazy symbol loading and 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
Causes only user-mode symbol information to be displayed. Only available in kernel mode.
k
Causes only kernel-mode symbol information to be displayed. Only available in kernel mode.

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.
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 | x86, IA-64, Alpha

Comments

The LM command will list all the modules and the status of symbols for each module.

Status values include:

Status | Meaning
(pdb symbols) | The pdb symbols were found and loaded correctly.
checkmark + (pdb symbols) | The pdb symbols were loaded, but there was an error in the load (such as a time/date mismatch or a checksum error.)
(deferred) | The debugger has not attempted to load the symbols yet.

If there are modules with identical names, the debugger will append the base address of each module to that module's name. This assures that the names will be unique.


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. See Address Syntax for more details.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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. See Address Syntax for more details.
first
The first line to be displayed. Default is the current line.
count
The quantity of lines to be displayed. Default is 20 (0x14).

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 or executing.

Syntax

lsp LeadingLines TrailingLines
lsp TotalLines
lsp

Parameters

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 | x86, IA-64, Alpha

Comments

When LSP is used with no parameters, it will display the current leading line and trailing line values.

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 information, see Address Ranges.
address
The starting address of the destination memory area. See Address Syntax for more details.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

Comments

WinDbg, KD, and CDB begin with the default radix set to 16.

Most 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 and Alpha 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 (Program 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 thread(s) are thawed and all others are frozen. For more information, see Process and 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 starts execution at the specified address. Otherwise, it starts execution at the instruction pointed to by the instruction pointer. See Address Syntax for details.
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 | x86, IA-64, Alpha

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.

Here are some examples. The command ~*p steps with all threads unfrozen; ~#p steps with only the current exception thread unfrozen; and ~123p steps with thread 123 unfrozen and all others frozen. The ~p and ~.p commands both step execution with the current thread unfrozen.

Additional Information

For other methods of issuing this command and 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 | x86, IA-64, Alpha

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 | x86 and IA-64 only

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. 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, and pseudo-registers.

Syntax

User-Mode Syntax

[Thread] r[F|L|M Mask|X] [Register [= [Value]]]

Kernel-Mode Syntax

[Processor] r[F|L|M Mask|X] [Register [= [Value]]]

Parameters

Processor
Specifies the processor from which the registers are to be read. The default is zero. 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 more information, see Process and Thread Syntax. Threads can only be specified in user mode.
F
Causes the floating-point registers to be displayed. The "F" must be upper-case. This option is equivalent to M 0x4.
L
(Alpha target only) Causes registers to be displayed in 64-bit format. If the L option is omitted, the low 32 bits are displayed. These bits will be followed by a asterisk (*) unless the upper 32 bits are simply a sign extension of the low 32 bits. This option is equivalent to setting the 0x2 bit in the mask. It is ignored on non-Alpha targets.
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.
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 to display or modify. See Register Syntax for more details.
Value
Specifies the value to assign to the register. Values should be entered in the current number base, or should use radix prefixes; see the N (Set Number Base) command for details.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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

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.

On an Alpha target, it is not possible to see all floating point registers in quad-word format, but you can see them one at a time by issuing commands such as rL f0. The F is not needed if you specify the register.

The following Mask bits are supported for an x86 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.

The following Mask bits are supported for an Alpha processor. If both 0x1 and 0x2 are set, 0x2 takes precedence:

Bit | Value | Description
0 | 0x1 | Causes registers to be displayed in 32-bit format. The low 32 bits will be displayed. These bits will be followed by an asterisk (*) unless the upper 32 bits are simply a sign extension of the lower 32 bits.
1 | 0x2 | Causes registers to be displayed in 64-bit format.
2 | 0x4 | Displays the floating-point 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

The R command can also be used to create pseudo-registers. These are not true registers, but rather macros. Pseudo-registers can be used to make entering debugger commands easier. See Using Pseudo-Registers 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 | x86, IA-64, Alpha

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.

Bit 0 (0x1) and bit 1 (0x2) will show up in the Rm display on all processors, but they only have any affect on an Alpha processor. 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:

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.

The following Mask bits are supported for an Alpha processor. If both 0x1 and 0x2 are set, 0x2 takes precedence:

Bit | Value | Description
0 | 0x1 | Causes registers to be displayed in 32-bit format. The low 32 bits will be displayed. These bits will be followed by an asterisk (*) unless the upper 32 bits are simply a sign extension of the lower 32 bits.
1 | 0x2 | Causes registers to be displayed in 64-bit format.
2 | 0x4 | Displays the floating-point 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), or |S (Set Current Process) commands.

Syntax

s [-Type] Range Pattern

Parameters

Type
The memory type to search for: w for a word, d for a double-word, q for a quad-word. Type should be preceded by a hyphen. If omitted, byte values will be used.
Range
The memory area to search through. For more information, see Address Ranges.
Pattern
One or more values to search for. These are byte values, unless specified otherwise by Type.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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

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.

Here are some examples. Assuming the current radix is 16, the following command will search memory locations 0012FF40 through 0012FF5F for the pattern "ABCD":

0:000> s 0012ff40 L20 'A' 'B' 'C' 'D'

The following command has the exact same effect:

0:000> s 0012ff40 L20 41 42 43 44

These commands will locate each appearance of the pattern "ABCD", and return the address of each such pattern. (The address of the "A" is returned, not the addresses of all four characters.)

Only patterns that are completely contained in the search range are returned. Overlapping patterns are found correctly. (In other words, the pattern "AAA" will be found three times in the block "AAAAA".)

Here is an example of a search using the Type parameter. This command will search memory locations 0012FF40 through 0012FF5F for the double-word 'DCBA'. (On little-endian machines, this is the same as the byte pattern 'A' 'B' 'C' 'D'):

0:000> s -d 0012ff40 L20 DCBA

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

Comments

The ss command with no argument outputs the current state of the suffix value.

When the debugger needs to interpret a symbol, it first searches the symbol files for that symbol name. If it does not find this name, it will append the symbol suffix ("A" or "W") to the name and search for this instead.

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.

Additional Information

For more details on this and other symbol options, see Setting Symbol Options.


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
A command that will be executed if this exception or event breaks into the debugger on its first chance. This command string must be enclosed in quotation marks; separate multiple commands with semicolons.
Cmd2
A command that will be executed if this exception or event breaks into the debugger on its second chance. This command string must be enclosed in quotation marks; separate multiple commands with semicolons.
Exception
The exception number that the command acts upon, in the current radix.
Event
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.
*
This specifies all numbered exceptions (but not any non-exception events).

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | x86, IA-64, Alpha

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, execution occurs and the target will break into the debugger.
SXD | Second chance break (Disabled) | The first time this exception occurs, the debugger will ignore it. The second time it occurs, execution will halt and the target will break into the debugger.
SXN | Output (Notify) | When this exception occurs, it will not break into the debugger. However, a message informing the user of this exception will be displayed.
SXI | Ignore | When this exception occurs, it will be ignored by the debugger. 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 thread(s) are thawed and all others are frozen. For more information, see Process and 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 starts execution at the specified address. Otherwise, it starts execution at the instruction pointed to by the instruction pointer. See Address Syntax for details.
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 | x86, IA-64, Alpha

Comments

The t command can be used to trace instructions in ROM.

Here are some examples. The command ~*t traces with all threads thawed; ~#t traces with only the current exception thread thawed; and ~123t traces with thread 123 thawed, and all others frozen. The ~t and ~.t commands both trace with the current thread thawed.

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

User-Mode Syntax

[thread] tb [r] [= startaddress] [count]

Kernel-Mode Syntax

tb [r] [= startaddress] [count]

Parameters

thread
If thread is specified, the indicated thread(s) are thawed and all others are frozen. For more information, see Process and 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 starts execution at the specified address. Otherwise, it starts execution at the instruction pointed to by the instruction pointer. See Address Syntax for details.
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 branch is reached, whichever occurs first. Each step is displayed as a separate action in the Debugger Command window.

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | x86 and IA-64 only

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.


U (Unassemble)

Displays the instructions of the program being debugged.

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 debugger displays the instructions generated from the first eight lines of code at the current address. (On an IA-64 processor, the default is nine instructions.) For more information, see Address Ranges.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

Comments

The 80286 protected-mode mnemonics cannot be displayed.

If the debugger is in assembly mode (ASM), disassembled machine instructions will be displayed. In source mode (SRC), the source lines will be displayed.

Additional Information

For a description of assembly debugging and related commands, see Debugging in Assembly Mode.


UX (Unassemble BIOS)

Displays the instruction set of the x86 BIOS code.

Syntax

ux [Address]

Parameters

Address
A memory address within the x86 BIOS code. This must be a single address, not a range. For more information, see Address Syntax.

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.

Additional Information

For a description of assembly debugging and related commands, see Debugging in Assembly Mode.


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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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

wt

Environment

Modes | user mode, kernel mode
Targets | live debugging only
Platforms | user mode: x86, IA-64, Alpha kernel mode: x86 only

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 (Program Step) command.

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

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 | x86, IA-64, Alpha

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

Symbol Syntax, 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. See Expression Syntax for more details.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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:

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:

reax=eax+1; rebx=ebx+1; z((eax<8)|(ebx<8)); ecx=ecx+1

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 (.).


.asm (Change IA-64 Disassembly Options)

Sets the IA-64 disassembly options.

Syntax

.asm
.asm[-] verbose

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | IA-64 only

Comments

The verbose option can be turned on with .asm verbose, or turned off with .asm- verbose. Using .asm by itself displays the current state of the options.

When the verbose option is active, bundle type information is displayed along with the standard disassembly information.


.attach (Attach to Process)

Attaches to a new target application.

Syntax

.attach [-v] [-e] PID

Parameters

-v
Causes the specified process to be debugged noninvasively.
-e
(Windows XP only) Allows the debugger to attach to a process that is already being debugged. See Re-attaching to the Target Application for details.
PID
Specifies the process ID of the new target application.

Environment

Modes | user mode only
Targets | live debugging only
Platforms | x86, IA-64, Alpha

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.

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

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.

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 only used when you are controlling the user-mode debugger from the kernel debugger.

Syntax

.breakin

Environment

Modes | controlling the user-mode debugger from the kernel debugger
Targets | live debugging only
Platforms | x86, IA-64, Alpha

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

Under any other conditions, the .breakin command is identical to the standard break commands (CTRL+C in CDB, and Debug | Break or CTRL+BREAK in WinDbg.)

Additional Information

For details, see Controlling the User-Mode Debugger from the Kernel Debugger.


.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 | x86, IA-64, Alpha

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 !analyzebugcheck 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 Codes 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. (The forcedecodeptes option is required when using .context (Set User-Mode Address Context) or .process (Set Process Context) during live debugging. The latter command can also be used to control this option.)
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 | x86, IA-64, Alpha

Comments

If .cache is used with no arguments, the current cache size, status, and options are displayed.


.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 | x86, IA-64, Alpha

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.

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 | x86, IA-64, Alpha

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.


.cls (Clear Screen)

Clears the Debugger Command window display.

Syntax

.cls

Environment

This command is only available in WinDbg.

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha


.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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 CommandLine

Parameters

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 | x86, IA-64, Alpha

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.

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

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.

Additional Information

For more details, and for other methods of 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 | x86, IA-64, Alpha

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. This returns the debugger to dormant mode.

Syntax

.detach

Environment

This command is only supported on Windows XP.

Modes | user mode only
Targets | live debugging only
Platforms | x86, IA-64, Alpha

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 [ /f | /m[Options] ] [/c "Comment"] Filename

Parameters

/f
Causes the debugger to create a Complete Memory Dump (in kernel mode) or a full user dump (in user mode).
/m
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.
Options
Specifies extra data that should be included in the dump. If f is specified, the dump will include full memory data. If h is specified, the dump will include handle data. It is permissible to include both options. These Options can only be used when creating a user-mode minidump; they should follow the /m specifier.
Comment
This 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 to be used for the dump file. The filename must follow Microsoft® MS-DOS® filename conventions.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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.


.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 | x86, IA-64, Alpha

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) character 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 (Toggle DbgPrint Time Stamps)

Toggles the display of time stamp information in DbgPrint output.

Syntax

.echotimestamps

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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

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 | x86, IA-64, Alpha

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_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 | x86, IA-64, Alpha

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


.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 | x86, IA-64, Alpha

Additional Information

For information on process servers, see Remote Debugging Through a Process Server.


.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 | x86, IA-64, Alpha

Additional Information

For details, and for other ways to change this path, see Setting Paths and Loading Files.


.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 | x86, IA-64, Alpha

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.


.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 | x86, IA-64, Alpha

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


.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
Expression to be evaluated with the expression evaluator. See Expression Syntax for details. The C++ expression evaluator cannot calculate expressions that use the conditional operator (?:).

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

Comments

The number is displayed in hexadecimal, decimal, octal, and binary formats. ASCII character formats are also displayed when the bytes correspond to standard ASCII characters.

See Also

? (Evaluate 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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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. 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 | x86, IA-64, Alpha

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)


.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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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.


.logappend (Append Log File)

Appends a copy of the events and commands from the Debugger Command window to the specified log file.

Syntax

.logappend [file]

Parameters

file
The name of the log file. You can specify a full path and file name or just the file name. If the name of the file is omitted, the file will be named dbgeng.log. If no directory is specified, the file will be placed in the default directory from which it was launched.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 [File]

Parameters

File
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, File should be enclosed in quotation marks. If File is omitted, the file will be named dbgeng.log and placed in the same directory as the debugger binaries.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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.


.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 | x86, IA-64, Alpha

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)


.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. If String includes a semicolon, it must be enclosed in quotation marks. 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 | x86, IA-64, Alpha

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. The filename must follow MS-DOS filename conventions.

Environment

This command is only available in WinDbg.

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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.


.process (Set Process Context)

Specifies which process will be used for the process context.

Syntax

.process [ [/p] Process]

Parameters

/p
If this option is included and Process is nonzero, all transition page table entries (PTEs) will be automatically translated into physical addresses before access. If this option is included and Process is zero, this translation will be disabled. (This behavior is the same as that of .cache forcedecodeptes and .cache noforcedecodeptes, respectively.)
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 set to the default process for the current system state.

Environment

Modes | kernel mode only
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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 doing live debugging, you should include the /p parameter, or issue a .cache forcedecodeptes command in addition to the .process 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, this 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 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 8114e848

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 | x86, IA-64, Alpha

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] ] ]

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 using /i, you must always use /f as well.
/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.
Module
Specifies the name of an image on the target system to reload symbols for on the host computer. 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.
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.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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.

To load the correct symbols while debugging in kernel mode, invoke KD with an explicit path to the kernel. For example:

kd c:\nt\oskrnl.exe

Then you can type:

kd> .reload

and the debugger will load the symbols for the drivers that the target system has already loaded.

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 lazy symbol loading and 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 | x86, IA-64, Alpha

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.


.restart (Restart Target Application)

Restarts the target application.

Syntax

.restart

Environment

Modes | user mode only
Targets | live debugging only
Platforms | x86, IA-64, Alpha

Comments

CDB and WinDbg can restart a target application if the application was originally created by the debugger. However, if the application was already running and the debugger was later attached to the process, the .restart command will have no effect.

The .restart command can be used even if the target application has already terminated.

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.


.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 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 and Windows XP only) See the Secure Channel (S-Channel) documentation in the MSDN for details.
SPIPE-Parameters
(Windows 2000 and Windows XP 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 | x86, IA-64, Alpha

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.


.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 | x86, IA-64, Alpha

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.

Syntax

.shell [ShellCommand]

Parameters

ShellCommand
The MS-DOS command to be executed.

Environment

Modes | user mode, kernel mode
Targets | live, crash dump
Platforms | x86, IA-64, Alpha

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.

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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.


.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 | x86, IA-64, Alpha

Comments

Use .symopt+0 or .symopt-0 to display the flags without changing them.

The following table summarizes the symbol option flags:

Flag | Option Name | Default
0x1 | SYMOPT_CASE_INSENSITIVE | On
0x2 | SYMOPT_UNDNAME | On
0x4 | SYMOPT_DEFERRED_LOADS | On
0x8 | SYMOPT_NO_CPP | On
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 | Off
0x400 | SYMOPT_EXACT_SYMBOLS | Off
0x80000000 | SYMOPT_DEBUG | Off

Additional Information

For a description of each of these symbol options, 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 | x86, IA-64, Alpha

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 [Address]

Parameters

Address
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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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.


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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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.

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 | x86, IA-64, Alpha

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. If the target computer is an Alpha, use SYSRQ (or ALT+SYSRQ on enhanced keyboards).

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. When debugging an Alpha machine, it must be pressed on the host 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

HKEY_LOCAL_MACHINE\System\CurrentControlSet\i8042prt\Parameters

create a key 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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

Comments

This attempts to synchronize the host computer with the target computer. Use this command if the target is not responding.

In WinDbg, this can also be accomplished by selecting Debug | Kernel Connection | Resynchronize.


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 | x86, IA-64, Alpha

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 | x86, IA-64, Alpha

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 which can be used in CDB, KD, and WinDbg.

On the individual extension command reference pages, 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 square brackets are optional: [ xxx ]. Square brackets with vertical lines indicate that any one, or none, of the enclosed parameters can be used: [ xxx | yyy ]. Curled 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. Moreover, they often will assume that numbers are hexadecimal (or, in rarer cases, decimal). 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

Miscellaneous 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, 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

!acl Address

Parameters

Address
Specifies the hexadecimal address of the ACL.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | 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.


!atom

Displays the formatted atom table for the atom specified, or for all atoms of the current process.

Syntax

!atom [Atom]

Parameters

Atom
The hexadecimal virtual address of the atom to be displayed. If this is omitted or zero, the atom table for the current process is dumped; this table list all atoms for the process.

DLL

Windows NT 4.0 | kdextx86.dll ntsdexts.dll
Windows 2000 | kdextx86.dll ntsdexts.dll
Windows XP | exts.dll

Additional Information

For information on atoms and atom tables, see the Platform SDK.


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

DLL

Windows NT 4.0 | dbghelp.dll kdextx86.dll ntsdexts.dll
Windows 2000 | dbghelp.dll kdextx86.dll ntsdexts.dll
Windows XP | 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

Dumps 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 and Windows XP only) Causes the display to include the module containing ModuleAddress.
-i
(Windows 2000 and Windows XP only) Causes the display to be sorted by initialization order.
-l
(Windows 2000 and Windows XP only) Causes the display to be sorted by load order. This is the default.
-m
(Windows 2000 and Windows XP only) Causes the display to be sorted by memory order.
-v
(Windows XP 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.

DLL

Windows NT 4.0 | kdextx86.dll ntsdexts.dll
Windows 2000 | kdextx86.dll ntsdexts.dll
Windows XP | exts.dll

Comments

The module listing includes all entry points into each module.

This command only works with live debugging — not with crash dump analysis.

This command only works in the context of a user-mode process. It 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


!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 | ext.dll ntsdexts.dll


!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 {+|-} Value
!gflag {+|-} Abbreviation
!gflag

Parameters

Value
This is a single 32-bit hexadecimal number. If no plus (+) or minus (-) is given, this entire number becomes the new value of the Global Flag. 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
This is a three-letter abbreviation for a Global Flag that will either be set to one (+) or to zero (-).

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll ntsdexts.dll
Windows XP | exts.dll

Comments

If no arguments are specified then 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 | "hat" | Enable heap API call tracing
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 tool (gflags.exe).


!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 a handle value for which information should 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.
Bit 4 (0x10)
(Windows XP only) Causes the display to include the kernel handle table.
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 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 to be displayed.

DLL

Windows NT 4.0 | kdextx86.dll uext.dll ntsdexts.dll
Windows 2000 | kdextx86.dll uext.dll ntsdexts.dll
Windows XP | 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 can not 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.)

Here are some examples (taken from user-mode live debugging).

Display a list of all handles:

0:000> !handle

Display a summary table of all open handles:

0:000> !handle 0 0

Display full details for all handles:

0:000> !handle 0 f

Display full details about all open events:

0:000> !handle 0 f Event

Additional Information

For information on handles, see the Platform SDK or Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!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 [Heap] [HeapOptions] [ValidationOptions]
!heap [Heap|BreakAddress] -b [ {alloc|realloc|free} [Tag] ]
!heap [Heap|BreakAddress] -B {alloc|realloc|free}
!heap -?

Windows 2000 Syntax

!heap [Heap] [HeapOptions] [ValidationOptions]
!heap [Heap|BreakAddress] -b [ {alloc|realloc|free} [Tag] ]
!heap [Heap|BreakAddress] -B {alloc|realloc|free}
!heap -p [-h|-a] Address
!heap -p -t [Traces]
!heap [-p] -?

Windows XP Syntax

!heap [Heap] [HeapOptions] [ValidationOptions]
!heap [Heap|BreakAddress] -b [ {alloc|realloc|free} [Tag] ]
!heap [Heap|BreakAddress] -B {alloc|realloc|free}
!heap -l
!heap -x [-v] Address
!heap -p [-h|-a] Address
!heap -p [ -t[c|s] | -fi ] [Traces]
!heap [-p] -?

Parameters

Heap
Specifies either a heap index number or a heap address. 1 is the default and specifies the process heap. 0 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:
-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 no more than one of the following options:
-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.
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 only) Causes the debugger to detect leaked heap blocks.
-x [-v]
(Windows XP 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 only) Specifies the address to search for.
-p
(Windows 2000 and Windows XP only) Specifies that page heap information is being requested. If this is used without any other options, all page heaps will be displayed. The following options can also be used:
-h Address
Causes the debugger to display detailed information about a page heap at Address.
-a Address
Causes the debugger to finds the page heap whose block is at Address. Full details of how this address relates to 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 4. If there are more traces than the specified number, the earliest traces are displayed. If -t or -tc is used, these are sorted by count usage. If -ts is used, these are sorted by size. (The c and s options are supported in Windows XP only.)
-fi [Traces]
(Windows XP only) Causes the debugger to display the most recent fault injection traces. Traces specifes the quantity to be displayed; the default is 4.
-?
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 command help. If this is preceded by -p, page heap help will be displayed. (Page heap help is available in Windows 2000 and Windows XP only.)

DLL

Windows NT 4.0 | kdextx86.dll ntsdexts.dll
Windows 2000 | kdextx86.dll ntsdexts.dll
Windows XP | 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.

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.

The !heap -p command displays various forms of page heap information. This command is only available in Windows 2000 (Service Pack 1 or later) and in Windows XP. 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) tool. Start this tool, fill in the name of the target application in the Image File Name text box, select Image File Options, select Enable page heap, and press Apply. Or from an MS-DOS Command prompt window, type 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 above 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, at address 00205990 there is a pointer to this block.

The following diagrams show the arrangement of heap blocks. These are valid in Windows 2000 Service Pack 1, as well as Windows XP.

Normal heap allocated block:

 +-----+---------------+---+
 |     |               |   |
 +-----+---------------+---+
    ^         ^          ^
    |         |          8 suffix bytes (filled with 0xA0)
    |         User allocation (filled with E0 if zeroing not requested)
    Block header (starts with 0xABCDAAAA and ends with 0xDCBAAAAA)

Normal heap freed block:

 +-----+---------------+---+
 |     |               |   |
 +-----+---------------+---+
    ^         ^          ^
    |         |          8 suffix bytes (filled with 0xA0)
    |         User allocation (filled with F0 bytes)
    Block header (starts with 0xABCDAAA9 and ends with 0xDCBAAA9)

Page heap allocated block:

 +-----+---------+---+-------
 |     |         |   |  ... 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)

Page heap freed block:

 +-----+---------+---+-------
 |     |         |   |  ... 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 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 page heap block in Windows XP, use dt DPH_BLOCK_INFORMATION with the header address, followed by dds with the block's StackTrace field.

Page heap blocks in Windows 2000 reside at the beginning of the page containing the user allocation, or 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.


!kuser

Dumps 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 | exts.dll

Comments

The KUSER_SHARED_DATA page gives resource and other information about the currently logged-on user.


!lmi

Displays detailed information about a module.

Syntax

!lmi Module

Parameters

Address
Specifies a loaded module, either by name or by base address.

DLL

Windows NT 4.0 | dbghelp.dll
Windows 2000 | dbghelp.dll
Windows XP | 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 0042c000   prymes       prymes.exe
77e80000 77f36000   kernel32     (deferred)
77f80000 77ff9000   ntdll        (export symbols)           ntdll.dll

0:000> !lmi 77e80000
Loaded Module Info: [77e80000]
         Module: KERNEL32
   Base Address: 0x77e80000
     Image Name: C:\WINNT\system32\KERNEL32.dll
   Machine Type: 332 (I386)
     Time Stamp: 3844d034 Tue Nov 30 23:37:24 1999
       CheckSum: bf812
Characteristics: 230e stripped
Debug Data Dirs: Type Size     VA  Pointer
                 MISC  110,     0,   b2c00 [Data not mapped]
    Symbol Type: DEFERRED - No error - symbol load deferred.
0:000>


!obja

Dumps an Object Manager object's attributes.

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 ntsdexts.dll
Windows 2000 | ext.dll kdextx86.dll ntsdexts.dll
Windows XP | ext.dll exts.dll kdexts.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.


!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 omitted, the PEB for the current process is used.

DLL

Windows NT 4.0 | kdextx86.dll ntsdexts.dll
Windows 2000 | kdextx86.dll ntsdexts.dll
Windows XP | exts.dll

Comments

The PEB is the user-mode portion of Microsoft® Windows' process control structures.

Here is an example of this command's output:

0:004> !peb
PEB at 7FFDF000
    InheritedAddressSpace:    No
    ReadImageFileExecOptions: No
    BeingDebugged:            Yes
    ImageBaseAddress:         01000000
    Ldr.Initialized: Yes
    Ldr.InInitializationOrderModuleList: 71f80 . bffa0
    Ldr.InLoadOrderModuleList: 71ee0 . c02a8
    Ldr.InMemoryOrderModuleList: 71ee8 . c02b0
        01000000 C:\WINNT\System32\winmine.exe
                 TimeStamp : 37f045df Mon Sep 27 21:36:47 1999
        77F80000 C:\WINNT\System32\ntdll.dll
                 TimeStamp : 394193d2 Fri Jun 09 18:03:14 2000
        78000000 C:\WINNT\system32\MSVCRT.dll
                 TimeStamp : 37f2c227 Wed Sep 29 18:51:35 1999
        77E80000 C:\WINNT\system32\KERNEL32.dll
                 TimeStamp : 394193d2 Fri Jun 09 18:03:14 2000
        77DB0000 C:\WINNT\system32\ADVAPI32.dll
                 TimeStamp : 394193d2 Fri Jun 09 18:03:14 2000
........
        770C0000 C:\WINNT\System32\CSCDLL.DLL
                 TimeStamp : 3924a0aa Thu May 18 19:02:18 2000
    SubSystemData:     0
    ProcessHeap:       70000
    ProcessParameters: 20000
        WindowTitle:  'C:\WINNT\System32\winmine.exe'
        ImageFile:    'C:\WINNT\System32\winmine.exe'
        CommandLine:  'winmine.exe'
        DllPath:      'C:\WINNT\System32;.;C:\WINNT\system;.....
        Environment:  0x10000

Additional Information

For information on process environment blocks, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!sd

Displays the security descriptor at the specified address.

Syntax

!sd Address

Parameters

Address
Specifies the hexadecimal address of SECURITY_DESCRIPTOR structure.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | 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.


!sid

Displays the security identifier (SID) at the specified address.

Syntax

!sid Address

Parameters

Address
Address of SID structure.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | 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.


!str

Dumps an ANSI_STRING structure.

Syntax

!str Address

Parameters

Address
Specifies the hexadecimal address of the ANSI_STRING structure.

DLL

Windows NT 4.0 | ext.dll ntsdexts.dll
Windows 2000 | ext.dll ntsdexts.dll
Windows XP | ext.dll exts.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

Activates or deactivates noisy symbol loading.

Syntax

!sym [noisy|quiet]

Parameters

noisy
Causes noisy symbol loading to be turned on.
quiet
Causes noisy symbol loading to be turned off.

DLL

Windows NT 4.0 | dbghelp.dll
Windows 2000 | dbghelp.dll
Windows XP | dbghelp.dll

Comments

If the !sym extension is used with no arguments, the current state of noisy symbol loading is displayed.

Additional Information

For a description of noisy symbol loading, as well as other methods of displaying and changing its status, see Setting Symbol Options.


!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 omitted, the TEB for the current thread is used.

DLL

Windows NT 4.0 | kdextx86.dll ntsdexts.dll
Windows 2000 | kdextx86.dll ntsdexts.dll
Windows XP | exts.dll

Comments

The TEB is the user-mode portion of Microsoft® Windows' thread control structures.

Here is an example of this command's output:

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

Additional Information

For information on thread environment blocks, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!ustr

Dumps 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 ntsdexts.dll
Windows 2000 | ext.dll ntsdexts.dll
Windows XP | ext.dll exts.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 which 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 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 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, 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.


!analyzebugcheck

Displays information about a bug check.

Syntax

!analyzebugcheck
!analyzebugcheck -show BugCheckCode

Parameters

-show BugCheckCode
Causes the debugger to show information about the specified bug check code.

DLL

Windows NT 4.0 | kext.dll
Windows 2000 | kext.dll
Windows XP | kext.dll

Comments

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 !analyzebugcheck extension command can be used whenever the target computer has experienced a bug check. (Indeed, in most cases it will automatically be issued after a bug check.) It can also be useful in other cases.

If you simply want the basic bug check parameters, you can also use the .bugcheck (Display Bug Check Data) command.

Additional Information

For more information about bug checks, see Bug Checks (Blue Screens). For a description of individual bug checks, see the Bug Check Codes reference section.


!arbiter

Displays the current system resource arbiters and arbitrated ranges.

Syntax

!arbiter [Flags]

Parameters

Flags
Specify 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 | kdexts.dll

Comments

For each arbiter, !arbiter displays each allocated range of system resources, the PDO attached to that range, and the service name (if known). 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. 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.


!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 ID's are usually listed in decimal format, you may need to prefix this with 0n, or convert it to hexadecimal.)

DLL

Windows NT 4.0 | Not available
Windows 2000 | Not available
Windows XP | 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 it 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 various system bug check buffers.

Syntax

!bugdump [Module]

Parameters

Module
Specifies the component whose bug data is to be examined. If omitted, all bug data is displayed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

See Also

.bugcheck (Display Bug Check 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 | 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 | 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 | 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 into which the call data is being collected.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

Comments

Call data was used to measure call performance in older releases of Windows NT.


!cmreslist

Displays the CM_RESOURCE_LIST for the specified device object.

Syntax

!cmreslist Address

Parameters

Address
Specifies the hexadecimal hexadecimal address of the CM_RESOURCE_LIST structure.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

Additional Information

See Plug and Play Debugging for applications of this extension command. For information on CM_RESOURCE_LIST structures, see the Windows DDK.


!cpuinfo

Displays detailed information about the target computer's CPU.

Syntax

Windows 2000 Syntax

!cpuinfo

Windows XP Syntax

!cpuinfo Processor
!cpuinfo

Parameters

Processor
(Windows XP 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 | 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.


!db

Displays a hexadecimal and ASCII dump of 128 bytes from the specified physical address on the target computer.

This extension command should not be confused with the DB (Display Memory) command.

Syntax

!db [PhysicalAddress]

Parameters

PhysicalAddress
Specifies the first physical address to be displayed, in hexadecimal. If this is omitted the first time this command is used, the address defaults to zero. If this is omitted on a subsequent use, !db will display the next 128 bytes starting at the first byte following the end of the previous !db command.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

Comments

The !db extension command displays bytes and ASCII characters, !dd displays ULONGs, and !dc displays ULONGs and ASCII characters. (Note that !dc is only available on Windows NT 4.0 and Windows XP.)

Additional Information

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 | 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) tool. Start this tool, 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 press Apply. Or from an MS-DOS Command prompt window, type 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.


!dc

Displays a hexadecimal and ASCII dump of 32 ULONG values from the specified physical address on the target computer.

This extension command should not be confused with the DC (Display Memory) command.

Syntax

!dc [PhysicalAddress]

Parameters

PhysicalAddress
Specifies the first physical address to be displayed, in hexadecimal. If this is omitted the first time this command is used, the address defaults to zero. If this is omitted on a subsequent use, !dc will display the next 32 ULONG values starting at the first byte following the end of the previous !dc command.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | Not available
Windows XP | kdexts.dll

Comments

The !db extension command displays bytes and ASCII characters, !dd displays ULONGs, and !dc displays ULONGs and ASCII characters. (Note that !dc is only available on Windows NT 4.0 and Windows XP.)

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


!dcs

Displays the PCI configuration space for a device.

Syntax

!dcs Bus.Device.Function

Parameters

Bus
Specifies the bus number.
Device
Specifies the device number.
Function
Specifies the function number.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

Additional Information

See Plug and Play Debugging for applications of this extension command.


!dd

Displays a hexadecimal dump of 32 ULONG values from the specified address on the target computer.

This extension command should not be confused with the DD (Display Memory) command.

Syntax

!dd [PhysicalAddress]

Parameters

PhysicalAddress
Specifies the first physical address to be displayed, in hexadecimal. If this is omitted the first time this command is used, the address defaults to zero. If this is omitted on a subsequent use, !dd will display the next 32 ULONG values starting at the first byte following the end of the previous !dd command.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

Comments

The !db extension command displays bytes and ASCII characters, !dd displays ULONGs, and !dc displays ULONGs and ASCII characters. (Note that !dc is only available on Windows NT 4.0 and Windows XP.)

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


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

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 | 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 dumped.
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
USBD | USB bus driver extension
UHCD | UHCD host controller extension
OpenHCI | Open HCI host controller extension
USBHUB | USB hub extension
HID | HID device extension

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP | 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 0, 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 | 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.

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 and Windows XP, 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 | 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 | 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.


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

Comments

Invalid arguments (e.g., !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, 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 | 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, then 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 example is a partial listing:

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

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 and Windows XP 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 and Windows XP, this can be the hexadecimal address of this structure or the name of the device.
Flags
(Windows 2000 and Windows XP 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 | 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      //  dump 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

Writes a sequence of byte values into a specified physical address.

This extension command should not be confused with the EB (Enter Values) command.

Syntax

!eb PhysicalAddress Data [ ... ]

Parameters

PhysicalAddress
Specifies the first physical address on the target computer to which the data will be written, in hexadecimal.
Data
Specifies one or more byte values to be written into physical memory. These will be written sequentially to memory. Multiple values can be separated by commas or by spaces.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


!ed

Writes a sequence of ULONG values into a specified physical address.

This extension command should not be confused with the ED (Enter Values) command.

Syntax

!ed PhysicalAddress Data [ ... ]

Parameters

PhysicalAddress
Specifies the first physical address on the target computer to which the data will be written, in hexadecimal.
Data
Specifies one or more ULONG values to be written into physical memory. These will be written sequentially to memory. Multiple values can be separated by commas or by spaces.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

Additional Information

For an overview of memory manipulation and a description of other memory-related commands, see Reading and Writing Memory.


!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 | 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 thatwas unable to be committed to the error log before the system halted.

Additional Information

For information on IoWriteErrorLogEntry, see the Windows DDK.


!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 | 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 | 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 name is given. 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 Syntax

!filelock FileLockAddress
!filelock ObjectAddress

Parameters

FileLockAddress
Specifies the hexadecimal address of the file lock structure.
ObjectAddress
(Windows XP 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 | kdexts.dll

Comments

Here is an example from an Alpha computer running Windows NT 4.0:

kd> bp FsRtlUninitializeFileLock

kd> g
ntoskrnl!FsRtlUninitializeFileLock+0x1c:
800a134c: 47f00409 bis     zero,a0,s0

kd> r a0             //  Specifies the filelock address (first parameter)
a0 = 80935a68

kd> !filelock 80935a68
FileLock @ 80935a68
FastIoIsQuestionable = T
CompletionRoutine    = 00000000
UnlockRoutine        = 00000000
LastReturnedLock     = 00000000
LowestLockOffset     = 00000000
LockTreeNode @ 8095e588 (P = 8095e588  R = 00000000  L = 00000000)
Lock @ 8095e5c8
Start = 000000000  Length = ffffffffffffffff  End    = fffffffffffffffe (Sh)
Key   = 00000001   FileOb = 80935be8   ProcId = 80937de0
No Exclusive Locks

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


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

Comments

Additional Information

For information on human input devices (HIDs), see the Windows DDK.


!ib, !id, !iw

The !ib, !id, and !iw extension commands are obsolete. Use the IB, ID, IW (Input from Port) commands instead.


!ioresdes

Displays the IO_RESOURCE_DESCRIPTOR 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 | 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.

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

This resource 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, 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 and Windows XP 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 and Windows XP 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 a full field dump.
2
(Checked build only) Causes the display to include tracking information.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | 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 (IRPs) 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 and Windows XP Syntax

!irpfind [PoolType [RestartAddress [Criteria Data]]]

Parameters

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, 5, 6
(Windows NT 4.0 only) Specify nonpaged, paged, and special pool, respectively, but also cause the display of information to be more detailed.
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 matches Data.
mdlprocess | Finds all IRPs whose Irp.MdlAddress.Process matches Data.
thread | Finds all IRPs whose Irp.Tail.Overlay.Thread matches 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 | 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), 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 | 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.


!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, then information about all ERESOURCE locks in the system will be displayed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | 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 needed by an executing thread. Most of the locks are shared locks.

Here are some examples:

kd> !locks
**** DUMP OF ALL RESOURCE OBJECTS ****
KD: Scanning for held locks....................
Resource @ 0x81785ca0    Shared 1 owning threads
     Threads: 809daca0-01
Resource @ 0x808728c0    Shared 1 owning threads
     Threads: 809ddcb0-01

kd> !locks -p -v -d
**** DUMP OF ALL RESOURCE OBJECTS ****
KD: Scanning for held locks.................

Resource @ 0xffb6ed14  Shared 2 owning threads
   Threads: ffb3bb70-01
0012fb50: Unable to read ThreadCount for resource

Resource @ 0xffb6ecdc  Shared 2 owning threads
   Threads: ffb3bb70-02
0012fb50: Unable to read ThreadCount for resource

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. For example, using the last resource listed:

kd> !thread 0xffb6ecdc

kd> dt ERESOURCE 0xffb6ecdc


!kv

The !kv extension command is obsolete. Use the KV (Display Stack Backtrace) command instead.


!lookaside

Displays information about one or more lookaside lists, resets the counters of one or more 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 0:
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 | 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 Syntax

!lpc message MessageID
!lpc port Port
!lpc scan Port
!lpc thread Thread
!lpc PoolSearch
!lpc

Parameters

message
(Windows 2000 and Windows XP only) Causes information about a message to be displayed, including information about the server port that contains it in the queue, and all threads which are doing something with this message.
MessageID
(Windows 2000 and Windows XP 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, and in Windows XP, this includes all messages in the kernel pool. Paged-out messages will not be included.)
port
(Windows 2000 and Windows XP 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 and Windows XP only) Causes summary information about the specified port and all ports which are connected to it to be displayed.
Port
(Windows 2000 and Windows XP 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 and Windows XP only) Causes port information to be displayed for all ports which contain the specified thread in their rundown port queues.
Thread
(Windows 2000 and Windows XP 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 which are performing any LPC operations.
PoolSearch
(Windows XP 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 which specify a nonzero value for MessageID.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | 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 and Windows XP.

In Windows 2000 and Windows XP, using !lpc with no arguments causes a short help text to be displayed.

If you have a thread which 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 which 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 | kdexts.dll

Comments

Physical memory statistics are collected from the Memory Manager's page frame number (PFN) database table.

This command can 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 which 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 | kdexts.dll

This extension command can only be used with an x86 target computer.

Additional Information

For more information, 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 | 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 | 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, 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 and Windows XP 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 (\), then !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 and Windows XP only) Causes cached values of global variables to be refreshed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | 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.
Bus
Specifies the bus to be displayed (this can range from 0 to 0xFF). If Flags includes bit 1 (0x2), this specifies the highest bus number to be displayed. If this is omitted, information on the primary bus (bus 0) is printed.
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 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

This extension command can only be used with an x86 target computer.

Comments

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. 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 | 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 sub-class 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 sub-class 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
(x86 and IA-64 targets only) Specifies the processor to retrieve the PCR information from. If Processor is omitted, processor zero will be used. This parameter cannot be used on Alpha target computers.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | 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

Here is an example on an Alpha target computer:

kd> !pcr
KPCR for Processor 0 at 8006c000:
Major 1 Minor 1
Panic Stack 8006c000
Dpc Stack 80064000
Irql addresses:
    Mask    8006ced0
    Table   8006ceb0
    Routine 8006d0e0

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.

Parameters

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

Comments

The page frame number can 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.


!pocaps

Displays the power capabilities of the target computer.

Syntax

!pocaps

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP | 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 0:
Bit 0 (0x1)
Causes the display to include the pool contents, not just the pool headers.
Bit 1 (0x2)
(Windows 2000 and Windows XP only) Causes the display to suppress pool header information for all pools except the one actually specified by Address.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

Comments

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 and Windows XP 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 and Windows XP 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
(Windows 2000 and Windows XP only) Specifies the special pool.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | 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 and Windows XP 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 usage.
Bit 2 (0x4)
Causes the display to be sorted by the amount of paged memory usage.
TagString
(Windows 2000 and Windows XP 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 | 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.


!popolicy

Displays the power policy of the target computer.

Syntax

!popolicy

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP | 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 | kdexts.dll

Comments

The PRCB is an extension of the processor control region (PCR). To display the PCR, use the !pcr extension.

Here is an example on an Alpha target computer:

kd> !prcb
PRCB for Processor 1241616 at 80076000:
Major 2 Minor 1
Threads--  Current 80a02800  Next 00000000  Idle 80076840
Number 0 SetMember 00000001
Interrupt Count -- 0000000e
Times -- Dpc    00000000 Interrupt 00000000
         Kernel 00000001 User      00000000

Additional Information

For information on the PCR and the PRCB, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


!process

Displays summarized or detailed information about the specified process, or about all processes.

Syntax

!process [/s Session] [Address [Flags]]

Parameters

Session
(Windows 2000 and Windows XP only) Specifies the session that owns the desired process.
Address
Specifies the hexadecimal address of the process on the target computer. If Address is -1 or omitted, it indicates the current process. If Address is 0, 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 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 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 | 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 of 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 of 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 of 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 of 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 of the preceding example, the owner is spoolss.exe. In the first entry, the owner is the operating system itself.

An example of a !process 0 7 display:

kd> !process 0 7
**** NT ACTIVE PROCESS DUMP ****
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 user mode, see Controlling Processes and Threads. 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 | Not available (see note in Comments section)

Comments

This extension command is not available in Windows XP. 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 the range whose page tables are to be displayed.
EndAddress
(x86 target computer only) Specifies the last virtual address in the range whose page tables are to be displayed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | 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 page directory entry (PDE) and the page table entry (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 / kernel mode)
W | R | Writeable / read-only (for multi-processor 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 / kernel mode)
D | - | Dirty
A | - | Accessed
W | R | Writeable / read-only (for multi-processor 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 / kernel mode)
A | - | Accessed
- | D | Dirty
W | R | Writeable or read-only (for multi-processor 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 page directory entry (PDE) page.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

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.


!qlocks

Displays the state of all queued spin locks.

Syntax

!qlocks

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

Comments

This command is only useful on a multiprocessor machine.

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 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 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 | 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. ConvKey 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 | 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 | 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, 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.


!sel

Displays information about the given processor selector.

Syntax

!sel [Selector]

Parameters

Selector
Specifies the number of the selector to display. If this is omitted, all selector values will be displayed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

Comments

The !sel extension command will only work with an x86 target machine.

The DG (Display Selector) command will also display information about a selector. It shows a slightly different selection of information than the DG command does, but cannot be used to display a list of all selectors.

Here is an example of these two commands:

kd> !sel
0028  Bas=803cc000 Lim=000020ab Bytes DPL=0  P TSS32    B
0030  Bas=ffdff000 Lim=00000001 Pages DPL=0  P Data  RW A
0038  Bas=7ffde000 Lim=00000fff Bytes DPL=3  P Data  RW A
0040  Bas=00000400 Lim=0000ffff Bytes DPL=3  P Data  RW
0048  Bas=00000000 Lim=00000000 Bytes DPL=0 NP
0050  Bas=80162b00 Lim=00000068 Bytes DPL=0  P TSS32    A
0058  Bas=80162b68 Lim=00000068 Bytes DPL=0  P TSS32    A
0060  Bas=00022ee0 Lim=0000ffff Bytes DPL=0  P Data  RW A
0068  Bas=000b8000 Lim=00003fff Bytes DPL=0  P Data  RW
0070  Bas=ffff7000 Lim=000003ff Bytes DPL=0  P Data  RW
0078  Bas=80400000 Lim=0000ffff Bytes DPL=0  P Code  RE
0080  Bas=80400000 Lim=0000ffff Bytes DPL=0  P Data  RW
0088  Bas=00000000 Lim=00000000 Bytes DPL=0  P Data  RW
0090  Bas=00000000 Lim=00000000 Bytes DPL=0 NP
0098  Bas=00000000 Lim=00000000 Bytes DPL=0 NP
00a0  Bas=827f06e8 Lim=00000068 Bytes DPL=0  P TSS32    A

kd> !sel 38
0038  Bas=7ffde000 Lim=00000fff Bytes DPL=3  P Data  RW A

kd> dg 38
Selector   Base     Limit   Type  DPL   Size  Gran
-------- -------- -------- ------ --- ------- ----
  0038   7ffde000 00000fff  Data   3    Big   Byte


!session

Displays one or more user sessions, or displays a specified process running in multiple user sessions.

Syntax

!session [SessionID [2 Image]]

Parameters

SessionID
Specifies the session ID for the desired session. If this is omitted or equal to -1, all sessions are displayed.
Image
Specifies the image name of a process. All processes with this name belonging to the session specified by SessionID will be displayed. If this is omitted, the csrss.exe process is displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

Comments

Since every session contains exactly one csrss.exe process, you should omit 3 Image if you simply desire to see a list of all current sessions.

Additional Information

For information on user sessions and the Session Manager (smss.exe), 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 | 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.

Here is an example from an Alpha target computer:

kd> bp symc810!Sym8xxStartIo      // Set a breakpoint in StartIO routine

kd> g
symc810!Sym8xxStartIo+0x14:
80007ec4: 47f00409 bis     zero,a0,s0

kd> r a1        // Get the second parameter (pointer to SRB)
a1=80992a88

kd> !srb 80992a88
Srb 80992a88 is from pool
SRB_FUNCTION_EXECUTE_SCSI: Path 0, Tgt 0, Lun 0, Tag 12, SrbStat 0, ScsiStat 0
OrgRequest 80992b68 SrbExtension 809d2240 TimeOut 0000000a SrbFlags 00010342
Queue Enable, No freeze, Cache Enable, Is active,
10 byte command with data transfer in: 28  0  0  9 d5 64  0  0 18  0

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.
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 | 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 the free page table entries. This bit has no effect in Windows XP, except when bit 3 (0x8) is set.
Bit 1 (0x2)
(Windows NT 4.0 and Windows 2000 only) Causes the display to include information about free PTEs.
Bit 2 (0x4)
(Windows 2000 and Windows XP only) Causes the display to include detailed information about any system PTEs that are allocated to mapping locked pages.
Bit 3 (0x8)
(Windows 2000 and Windows XP only) Displays non-paged pool expansion free PTE information. If this bit is set, the other lists are not displayed. If both 0x1 and 0x8 are set, all non-paged 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 | 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.
......

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 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 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 | 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:

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 user mode, see Controlling Processes and Threads. 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 | Not available (see note in Comments section)

Comments

This extension command is not available in Windows XP. 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 | kdexts.dll

Comments

The !timer extension dumps 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.


!token

Displays a formatted view of a security token object.

Syntax

!token Address [Flags]

Parameters

Address
Specifies the address of the token to be displayed.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | kdexts.dll

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 and Windows 2000, or use the dt nt!_TOKEN command in Windows XP.

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


!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 | Not available (see note in Comments section)

Comments

This extension command is not available in Windows XP. 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 | 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. A asterisk (*) indicates all breakpoints.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP | 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. A asterisk (*) indicates all breakpoints.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP | 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 | 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 | 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 | kdexts.dll

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 | 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:

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 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, spinlocks, 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 non-paged 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 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 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 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 only) Causes a short help text to be displayed.

DLL

Windows NT 4.0 | Not available
Windows 2000 | kdextx86.dll
Windows XP | 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 and Windows XP Syntax

!vm [Flags]

Parameters

Flags
(Windows 2000 and Windows XP 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 only) Causes the display to include terminal server memory usage.

DLL

Windows NT 4.0 | kdextx86.dll
Windows 2000 | kdextx86.dll
Windows XP | 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 | kdexts.dll

Comments

Here is an example. First, we dump 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.


!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 | 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 user mode, see Controlling Processes and Threads. 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, 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.


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


!dp

Dumps a CSR process.

This extension command should not be confused with the DP (Display Memory) 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 | 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 | Not available

Comments

If you are investigating the page heap in Windows 2000 (Service Pack 1 or later) or in Windows XP, 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 | 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) or in Windows XP, 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 normal 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 normal 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 | Not available

Comments

If you are investigating the page heap in Windows 2000 (Service Pack 1 or later) or in Windows XP, 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 memory gets below 48% then all allocations are done in normal heap:

!dphflags 0x3000300F

See Also

!dphdump, !dphfind, !dphhogs


!dphhogs

Dumps 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 | 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) or in Windows XP, 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 | 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 | 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


!gatom

Dumps the global atom table.

Syntax

!gatom

DLL

Windows NT 4.0 | ntsdexts.dll
Windows 2000 | ntsdexts.dll
Windows XP | ntsdexts.dll

Additional Information

For information on the global atom table, see the Platform SDK.


!gle

Displays the last error value for the current thread.

Syntax

!gle

DLL

Windows NT 4.0 | ntsdexts.dll
Windows 2000 | ntsdexts.dll
Windows XP | ntsdexts.dll

Comments

This extension dumps the value of GetLastError and attempts to decode this value.

Additional Information

For information on the GetLastError routine, 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 | Not available


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


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

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 | ntsdexts.dll

Comments

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.


!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 | uext.dll ntsdexts.dll

Comments

The !vprot extension command can be used for both live debugging and dump file debugging.

This command displays base address, allocation base, allocation protection status, region size, state, memory protection status, and memory type.

Protection status values can be PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_WRITECOPY, PAGE_EXECUTE_WRITECOPY, or PAGE_GUARD. State values can be MEM_COMMIT, MEM_FREE, or MEM_RESERVE. Memory type values can be MEM_IMAGE, MEM_MAPPED, or MEM_PRIVATE.

Additional Information

For information on memory protection, see Inside Microsoft Windows 2000 by David Solomon and Mark Russinovich.


Miscellaneous Extensions

This section of the reference discusses extensions commands in the less-used extension DLLs.

These include:

Graphics Driver Extensions

OEM Support Extensions


Graphics Driver Extensions

Extension commands which are useful for debugging the Graphics Driver Interface (GDI) can be found in gdikdx.dll. Versions of this extension DLL appear in the nt4fre, nt4chk, w2kfre, and w2kchk directories.


!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.
s
(Windows XP only) Causes the display to include Low Resource Simulation statistics. A list of GDI callback functions will be displayed, along with the number of times each function was called and the number of times this function was failed by Driver Verifier.
h (or ?)
Displays a brief help text about this command.

DLL

Windows NT 4.0 | Not available
Windows 2000 | gdikdx.dll
Windows XP | gdikdx.dll

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)

Using Debugging Tools for Windows

OEM Support Extensions

[This is preliminary documentation and subject to change.]

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, go to http://support.microsoft.com/support/kb/articles/Q253/0/66.asp and follow the instructions on that page.


Routines Called From Debugger Extensions

This section of the reference discusses the routines in wdbgexts.dll.

This DLL exposes a number of routines which can be used 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.


Routines in Wdbgexts.h

The following routines are exposed by the wdbgexts.h header file. This file is shipped with the Microsoft® Windows® 2000 DDK.


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 Processor,
    PCONTEXT lpContext,
    ULONG cbSizeOfContext
    );

Parameters

Processor
Processor number.
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
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

VOID ReadIoSpaceEx is an extended version of ReadIoSpace, and is supported on Alpha processors only. 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.

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 2000 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 Processor,
    PCONTEXT lpContext,
    ULONG cbSizeOfContext
    );

Parameters

Processor
Processor number.
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
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, and is supported on Alpha processors only. 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 2000 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.


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.

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

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

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.

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.

If no buttons are toggled, only the name or offset of each function is displayed.

Toggling the Column names button will cause titles to appear at the top of each column.

Toggling the Frame addresses 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 Arguments and Nonvolatile registers buttons are toggled as well. On an Alpha or AXP64 processor, this includes the return address (Return-RA).

Toggling the Source line button will cause source module names and line numbers to be displayed after the function names (if the debugger has this information).

Toggling the Arguments 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 registers button is also toggled. On an Alpha or AXP64 processor, this includes the parameters passed to the function (Arguments to Callee).

Toggling the Nonvolatile registers button will cause the nonvolatile portion of the register context to be displayed. This is only available on an IA-64 processor.

Toggling the Function info button displays FPO data and other internal information about the function. This is only available on an x86 processor.

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 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 line representing the current program counter is highlighted in green. At the right side of this line, the values of any memory locations or registers being accessed are displayed as well.

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 assembly debugging and related commands, 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 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.

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.

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.

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 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 and Windows XP only) If SSL protocol is used, SSL-Parameters should match those used when the server was created.
SPIPE-Parameters
(Windows 2000 and Windows XP 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. (This can be in the format "com2" or in the format "\\.\com2", but should not simply be a number). Then click OK. If you click OK without entering text, WinDbg checks to see if the _NT_DEBUG_PORT and _NT_DEBUG_BAUD_RATE environment variables have been set. If not, WinDbg defaults to COM1 and 19200 baud.
  • The 1394 tab indicates that the connection will use 1394. In the Channel text box, enter the 1394 channel used at boot. If you do not specify the channel, WinDbg checks to see if the _NT_DEBUG_1394_CHANNEL environment variable has been set.
  • The Local tab indicates that WinDbg will perform local kernel debugging. Local kernel debugging is only supported on Windows XP.

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 | 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 | 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 not appear in any debuggers connected to your session remotely, nor will it appear in any log files.

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 | 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 clicking the following toolbar button:

However, if a Source window or the Disassembly window is active, this button will set a breakpoint on the current line.

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 | 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. If the target computer is an Alpha, use SYSRQ (or ALT+SYSRQ on an enhanced keyboards).

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

HKEY_LOCAL_MACHINE\System\CurrentControlSet\i8042prt\Parameters

create a key 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 | Processes and Threads

Selecting Processes and Threads from the Debug menu displays process and thread information, and allows you to change the currently-active process or thread.

Dialog Box

The Processes and Threads dialog box displays a list of all processes currently being debugged. Under each process, all of its threads appear. You can expand or collapse the listing of the threads under each process by clicking the + (plus) or - (minus) buttons.

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 process and thread appear in bold type.

To make a new process or thread active, click on it and click Set. Click Close to close this dialog box. You can also double-click on a thread to make it active and close the dialog box.

Additional Information

For more details, and for other methods of displaying or controlling processes and threads, see Controlling Processes and Threads.


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 Loaded image column gives the name of the executable, driver, or DLL associated with this module.

The Symbols column tells the kind of symbols used by this module. Possible values include "None", "COFF", "CodeView", "PDB", "Export", "Deferred", and "Sym".

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.


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

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.


Help | Index

Selecting Index from the Help menu pops up this Help file and selects the Index tab.


Help | Search

Selecting Search from the Help menu pops up this Help file and selects the Search tab.


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.
 | Places a breakpoint at the current line, if the active window is a Source window or the Disassembly window. 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
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
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
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


Bug Check Codes

This reference 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.


Bug Check 0xA: IRQL_NOT_LESS_OR_EQUAL

The IRQL_NOT_LESS_OR_EQUAL bug check has value 0x0000000A. This signals that the 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 bug-ridden 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 bug-ridden 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 0x1E: KMODE_EXCEPTION_NOT_HANDLED

The KMODE_EXCEPTION_NOT_HANDLED bug check has value 0x0000001E. This signals 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 | Exception code that was not handled
2 | Address at which exception occurred
3 | Parameter 0 of exception
4 | Parameter 1 of exception

Cause

To interpret this error message, it is necessary to 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, which 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

As this bug check often does not display full stack information, obtaining a stack trace can be difficult. 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).

Buggy device driver or system service. In addition, a bug-ridden 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.

To get a stack trace if the normal stack tracing procedures fail:

  1. Use the KB (Display Stack Backtrace) debugger command to display parameters in the stack trace to locate the first parameter to NT!PspUnhandledExceptionInSystemThread. (This will not work on an Alpha processor, since function parameters are passed in registers a0 - a5 on such systems. See the debugger documentation for details.)
  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) debugger 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 debugger command to display the exception record, and use the .cxr debugger command to display the context record.
  4. After the .cxr command executes, use the KB (Display Stack Backtrace) debugger 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.

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 0x24: NTFS_FILE_SYSTEM

The NTFS_FILE_SYSTEM bug check has value 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 error message includes the following four parameters in order of appearance:

Parameter | Description
1 | Source file and line number
2 | Address of the exception record (optional)
3 | Address of the context record (optional)
4 | Address where the original exception occurred (optional)

All bug checks due to problems with the file system have encoded in their first parameter the source file and the line number within the source file that generated the bug check. The high 16 bits (the first four hexadecimal digits after the 0x) identify the source file number, while the lower 16 bits (the last four hexadecimal digits of the parameter) identify the source line in the file where the bug check occurred.

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

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

Resolving a nonpaged pool memory depletion problem: Either increase the amount of installed random access memory (RAM), which increases the quantity of nonpaged pool memory available to the kernel, or reduce the number of files on the SFM volume.


Bug Check 0x2E: DATA_BUS_ERROR

The DATA_BUS_ERROR bug check has value 0x0000002E. This typically indicates that a parity error in system memory has been detected. This error is almost always caused by a hardware problem — a configuration issue, defective hardware, or incompatible hardware. The exception is when a device driver has accessed an address in the 0x8xxxxxxx range that does not exist (does not have a physical address mapping).

Parameters

The four parameters listed in the message are defined in order of appearance as follows:

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

The most common cause of this error is a hardware problem, usually related to defective RAM, Level 2 (L2) RAM cache, or video RAM. Bug check 0x2E usually occurs after the installation of faulty hardware or when existing hardware fails.

Hard disk corruption could also cause this error.

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 following items: firmware on reduced instruction set computing (RISC) systems, BIOS revisions on the motherboard, 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 of 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.

If you have the wrong revision of the CPU module on an Alpha computer, you might also encounter this error This error has been observed on an Alpha XL 266 using a revision of B02 or earlier. To resolve the error, update your system to a CPU module with a higher revision than B02.


Bug Check 0x35: NO_MORE_IRP_STACK_LOCATIONS

The NO_MORE_IRP_STACK_LOCATIONS bug check has value 0x00000035. This signifies that 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 0x3F: NO_MORE_SYSTEM_PTES

The NO_MORE_SYSTEM_PTES bug check has value 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

None

Cause

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

Modify the registry to increase the total number of system PTEs.


Bug Check 0x50: PAGE_FAULT_IN_NONPAGED_AREA

The PAGE_FAULT_IN_NONPAGED_AREA bug check has value 0x00000050. This signals 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 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of 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 bug-ridden 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 bug-ridden 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 0x58: FTDISK_INTERNAL_ERROR

The FTDISK_INTERNAL_ERROR bug check has value 0x00000058. This is issued if the system is booted from the wrong copy of a mirrored partition.

Parameters

None.

Cause

This often occurs if the primary partition was revived. The mirror appears to support a boot, but it does not.

Resolving the Problem

Reboot the system from the shadow partition.


Bug Check 0x76: PROCESS_HAS_LOCKED_PAGES

The PROCESS_HAS_LOCKED_PAGES bug check has value 0x00000076. This signifies 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 (zero)
2 | Process address
3 | Number of locked pages
4 | 0 (zero), or pointer to driver stacks

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 path, set a TrackLockedPages key equal to DWORD 1, then reboot. The system will then save stack traces, and if the driver commits the same error, the system will issue bug check 0xCB, DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS. This will identify the guilty driver.

See Also

Bug Check 0xCB


Bug Check 0x77: KERNEL_STACK_INPAGE_ERROR

The KERNEL_STACK_INPAGE_ERROR bug check has value 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 and third parameters are zero, the following definitions should be used:

Parameter | Description
1 | 0
2 | Value found in stack where signature should be
3 | 0
4 | Address of signature on kernel stack

Otherwise, use the following definitions:

Parameter | Description
1 | Status code
2 | I/O status code
3 | Page file number
4 | Offset into page file

Cause

Frequently, the cause of this error can be determined from the second parameter, the I/O status code. 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.

If the first and third parameters are zero, the stack signature in the kernel stack was not found. This error is caused by defective hardware.

Another common cause of this error message is 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 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.


Bug Check 0x79: MISMATCHED_HAL

The MISMATCHED_HAL bug check has value 0x00000079. This signifies 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 | Description
1 | Release level of ntoskrnl.exe | Release level of hal.dll | PRCB release level mismatch
2 | Build type of ntoskrnl.exe | Build type of hal.dll | Build type mismatch
3 | Machine type detected during boot | Machine type supported by HAL | Micro Channel 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

When Parameter 1 equals three, there is an Micro Channel Architecture (MCA) mismatch between the machine and the HAL. (Micro Channel computers require a Micro Channel-specific HAL.) A machine type of "2" indicates MCA.

Cause

This error often results from the user manually updating either ntoskrnl.exe or hal.dll.

Bug check 0x79 can occur if either the ntoskrnl.exe or hal.dll files have been manually updated. 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). Additionally, 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.

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 value 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
2 | 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 | 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 second parameter, the I/O status code. 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.


Bug Check 0x7B: INACCESSIBLE_BOOT_DEVICE

The INACCESSIBLE_BOOT_DEVICE bug check has value 0x0000007B. This indicates that Windows has lost access to the system partition during startup. This error always occurs while the system is starting and cannot be debugged because it generally occurs before the operating system has loaded the debugger.

Parameters

The four parameters listed in the message are defined, in order of appearance, as follows:

Parameter | Description
1 | Address of a Unicode string data structure representing the Advanced RISC Computing (ARC) specification name of the device from which the startup was being attempted
2 | Pointer to ARC name string in memory
3 | 0
4 | 0

The first parameter typically contains two separate pieces of data. For example, if the parameter is 0x00800020, 0x0020 is the actual length of the Unicode string and 0x0080 is the maximum name string length. The next parameter contains the address of the buffer. This address is in system space, so the high-order bit is set.

If the file system that is 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, the following parameter definition applies:

Parameter | Description
1 | Address of the device object that could not be mounted
2 | 0
3 | 0
4 | 0

The value of the first argument determines whether the argument is a pointer to an ARC name string (ARC names are a generic method of identifying devices within the ARC environment) or a device object, because a Unicode string never has an odd number of bytes, and a device object always has a Type code of 0003.

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

Resolving a failed boot device problem: If this happens on x86 systems, the boot.ini file must be edited; on Alpha systems, system Setup must be run.

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.

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 command on the debugger. Verify that the following drivers were loaded: disk, classpnp, ftdisk, partmgr, and either FAT or NTFS.

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.

If you know how to read through !devnode debugger extension output, and you know what your boot devices are, you can get further. 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.

kd> lm            //  Displays loaded modules

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)   \\ntstress\symbols\x86\1915\symbols\exe\ntoskrnl.dbg
80540000 80546f20   ksecdd       (deferred)
80547000 80554620   cnss         (deferred)
80555000 80579000   ndis         (deferred)


Bug Check 0x7F: UNEXPECTED_KERNEL_MODE_TRAP

The UNEXPECTED_KERNEL_MODE_TRAP bug check has value 0x0000007F. This signifies that a trap was generated by the Intel CPU which the kernel did not catch.

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. This is almost always caused by hardware problems.

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.

Resolving the Problem

To debug this problem, use the KB (Display Stack Backtrace) debugger command to find the trap frame address. Use the .trap debugger command to format the frame. (On Intel platforms, this frame is associated with the procedure NT!KiTrap.)

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, especially the memory scanner, 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 adapter card contacts are clean.

If the error appears on a newly installed system, check the availability of updates for the following items: firmware on RISC systems and BIOS revisions on the motherboard, 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 0x9F: DRIVER_POWER_STATE_FAILURE

The DRIVER_POWER_STATE_FAILURE bug check has value 0x0000009F. This signifies 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 | Description
1 | Pointer to the device object | Reserved | Reserved | The device object being freed still has an outstanding power request which it has not completed
2 | Pointer to the target device object | Pointer to the device object | Reserved | The device object completed the IRP for the system power state request, but failed to call PoStartNextPowerIrp
3 | 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
100 | 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
101 | 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


Bug Check 0xBE: ATTEMPTED_WRITE_TO_READONLY_MEMORY

The ATTEMPTED_WRITE_TO_READONLY_MEMORY bug check has value 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 PUNICODE_STRING parameter of KiBugCheckDriver.


Bug Check 0xC1: SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION

The SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION bug check has value 0x000000C1. This signals 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 | Description
Address that the driver tried to free | Reserved | 0 | 0x20 | Attempt to free pool which was not allocated
Address that the driver tried to free | Bytes requested | Bytes calculated | 0x21, 0x22 | Attempt to free a bad address
Address that the driver tried to free | Address where bits are corrupted | Reserved | 0x23 | Freeing an address when nearby bytes on same page have been corrupted
Address that the driver tried to free | Address where bits are corrupted | Reserved | 0x24 | Freeing an address when bytes after end of allocation have been overwritten
Current IRQL | Pool type | Number of bytes | 0x30 | Attempt to allocate pool at incorrect IRQL
Current IRQL | Pool type | Address that the driver tried to free | 0x31 | Attempt 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 value 0x000000C2. This signifies 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 | Description
0x01, 0x02, or 0x04 | Pointer to pool header | First part of pool header contents | 0 | Pool header has been corrupted
0x06 | Reserved | Pointer to pool header | Pool header contents | Attempt to free pool which was already freed
0x07 | Reserved | Pointer to pool header | 0 | Attempt to free pool which was already freed
0x08 | Current IRQL | Pool type | Size of allocation | Attempt to allocate pool at an invalid IRQL
0x09 | Current IRQL | Pool type | Address of pool | Attempt to free pool at an invalid IRQL
0x40 | Starting address | Start of system address space | 0 | Attempt to free kernel pool at user-mode address
0x41 | Starting address | Physical page frame | Highest physical page frame | Attempt to free a nonallocated nonpaged pool address
0x50 | Starting address | Start offset in pages from beginning of paged pool | Size of paged pool, in bytes | Attempt to free a nonallocated paged pool address
0x99 | Address being freed | 0 | 0 | Attempt to free pool with invalid address (or corruption in pool header)
0x9A | Pool type | Number of bytes requested | Pool tag | Allocation request was marked MUST_SUCCEED (this is never permitted)

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 the Driver Verifier to obtain more information about these errors. For details, consult the Driver Verifier section of the Windows DDK.


Bug Check 0xC4: DRIVER_VERIFIER_DETECTED_VIOLATION

The DRIVER_VERIFIER_DETECTED_VIOLATION bug check has value 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 | Description
0x00 | Current IRQL | Pool type | 0 | Call to allocate zero bytes (minimum allocation one byte)
0x01 | Current IRQL | Pool type | Number of bytes | Attempt to allocate paged memory at an IRQL above APC_LEVEL
0x02 | Current IRQL | Pool type | Number of bytes | Attempt to allocate nonpaged memory at an IRQL above DISPATCH_LEVEL
0x10 | Bad Address | 0 | 0 | Trying to free an address that was not returned from an allocate call
0x11 | Current IRQL | Pool type | Address of pool | Attempt to free paged pool at an IRQL above APC_LEVEL
0x12 | Current IRQL | Pool type | Address of pool | Attempt to free nonpaged pool at an IRQL above DISPATCH_LEVEL
0x13 or 0x14 | Reserved | Pointer to pool header | Pool header contents | Attempt to free memory pool which was already freed
0x15 | Timer entry | Pool type (-1 for special pool) | Pool address being freed | Attempt to free pool which contains an active timer
0x16 | Reserved | Pool address | 0 | Attempt to free pool at bad address, passing invalid parameters to memory routine
0x17 | Resource entry | Pool type (-1 for special pool) | Pool address being freed | Attempt to free pool which contains an active ERESOURCE
0x18 | Timer entry | -1 | DLL base address | Attempt to unload a driver whose DLL contains an active timer
0x19 | Resource entry | -1 | DLL base address | Attempt to unload a driver whose DLL contains an active ERESOURCE
0x30 | Current IRQL | Requested IRQL | 0 | Passing an invalid parameter to KeRaiseIrql (either a value lower than the current IRQL, or a value higher than HIGH_LEVEL) — this may result from using an uninitialized parameter
0x31 | Current IRQL | Requested IRQL | 0 | Passing an invalid parameter to KeLowerIrql (either a value higher than the current IRQL, or a value higher than HIGH_LEVEL) — this may result from using an uninitialized parameter
0x32 | Current IRQL | Spin lock address | 0 | Call to KeReleaseSpinLock at an IRQL other than DISPATCH_LEVEL (perhaps due to double-release of spin lock)
0x33 | Current IRQL | Fast mutex address | 0 | Attempt to acquire fast mutex at an IRQL above APC_LEVEL
0x34 | Current IRQL | Fast mutex address | 0 | Attempt to release fast mutex at an IRQL other than APC_LEVEL
0x35 | Current IRQL | Spin lock address | Old IRQL | Kernel is releasing a spin lock when not at DISPATCH_LEVEL
0x36 | Current IRQL | Spin lock number | Old IRQL | Kernel is releasing a queued spin lock when not at DISPATCH_LEVEL
0x37 | Current IRQL | Thread APC disable count | Resource | A resource is being acquired, but APCs are not disabled
0x38 | Current IRQL | Thread APC disable count | Resource | A resource is being released, but APCs are not disabled
0x39 | Current IRQL | Thread APC disable count | Mutex | A mutex is being acquired "unsafe", but IRQL is not APC_LEVEL on entry
0x3A | Current IRQL | Thread APC disable count | Mutex | A mutex is being released "unsafe", but IRQL is not APC_LEVEL on entry
0x3B | Current IRQL | Object to wait on | Timeout parameter | Call to KeWaitXxx at an IRQL of DISPATCH_LEVEL or higher
0x3C | Handle passed to routine | Object type | 0 | Call to ObReferenceObjectByHandle with a bad handle
0x40 | Current IRQL | Spin lock address | 0 | Call to KeAcquireSpinLockAtDpcLevel at an IRQL other than DISPATCH_LEVEL
0x41 | Current IRQL | Spin lock address | 0 | Call to KeReleaseSpinLockFromDpcLevel at an IRQL other than DISPATCH_LEVEL
0x42 | Current IRQL | Spin lock address | 0 | Call to KeAcquireSpinLock at an IRQL above DISPATCH_LEVEL
0x6F | MDL address | Physical page being locked | Highest physical page in the system | Page passed to MmProbeAndLockPages was not in 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 | Call to MmProbeAndLockPages at an IRQL above DISPATCH_LEVEL
0x71 | Current IRQL | MDL address | Process address | Call to MmProbeAndLockProcessPages at an IRQL above DISPATCH_LEVEL
0x72 | Current IRQL | MDL address | Process address | Call to 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 | Call to MmMapIoSpace at an IRQL above DISPATCH_LEVEL
0x74 | Current IRQL | MDL address | Access mode | Call to MmMapLockedPages in kernel mode at an IRQL above DISPATCH_LEVEL
0x75 | Current IRQL | MDL address | Access mode | Call to MmMapLockedPages in user mode at an IRQL above APC_LEVEL
0x76 | Current IRQL | MDL address | Access mode | Call to MmMapLockedPagesSpecifyCache in kernel mode at an IRQL above DISPATCH_LEVEL
0x77 | Current IRQL | MDL address | Access mode | Call to MmMapLockedPagesSpecifyCache in user mode at an IRQL above APC_LEVEL
0x78 | Current IRQL | MDL address | 0 | Call to MmUnlockPages at an IRQL above DISPATCH_LEVEL
0x79 | Current IRQL | Virtual address being unmapped | MDL address | Call to MmUnmapLockedPages in kernel mode at an IRQL above DISPATCH_LEVEL
0x7A | Current IRQL | Virtual address being unmapped | MDL address | Call to MmUnmapLockedPages in user mode at an IRQL above APC_LEVEL
0x7B | Current IRQL | Virtual address being unmapped | Number of bytes | Call to MmUnmapIoSpace at an IRQL above APC_LEVEL
0x7C | MDL address | MDL flags | 0 | Call to MmUnlockPages passed an MDL whose pages were never successfully locked
0x7D | MDL address | MDL flags | 0 | Call to MmUnlockPages passed an MDL whose pages are from nonpaged pool (these should never be unlocked)
0x80 | Current IRQL | Event address | 0 | Call to KeSetEvent at an IRQL above DISPATCH_LEVEL
0x81 | MDL address | MDL flags | 0 | Call to MmMapLockedPages without MDL_MAPPING_CAN_FAIL
0x82 | MDL address | MDL flags | 0 | Call to MmMapLockedPagesSpecifyCache without MDL_MAPPING_CAN_FAIL
0x90 | Reserved | Reserved | Reserved | A 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 Allocation Tracking option of Driver Verifier is active.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Description
0x51 | Base address of allocation | Corrupt address | Number of charged bytes | Driver is trying to free memory after having written past the end of the allocation
0x52 | Base address of allocation | Reserved | Number of charged bytes | Driver is trying to free memory after having written past the end of the allocation
0x53, 0x54, or 0x59 | Base address of allocation | Reserved | Reserved | Driver is trying 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 | Driver did not free all memory pools prior to unload
0x61 | Bytes allocated from paged pool | Bytes allocated from nonpaged pool | Total number of unfreed allocations | Driver is allocating pool (in another thread) at the same time as it is unloading

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 | Description
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 _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

If you are a system administrator, you should unload the driver if the problem persists. Turning Driver Verifier off will also stop these codes from occurring.

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> dc ViBadDriver l1; dc @$p+4 l1; du @$p

This will return the name of the driver causing the error.

Then use the !verifier extension:

kd> !verifier 3 drivername.sys

This will return information about the leaked memory allocations.

For full details on Driver Verifier, consult the Windows DDK.


Bug Check 0xC5: DRIVER_CORRUPTED_EXPOOL

The DRIVER_CORRUPTED_EXPOOL bug check has value 0x000000C5. This signifies 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

A driver has probably corrupted the system pool. This code is usually issued when the corruption was in a small allocation (less than PAGE_SIZE).

Resolving the Problem

To deal with this bug, 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.

See Also

Bug Check 0xD0


Bug Check 0xC6: DRIVER_CAUGHT_MODIFYING_FREED_POOL

The DRIVER_CAUGHT_MODIFYING_FREED_POOL bug check has value 0x000000C6. This signifies 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 | Zero: Read One: Write
3 | Zero: Kernel mode One: User mode
4 | Four

Comments

The faulty component will be displayed in the current kernel stack.


Bug Check 0xC7: TIMER_OR_DPC_INVALID

The TIMER_OR_DPC_INVALID bug check has value 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, consult the Windows DDK.


Bug Check 0xC9: DRIVER_VERIFIER_IOMANAGER_VIOLATION

The DRIVER_VERIFIER_IOMANAGER_VIOLATION bug check has value 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 | Description
0x01 | Address of IRP being freed | 0 | 0 | Attempt to free object whose type is not IO_TYPE_IRP
0x02 | Address of IRP being freed | 0 | 0 | Attempt to free IRP still associated with a thread
0x03 | Address of IRP being sent | 0 | 0 | Call to IoCallDriver with IRP Type not equal to IRP_TYPE
0x04 | Address of DeviceObject | 0 | 0 | Invalid device object passed to IoCallDriver
0x05 | Address of DeviceObject associated with offending driver | IRQL before IoCallDriver | IRQL after IoCallDriver | IRQL not preserved across call to driver dispatch routine
0x06 | IRP status | Address of IRP being completed | 0 | IoCompleteRequest called with status marked as pending or equal to -1
0x07 | Address of cancel routine | Address of IRP being completed | 0 | IoCompleteRequest called with cancel routine still set
0x08 | Address of DeviceObject | IRP major function code | Exception code | Invalid buffer passed to IoBuildAsynchronousFsdRequest
0x09 | Address of DeviceObject | I/O control code | Exception code | Invalid buffer passed to IoBuildDeviceIoControlRequest
0x0A | Address of DeviceObject | 0 | 0 | Device object with an already-initialized timer passed to IoInitializeTimer
0x0C | Address of IO status block | 0 | 0 | I/O status block passed to IRP is allocated on stack which has already unwound past that point
0x0D | Address of user event object | 0 | 0 | Event passed to IRP is allocated on stack which has already unwound past that point
0x0E | Current IRQL | Address of IRP | 0 | Call to IoCompleteRequest with IRQL above DPC

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 name of the driver which caused the error, along with the address in the driver's code where the error was detected.
  • 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.)

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 | Description
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 | Driver has attempted to detach from device object (specified), which is not attached to anything. This may occur if detach was called twice on the same device object.
0x203 | Fatal error | A driver has called IoCallDriver without setting the CancelRoutine in the IRP to NULL. (IRP specified.)
0x204 | Fatal error | Caller has passed in NULL as a DeviceObject. This is fatal. (IRP specified.)
0x205 | Fatal error | 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 | Caller has incorrectly forwarded an IRP (control field not zeroed). The driver should use IoCopyCurrentIrpStackLocationToNext or IoSkipCurrentIrpStackLocation. (IRP specified.)
0x207 | Fatal error | 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 | 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 | Caller of IoFreeIrp is freeing an IRP that is still in use. (Original IRP and IRP in use specified.)
0x20B | Fatal error | Caller of IoFreeIrp is freeing an IRP that is still in use. (IRP specified.)
0x20C | Fatal error | Caller of IoFreeIrp is freeing an IRP that is still queued against a thread. (IRP specified.)
0x20D | Fatal error | 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 | Any PNP IRP must have status initialized to STATUS_NOT_SUPPORTED. (IRP specified.)
0x20F | Non-fatal error | Any Power IRP must have status initialized to STATUS_NOT_SUPPORTED. (IRP specified.)
0x210 | Non-fatal error | Any WMI IRP must have status initialized to STATUS_NOT_SUPPORTED. (IRP specified.)
0x211 | Non-fatal error | 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 | Caller has trashed or has not properly copied the IRP's stack. (IRP specified.)
0x213 | Non-fatal error | Caller has changed the status field of an IRP it does not understand. (IRP specified.)
0x214 | Non-fatal error | Caller has changed the information field of an IRP it does not understand. (IRP specified.)
0x215 | Non-fatal error | 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 | Previously set IRP_MJ_PNP status has been converted to STATUS_NOT_SUPPORTED. (IRP specified.)
0x217 | Non-fatal error | FDO caller has not handled a required IRP. The FDO must either fail the IRP or set the IRP's status if it is not going change the IRP's status using a completion routine. (IRP specified.)
0x218 | Non-fatal error | FDO caller has responded to an IRP that is reserved for PDO use only. (IRP specified.)
0x219 | Non-fatal error | 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 | Previously set IRP_MJ_POWER status has been converted to STATUS_NOT_SUPPORTED. (IRP specified.)
0x21B | Non-fatal error | Driver has returned a suspicious status. This is probably due to an uninitialized variable bug in the driver. (IRP specified.)
0x21C | Warning | 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 | This 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, execute an LN command on 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 | IRP completion routines must be in nonpagable code, and this one is not. (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 | PDO has not responded to a required IRP. (IRP specified.)
0x22B | Non-fatal error | 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 | Caller has completed a IRP_MJ_PNP it didn't understand instead of passing it down. (IRP specified.)
0x22E | Non-fatal error | Caller has completed successful IRP_MJ_PNP instead of passing it down. (IRP specified.)
0x22F | Non-fatal error | Caller has completed 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 | Caller has completed a IRP_MJ_POWER it didn't understand instead of passing it down. (IRP specified.)
0x231 | Fatal error | Caller has completed successful IRP_MJ_POWER instead of passing it down. (IRP specified.)
0x232 | Non-fatal error | Caller has completed 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 | Fatal error | The version field of the query capabilities structure in a query capabilities IRP was not properly initialized. (IRP specified.)
0x234 | 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 | 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 | Fatal error | 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 | Description
0x23C | Fatal error | A driver has completed an IRP without setting the cancel routine in the IRP to NULL. (IRP specified.)
0x23D | Fatal error | A driver has returned STATUS_PENDING but did not mark the IRP pending via a call to IoMarkIrpPending. (IRP specified.)
0x23E | 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 | 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.

Cause

See the description of each code in the Parameters section for a description of the cause.

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, consult the Windows DDK.


Bug Check 0xCA: PNP_DETECTED_FATAL_ERROR

The PNP_DETECTED_FATAL_ERROR bug check has value 0x000000CA. This signifies 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 | Description
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 | Reserved | Reserved | Invalid PDO. An API which requires a PDO has been called with one of the following: random memory, an FDO, or a PDO which hasn't been initialized (that is, it 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 value 0x000000CB. This signifies 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 | Calling address in driver that locked the pages
2 | Caller of the calling address in driver that locked the pages
3 | Pointer to MDL containing the locked pages
4 | Guilty driver's name (pointer to Unicode string)

If the guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver and in Parameter 4.

Comments

This bug check is issued only if the registry key \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\TrackLockedPages is equal to DWORD 1. If this key is not set, the system will issue the less-informative bug check 0x76, PROCESS_HAS_LOCKED_PAGES.

See Also

Bug Check 0x76


Bug Check 0xCC: PAGE_FAULT_IN_FREED_SPECIAL_POOL

The PAGE_FAULT_IN_FREED_SPECIAL_POOL bug check has value 0x000000CC. This signals 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 guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of 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 value 0x000000CD. This signals 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 guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of 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 value 0x000000CE. This signals 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 guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of 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 value 0x000000CF. This signals 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 guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.

Cause

The driver is referencing session space addresses from the system process context.

The driver probably queued an item to a system worker thread.


Bug Check 0xD0: DRIVER_CORRUPTED_MMPOOL

The DRIVER_CORRUPTED_MMPOOL bug check has value 0x000000D0. This signifies 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

A driver has probably corrupted the system pool. This code is usually issued when the corruption was in a large allocation (PAGE_SIZE or larger).

Resolving the Problem

To deal with this bug, 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 set the \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\ProtectNonPagedPool registry key equal to DWORD 1 and 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.)

See Also

Bug Check 0xC5


Bug Check 0xD1: DRIVER_IRQL_NOT_LESS_OR_EQUAL

The DRIVER_IRQL_NOT_LESS_OR_EQUAL bug check has value 0x000000D1. This signifies 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

Cause

This bug check is usually caused by drivers that have used improper addresses.

Resolving the Problem

To deal with this bug, use a kernel debugger to get a stack trace.


Bug Check 0xD3: DRIVER_PORTION_MUST_BE_NONPAGED

The DRIVER_PORTION_MUST_BE_NONPAGED bug check has value 0x000000D3. This signifies 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 guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.

Cause

This bug check is usually caused by drivers that have incorrectly marked code or data as pageable.

Resolving the Problem

To deal with this bug, 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 value 0x000000D4. This signifies 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 guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of 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 deal with this bug, 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, consult the Windows DDK.


Bug Check 0xD5: DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL

The DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL bug check has value 0x000000D5. This signals 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 guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of 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 value 0x000000D6. This signals 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 guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of 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 value 0x000000D7. This signifies 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 | 0: system is not Terminal Server 1: system is Terminal Server
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 value 0x000000D8. This signifies 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 guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.

Cause

This is usually caused by a driver not cleaning up 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 0xDB: DRIVER_CORRUPTED_SYSPTES

The DRIVER_CORRUPTED_SYSPTES bug check has value 0x000000DB. This signifies 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

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 path, set a TrackPtes key equal to DWORD 1, 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 value 0x000000DC. This signifies 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 value 0x000000DE. This signifies 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 0xE1: WORKER_THREAD_RETURNED_AT_BAD_IRQL

The WORKER_THREAD_RETURNED_AT_BAD_IRQL bug check has value 0x000000E1. This signifies 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 (ought to have been zero)
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 following kernel 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 value 0x000000E2. This signifies 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 the debugger documentation.


Bug Check 0xE3: RESOURCE_NOT_OWNED

The RESOURCE_NOT_OWNED bug check has value 0x000000E3. This signifies 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 value 0x000000E4. This signifies 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 value 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.

Parameter 1 | Description
0x03 | The driver freed the same DMA common buffer twice.
0x04 | The driver freed the same DMA adapter channel twice.
0x05 | The driver freed the same DMA map register twice.
0x06 | The driver freed the same DMA scatter-gather list twice.
0x0E | The driver attempted a DMA transfer without locking the buffer. The buffer in question was in paged memory.
0x0F | The driver or the hardware wrote past the end of its allocated DMA buffer.
0x18 | The driver attempted a DMA operation using an adapter that was already released and no longer exists.
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 contained in this MDL.
0x1D | The driver attempted to map an address that was already mapped.

Cause

See the description of each code in the Parameters section for a description of the cause.

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.

The Driver Verifier DMA Verification option is only available in Windows XP and later. For full details on Driver Verifier, consult the Windows DDK.


Bug Check 0xF1: SCSI_VERIFIER_DETECTED_VIOLATION

The SCSI_VERIFIER_DETECTED_VIOLATION bug check has value 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 | Description
0x1000 | First argument passed | Second argument passed | Reserved | Miniport passed bad arguments to ScsiPortInitialize.
0x1001 | Delay, in microseconds | Reserved | Reserved | Miniport 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 | Miniport routine called by the port driver took longer than 0.5 second to execute. (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 | Miniport completed a request more than once.
0x1004 | Address of the SRB | Address of miniport's HW_DEVICE_EXTENSION | Reserved | Miniport completed a request with an invalid SRB status.
0x1005 | Address of miniport's HW_DEVICE_EXTENSION | Address of LOGICAL_UNIT_EXTENSION | Reserved | Miniport 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 | Miniport 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 miniport still has outstanding requests.

Cause

See the description of each code in the Parameters section for an explanation of the cause.

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.

The Driver Verifier SCSI Verification option is only available in Windows XP and later. For full details on Driver Verifier, consult the Windows DDK.


Bug Check 0xC000021A: STATUS_SYSTEM_PROCESS_TERMINATED

The STATUS_SYSTEM_PROCESS_TERMINATED bug check has value 0xC000021A. This means that an error has occurred in a crucial user-mode subsystem.

Parameters

The error message includes the following three parameters, in order of appearance:

Parameter | Description
1 | Status code
2 | 0
3 | 0

For information about all possible status codes that might be returned, see the file ntstatus.h in the Windows DDK.

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 value 0xC0000221. This indicates that a driver or a system DLL has been corrupted.

Parameters

This bug check will display a descriptive text message.

Typically, 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.

This can also be caused by 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, start from an MS-DOS startup disk and copy the file from the original source onto the hard disk. If the partition is NTFS, 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.


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.