PowerDbg is a script that allows you to control the
execution of the native debuggers through PowerShell. The script allows
you to fold the power of the native debuggers into the rich scripting
language of PowerShell and thereby leverage both the debuggers’
scripting capabilities as well as PowerShell’s, creating new commands
that can do post processing of the debugger command output and display
the results in an easy-to-digest fashion. PowerDbg works on both live
debug sessions as well as dump file debugging.
Installing PowerDbg
The latest
version of PowerDbg requires PowerShell version 2.0. At the time of this
writing, PowerShell 2.0 was in Customer Technology Preview release
version 3 (CTP3) and can be downloaded for free from the Microsoft Web
site. After PowerShell is installed, the PowerDbg bits have to be
downloaded and can be found on Codeplex at the following location:
The download comes in the form of a ZIP file that contains the following files:
Microsoft.PowerShell_profile.ps1. This file contains all the cmdlets that parse the native debuggers command output and must be placed in the following path:
%USERPROFILE%\Documents\WindowsPowerShell
WinDbg.psm1.
This file contains all the cmdlets that handle communication with the
native debuggers and must be placed in the following path:
%WINDIR%\System32\WindowsPowerShell\v1.0\Modules\WinDbg
Before PowerDbg can be
used, a couple of configuration steps have to be made. The first step is
to instruct PowerShell to allow for execution of script files. This can
easily be accomplished by running the following command from the
PowerShell window:
PS C:\Windows\System32>set-executionpolicy Unrestricted
The preceding command
sets the script execution policy to allow running any script on the
system. If the script was downloaded from the Internet, PowerShell
prompts for permission before executing.
Next, you have to perform a one-time import of the WinDbg.psm1 module by using the following command:
Please note that the import is persisted and a one-time configuration step only.
The next step is to
configure the debugger for remote debugging. To get a better
understanding of why this is required, it is important to understand
that the way the PowerDbg cmdlets communicate with the native debuggers
is via the built-in remoting capabilities of the native debuggers. In
other words, the remote pipe has to first be set up in the debugger for
PowerDbg to work. To set up a remote pipe, in the debugger, use
.server tcp:port=<port_number>
where port_number is an available TCP port to be used during communication. For example, if we want to use TCP port 8888, we would use the following the command:
The next step is making sure that the debug session has the proper symbol path’s setup. We can utilize the good old .symfix command from within the WinDbg session to set the symbol path to the Microsoft public symbol server.
The final step is to tell PowerDbg to connect to the debug session by using the Connect-WinDbg cmdlet. The Connect-WinDbg
cmdlet takes as an argument the remote connection string established
while setting up the remote connection in the WinDbg session and takes
on a similar syntax
tcp:Port=<port_number>,Server=<server_name>
where port_number is the TCP port used earlier to create the remote pipe and the server_name is the name of the server that the WinDbg session is running on. For example, with a TCP port of 8888 and a server name of MARIOH-LAPTOP, we would specify the following command to make the connection:
Connect-WinDbg "tcp:Port=8888,Server=MARIOH-LAPTOP"
Currently, only one open
connection at a time is supported, and if you want to reconnect to a
different remote session, you must first use the Disconnect-WinDbg command.
Does it Only Support WINDBG?
Not at all. All of
the debuggers in the Debugging Tools for Windows package share the same
debugger engine and as such WinDbg, cdb, or ntsd can be used to create
the remote connection.
That is all the
preparatory work that is required to get started with PowerDbg (launch
debugger, create a remote connection, set symbols, and use the Connect-WinDbg command to connect). Next, we’ll take a look at a few of the cmdlets available in PowerDbg.
Analyze-PowerDbgThreads
The Analyze-PowerDbgThreads
command enumerates all the existing threads in the process and displays
their respective states. The available states are listed in Table 1.
Table 1. Available States in Analyze-PowerDbgThreads cmdlet
State | Description |
---|
UNKNOWN_SYMBOL | The state of the thread is unknown. |
WAITING_FOR_CRITICAL_SECTION | The thread is waiting for a critical section. |
DOING_IO | The thread is doing file manipulations. |
WAITING | The thread is waiting on a synchronization primitive. |
GC_THREAD | The thread is doing a garbage collection. |
WAIT_UNTIL_GC_COMPLETE | The thread is waiting for a garbage collection to complete. |
SUSPEND_FOR_GC | The thread is suspended by the garbage collector. |
WAIT_FOR_FINALIZE | The thread is waiting for objects to be finalized. |
TRYING_MANAGED_LOCK | The thread is trying to acquire a managed lock. |
DATA_FROM_WINSOCK | The thread is waiting for data from the Windows sockets layer. |
The way in which the cmdlet finds the state of a thread is by sending a k
(display stack trace) command to the debugger session and mapping the
symbols on the stack to the corresponding state. It’s extremely easy to
change the cmdlet and add your own symbols and states by simply changing the Classify-PowerDbgThreads function in
%USERPROFILE%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
Here is an example of the output from the command when run on 05Heap.exe:
Threads sorted by User Time...
Thread Number User Time Kernel Time Activity
0 0:00:00.031 0:00:00.078 Thread working and
doing unknown activity.
4 0:00:00.000 0:00:00.000 Thread in wait state.
3 0:00:00.000 0:00:00.000 Thread working and doing unknown
activity.
2 0:00:00.000 0:00:00.000 Thread waiting for the Finalizer
event. The Finalizer thread might be b
locked.
1 0:00:00.000 0:00:00.000 Thread is the CLR Debugger Thread.
As
can be seen from the output, in addition to the activity state of each
thread, the user and kernel times are also displayed making it easy to
detect potential runaway or blocked threads.