- Debugging Device Installations with the Kernel Debugger (KD)
- Local Kernel-Mode Debugging
- Setting Up Local Kernel-Mode Debugging
- Starting the Debugging Session
- Using WinDbg
- Using KD
- Commands That Are Not Available
- Commands That Are Available
- Difficulties in Performing Local Kernel Debugging
- LiveKD
- Debug Windows Drivers — Step by Step Lab (Echo Kernel-Mode)
- Lab objectives
- Lab setup
- Section 1: Connect to a kernel mode WinDbg session
- Configure kernel–mode debugging using ethernet
- Section 4: Install the KMDF echo driver sample on the target system
- Section 5: Use WinDbg to display information about the driver
- Section 6: Displaying Plug and Play device tree information
- Section 8: Viewing variables and call stacks
- Section 9: Displaying processes and threads
- Processes
- Viewing the saved IRQL
- Ending the WinDbg session
Debugging Device Installations with the Kernel Debugger (KD)
Starting with Windows Vista, when the Plug and Play (PnP) manager detects a new device in the system, the operating system starts the device installation host process (DrvInst.exe) to search for and install a driver for the device.
Because device installation occurs within this user-mode process, it is usually easiest to use a user-mode debugger as described in Debugging Device Installations with a User-mode Debugger. In some cases, however, it might be helpful to use the kernel debugger (KD) to monitor the user-mode device installation process.
For example, by using KD while debugging the user-mode device installation, you can do the following:
Simultaneously debug a kernel-mode issue by using !devnode, !devobj, !drvobj, !irp, and other KD extensions.
Monitor other user-mode processes without managing multiple debuggers by using the KD extensions !process or .process /p.
For more information about KD and other debugging tools, see Windows Debugging.
The DebugInstall registry value specifies the type of device installation debugging support enabled on the system. For more information about this registry value, see Enabling Support for Debugging Device Installations.
When the DebugInstall registry value is set to 1, DrvInst.exe will first check that the kernel debugger is both enabled and currently attached before it breaks into the debugger. After this break is made, breakpoints can be set in the user-mode modules of the current process. For example:
This sets a breakpoint on the routine SETUPAPI!SetupDiCallClassInstaller for the current process only.
For the developer of a driver package, it is usually most desirable to debug the actions of a class installer or co-installer DLL during the installation of a device. However, when DrvInst.exe breaks into the debugger, any class installer or co-installer DLLs from the driver package will not have been loaded. Although the user-mode debuggers support the ability to set a debugger exception when a user-mode module is loaded into the process with the «sx e ld» command, the kernel debugger only supports kernel-mode modules with that command.
The following code example shows how a «Debugger Command Program» monitors the loading of a specific class installer or co-installer into the current process. In this example, the debugger command program will set a breakpoint on the main entry point (CoInstallerProc) of the Mycoinst.dll co-installer:
When executed, the debugger command program will check the list of modules loaded into the current process for Mycoinst.dll. After this co-installer DLL is loaded, the debugger will set a breakpoint (with a well-known breakpoint ID) on the CoInstallerProc entry point function.
Starting from the debug break initiated by the DrvInst.exe host process, you should first set a breakpoint on the return address of the call where DrvInst.exe broke into the kernel debugger. This breakpoint will clear all breakpoints set during the device installation and continue execution:
Next, you should set some breakpoints within the process to allow the commands in the debugger command program to execute at the appropriate time during device installation.
To make sure that the breakpoint for the class installer or co-installer DLL entry point is set before the function is invoked for device installation, the debugger command program should be executed anytime a new DLL is loaded into the current process, that is, after a call to LoadLibraryExW returns:
Rather than executing the program on every LoadLibraryEx call within the process (bp[0x10]), the developer can restrict it to execute only when class installer and co-installer DLLs are loaded into the process. Because SetupDiCallClassInstaller is the routine that invokes class installers and co-installers that are registered for a device, these DLLs will be loaded into the process during that call.
Because no assumptions should be made about when these DLLs will be unloaded from the DrvInst.exe host process, you must make sure the breakpoints can handle locating the DLL entry points during any calls that are made to SetupDiCallClassInstaller from the DrvInst.exe host process.
The breakpoint to execute the debugger command program (bp[0x10]) is initially disabled. It is enabled whenever SetupDiCallClassInstaller is invoked (bp[0x11]), and execution continues. The debugger command program (bp[0x10]) is again disabled when SetupDiCallClassInstaller returns by setting a breakpoint on the return address of that routine itself (bp[0x12]).
Be aware that the breakpoint that disables the debugger command program also clears itself and continues execution until SetupDiCallClassInstaller is called again or until the installation program completes and all breakpoints are cleared (bp[0x13]).
When execution begins after the above breakpoints are set, the process will break on each call to mycoinst!CoInstallerProc. This allows you to debug the execution of the class installer or co-installer DLL during core device installation.
The default time period for an installation process to complete is 5 minutes. If the process does not complete within the given time period, the system assumes that the process has stopped responding, and it is terminated.
The default timeout restriction placed on device installations is still in effect while the process is being debugged through the kernel debugger. Because execution of all programs on the system is stopped while broken into the debugger, the amount of time taken by the installation process is tracked the same as it would be on a system that is not being debugged.
Local Kernel-Mode Debugging
Debugging Tools for Windows supports local kernel debugging. This is kernel-mode debugging on a single computer. In other words, the debugger runs on the same computer that is being debugged.
Setting Up Local Kernel-Mode Debugging
Starting the Debugging Session
Using WinDbg
Open WinDbg as Administrator. On the File menu, choose Kernel Debug. In the Kernel Debugging dialog box, open the Local tab. Select OK.
You can also start a session with WinDbg by opening a Command Prompt window as Administrator and entering the following command:
windbg -kl
Using KD
Open a Command Prompt window as Administrator, and enter the following command:
kd -kl
Commands That Are Not Available
Not all commands are available in a local kernel debugging session. Typically, you cannot use any command that causes the target computer to stop, even momentarily, because you cannot resume operation.
In particular, you cannot use the following commands:
Execution commands, such as g (Go), p (Step), t (Trace), wt (Trace and Watch Data), tb (Trace to Next Branch), gh (Go with Exception Handled), and gn (Go with Exception Not Handled)
Shutdown and dump file commands, such as .crash, .dump, and .reboot
Breakpoint commands, such as bp, bu, ba, bc, bd, be, and bl
Register display commands, such as r and variations
Stack trace commands, such as k and variations
If you are performing local kernel debugging with WinDbg, all of the equivalent menu commands and buttons are also unavailable.
Commands That Are Available
All memory input and output commands are available. You can freely read from user memory and kernel memory. You can also write to memory. Make sure that you do not write to the wrong part of kernel memory, because it can corrupt data structures and frequently causes the computer to stop responding (that is, crash).
Difficulties in Performing Local Kernel Debugging
Local kernel debugging is a very delicate operation. Be careful that you do not corrupt or crash the system.
One of the most difficult aspects of local kernel debugging is that the machine state is constantly changing. Memory is paged in and out, the active process constantly changes, and virtual address contexts do not remain constant. However, under these conditions, you can effectively analyze things that change slowly, such as certain device states.
Kernel-mode drivers and the Windows operating system frequently send messages to the kernel debugger by using DbgPrint and related functions. These messages are not automatically displayed during local kernel debugging. You can display them by using the !dbgprint extension.
LiveKD
The LiveKD tool simulates local kernel debugging. This tool creates a «snapshot» dump file of the kernel memory, without actually stopping the kernel while this snapshot is made. (Therefore, the snapshot might not actually show a single instant state of the computer.)
LiveKD is not part of the Debugging Tools for Windows package. You can download LiveKd from the Windows Sysinternals site.
Debug Windows Drivers — Step by Step Lab (Echo Kernel-Mode)
This lab introduces the WinDbg kernel debugger. WinDbg is used to debug the echo kernel mode sample driver code.
Lab objectives
This lab includes exercises that introduce the debugging tools, teach common debugging commands, illustrate the use of break points, and show the use of the debugging extensions.
In this lab, a live kernel debug connection is used to explore the following:
- Use the Windows debugger commands
- Use standard commands (Call stacks, variables, threads, IRQL)
- Use advanced driver debugging commands (!commands)
- Use symbols
- Set breakpoints in live debugging
- View call stacks
- Display the Plug and Play device tree
- Work with thread and process context
Note When working with the Windows debugger, there are two types of debugging that can be performed — user or kernel mode debugging.
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.
Kernel mode — Kernel mode is the processor access mode in which the operating system and privileged programs run. Kernel mode code has permission to access any part of the system, and is not restricted like user mode code. It can gain access to any part of any other process running in either user mode or kernel mode. Much of the core OS functionality and many hardware device drivers run in kernel mode.
This lab will focus on kernel mode debugging, as that is the method used to debug many device drivers.
This exercise covers debug commands that are frequently used during both user-mode and kernel-mode debugging. The exercise also covers debug extensions (sometimes called «!commands») that are used for kernel-mode debugging.
Lab setup
You will need the following hardware to be able to complete the lab.
- A laptop or desktop computer (host) running Windows 10
- A laptop or desktop computer (target) running Windows 10
- A network hub/router and network cables to connect the two PCs
- Access to the internet to download symbol files
You will need the following software to be able to complete the lab.
- Visual Studio
- Windows Software Development Kit (SDK) for Windows 10
- Windows Driver Kit (WDK) for Windows 10
- The sample echo driver for Windows 10
The lab has the following eleven sections.
Section 1: Connect to a kernel mode WinDbg session
In Section 1, you will configure network debugging on the host and target system.
The PCs in this lab need to be configured to use an Ethernet network connection for kernel debugging.
This lab uses two PCs. Windows debugger runs on the host system and the KMDF Echo driver runs on the target system.
Use a network hub/router and network cables to connect the two PCs.
To work with kernel mode applications and use WinDbg, we recommend that you use the KDNET over Ethernet transport. For information about how to use the Ethernet transport protocol, see Getting Started with WinDbg (Kernel-Mode). For more information about setting up the target computer, see Preparing a Computer for Manual Driver Deployment and Setting Up KDNET Network Kernel Debugging Automatically.
Configure kernel–mode debugging using ethernet
To enable kernel mode debugging on the target system, perform the following steps.
On the target system
- Open a command prompt on the target system and use the ping command to confirm network connectivity between the two systems. Use the actual IP address of the host system you recorded instead of 169.182.1.1 that is shown in the sample output.
Enable kernel mode debugging on the target system by completing the following steps.
Before using BCDEdit to change boot information you may need to temporarily suspend Windows security features such as BitLocker and Secure Boot on the test PC. Re-enable these security features when testing is complete and appropriately manage the test PC, when the security features are disabled.
On the target computer, open a Command Prompt window as Administrator. Enter this command to enable debugging.
Type this command to enable test signing.
Type this command to set the IP address of the host system. Use the IP address of the host system that you recorded earlier, not the one shown.
Warning To increase the security of the connection and decrease the risk of the random client debugger connection requests, consider using an auto generated random key. For more information, see Setting Up KDNET Network Kernel Debugging Automatically.
Type this command to confirm that the dbgsettings they are set properly.
Note
Firewalls and debuggers
If you receive a pop-up message from the firewall, and you wish to use the debugger, check all three of the boxes.
On the target system
Reboot the target system.
Section 2: Kernel mode debugging commands and techniques
In Section 2, you will use debug commands to display information about the target system.
Section 3: Download and build the KMDF echo driver
In Section 3, you will download and build the KMDF echo driver.
Typically, you would be working with your own driver code when you use WinDbg. To become familiar with WinDbg operation, the KMDF Template «Echo» sample driver is used. With the source code available, it will also be easier to understand the information that is displayed in WinDbg. In addition, this sample is used to illustrate how you can single step through native kernel mode code. This technique can be very valuable for debugging complex kernel mode code issues.
To download and build the Echo sample audio driver, perform the following steps.
Download and extract the KMDF Echo sample from GitHub
You can use a browser to view the echo sample in GitHub here:
You can read about the sample here:
You can browse all of the Windows driver samples here:
The KMDF Echo sample is located in the general folder.
a. This lab, shows how to download the driver samples in one zip file.
b. Download the master.zip file to your local hard drive.
c. Select and hold (or right-click) Windows-driver-samples-master.zip, and choose Extract All. Specify a new folder, or browse to an existing one that will store the extracted files. For example, you could specify C:\DriverSamples\ as the new folder into which the files are extracted.
d. After the files are extracted, navigate to the following subfolder.
Open the driver solution in Visual Studio
In Microsoft Visual Studio, select File > Open > Project/Solution. and navigate to the folder that contains the extracted files (for example, C:\DriverSamples\general\echo\kmdf). Double-click the kmdfecho solution file to open it.
In Visual Studio, locate the Solution Explorer. (If this is not already open, choose Solution Explorer from the View menu.) In Solution Explorer, you can see one solution that has three projects.
Set the sample’s configuration and platform
In Solution Explorer, select and hold (or right-click) Solution ‘kmdfecho’ (3 projects), and choose Configuration Manager. Make sure that the configuration and platform settings are the same for the three projects. By default, the configuration is set to «Win10 Debug», and the platform is set to «Win64» for all the projects. If you make any configuration and/or platform changes for one project, you must make the same changes for the remaining three projects.
Set the runtime library
Set the runtime library — Open the echo driver’s property page and locate C/C++ > Code Generation. Change Runtime Library from DLL version to non DLL version. Without this setting, you have to install the MSVC runtime to the target computer separately.
Check driver signing
Also on the driver’s properties make sure Driver Signing > Sign Mode is set to “Test Sign”. This is required because Windows requires that drivers are signed.
Build the sample using Visual Studio
In Visual Studio, select Build > Build Solution.
If all goes well, the build windows should display a message indicating that the build for all three projects succeeded.
Locate the built driver files
In File Explorer, navigate to the folder that contains the extracted files for the sample. For example, you would navigate to C:\DriverSamples\general\echo\kmdf, if that’s the folder you specified earlier. Within that folder, the location of the compiled driver files varies depending on the configuration and platform settings that you selected in the Configuration Manager. For example, if you left the default settings unchanged, then the compiled driver files will be saved to a folder named \x64\Debug for a 64 bit, debug build.
Navigate to the folder that contains the built files for the Autosync driver:
The folder should contain these files:
File | Description |
---|---|
Echo.sys | The driver file. |
Echo.inf | An information (INF) file that contains information needed to install the driver. |
In addition, the echoapp.exe file was built and it should be located here: C:\DriverSamples\general\echo\kmdf\exe\x64\Debug
File | Description |
---|---|
EchoApp.exe | A command prompt executable test file that communicates with the echo.sys driver. |
Locate a USB thumb drive or set up a network share to copy the built driver files and the test EchoApp from the host to the target system.
In the next section, you will copy the code to the target system, and install and test the driver.
Section 4: Install the KMDF echo driver sample on the target system
In Section 4, you will use devcon to install the echo sample driver.
The computer where you install the driver is called the target computer or the test computer. Typically, this is a separate computer from the computer on which you develop and build the driver package. The computer where you develop and build the driver is called the host computer.
The process of moving the driver package to the target computer and installing the driver is called deploying the driver.
Before you deploy a test signed driver, you must prepare the target computer by enabling test signing. You also need to locate the DevCon tool in your WDK installation and copy that to the target system.
To install the driver on the target system, perform the following steps.
-> On the target system
Enable test signed drivers
Enable the ability to run test signed drivers:
a. Open Windows Settings.
b. In Update and Security, select Recovery.
c. Under Advanced startup, select Restart Now.
d. When the PC reboots, select Startup options. In Windows 10, select Troubleshoot > Advanced options > Startup Settings , then select Restart button.
e. Select Disable driver signature enforcement by pressing the F7 key.
f. Reboot the target computer.
On the target system
On the target computer, select and hold (or right-click) the certificate file, and select Install, then follow the prompts to install the test certificate.
If you need more detailed instructions for setting up the target computer, see Preparing a Computer for Manual Driver Deployment.
-> On the target system
Install the driver
The following instructions show you how to install and test the sample driver. Here’s the general syntax for the devcon tool that you will use to install the driver:
The INF file required for installing this driver is echo.inf. The inf file contains the hardware ID for installing the echo.sys. For the echo sample the hardware ID is root\ECHO.
On the target computer, open a Command Prompt window as Administrator. Navigate to your driver package folder, and enter the following command:
devcon install echo.inf root\ECHO If you get an error message about devcon not being recognized, try adding the path to the devcon tool. For example, if you copied it to a folder called C:\Tools, then try using the following command:
c:\tools\devcon install echo.inf root\ECHO A dialog box will appear indicating that the test driver is an unsigned driver. Select Install this driver anyway to proceed.
В If you have any issues with the installation, check the following file for more information. %windir%\inf\setupapi.dev.log
After successfully installing the sample driver, you’re now ready to test it.
Examine the driver in Device Manager
On the target computer, in a Command Prompt window, enter devmgmt open Device Manager. In Device Manager, on the View menu, choose Devices by type. In the device tree, locate Sample WDF Echo Driver in the Sample Device node.
Test the driver
Type echoapp to start the test echo app to confirm that the driver is functional.
Section 5: Use WinDbg to display information about the driver
In Section 5, you will set the symbol path and use kernel debugger commands to display information about the KMDF echo sample driver.
View information about the driver by performing the following steps.
x ECHO!Echo* to display information about all of the symbols associated with echo driver that start with Echo.
The !lmi extension displays detailed information about a module. Type !lmi echo. Your output should be similar to the text shown below.
Use the !dh extension to display header information as shown below.
Setting the debug mask
Type the following to change the default debug bit mask so that all debug messages from the target system will be displayed in the debugger.
Some drivers will display additional information when the mask of 0xFFFFFFFF is used. Set the mask to 0x00000000 if you would like to reduce the amount of information that is displayed.
Use the dd command to display confirm the mask is set to display all of the debugger messages.
Section 6: Displaying Plug and Play device tree information
In Section 6, you will display information about the echo sample device driver and where it lives in the Plug and Play device tree.
Information about the device driver in the Plug and Play device tree can be useful for troubleshooting. For example, if a device driver is not resident in the device tree, there may an issue with the installation of the device driver.
For more information about the device node debug extension, see !devnode.
Section 7: Working with breakpoints and source code
In Section 7, you will set breakpoints and single step through kernel mode source code.
Note
Setting breakpoints using commands
To be able to step through code and check the values of variables in real time, we need to enable breakpoints and set a path to the source code.
Breakpoints are used to stop code execution at a particular line of code. You can then step forward in the code from that point, to debug that specific section of code.
To set a breakpoint using a debug command, use one of the following b commands.
Sets a breakpoint that will be active until the module it is in is unloaded.
Sets a breakpoint that is unresolved when the module is unloaded and re-enables when the module reloads.
Sets a breakpoint for a symbol. This command will use bu or bp appropriately and allows wildcards * to be used to set breakpoints on every symbols that matches (like all methods in a class).
For more information, see Source Code Debugging in WinDbg in the debugging reference documentation.
Source Mode is enabled in the current WinDbg session.
Add your local code location to the source path by typing the following command.
Add your local symbol location to the symbol path by typing the following command.
We will use the x command to examine the symbols associated with the echo driver to determine the function name to use for the breakpoint. We can use a wild card or Ctrl+F to locate the DeviceAdd function name.
The output above shows that DeviceAdd method for our echo driver is ECHO!EchoEvtDeviceAdd.
Alternatively, we could review the source code to locate the desired function name for our breakpoint.
Set the breakpoint with the bm command using the name of the driver, followed by the function name (for example AddDevice) where you want to set the breakpoint, separated by an exclamation mark. We will use AddDevice to watch the driver being loaded.
Note
You can use different syntax in conjunction with setting variables like ! , :: ,†:
’, or skip a number of times . For more information, see Conditional breakpoints in WinDbg and other Windows debuggers.
List the current breakpoints to confirm that the breakpoint was set by typing the bl command.
The «e» in the output shown above indicates that the breakpoint number 1 is enabled to fire.
Restart code execution on the target system by typing the go command g.
-> On the target system
In Windows, open Device Manager using the icon or by entering mmc devmgmt.msc. In Device Manager, expand the Samples node.
Select and hold (or right-click) the KMDF Echo driver entry and select Disable from the menu.
Select and hold (or right-click) the KMDF Echo driver entry again and select Enable from the menu.
Clears a breakpoint from the list. Use bc * to clear all breakpoints.
Disables a breakpoint. Use bd * to disable all breakpoints.
Enables a breakpoint. Use be * to enable all breakpoints.
Alternatively, you can also modify breakpoints by selecting edit > breakpoints in WinDbg. Note that the breakpoint dialog box only works with existing breakpoints. New breakpoints must be set from the command line.
Note
Setting memory access breakpoints
You can also set breakpoints that fire when a memory location is accessed. Use the ba (break on access) command, with the following syntax.
Option | Description |
---|---|