[PowerShell Script] PowerDbg v3.1 – Using PowerShell to Control WinDbg

This new version has one more parser for !PrintException and a killer feature that my colleagues and myself havewanted since the beginning: PowerDbg, more specifically Send-PowerDbgCommand, whichnow has the ability to wait until a command finished its execution.It means no more delays to wait for a command to be processed and no more exceptions when the command takes longer than the delay to finish its execution.

To know how it’s a great improvement over the previous version, let me explain the PowerDbg concept.

With PowerDbg it’s possible to send commands to WinDbg and receive data from WinDbg.

The basic flow from a script using PowerDbg is below. As you can see, it’s very easy to interact with WinDbg and to create more parsers or scripts that use PowerDbg:

1-Change (.wtitle PowerDbg) WinDbg title to PowerDbg, so the cmdlets can find the WinDbg instance.

2-Send-PowerDbgCommand “command”ß Sends command to the debugger.

3-Parse-PowerDbg<command>ß Parses the output and sends it to a CSV file.

4-Convert-PowerDbgCSVToHashTableßConverts the CSV to a Hash Table.

Then you can use the hash table inthe way you want.

It works fine, however, when Send-PowerDbgCommand sends a command to WinDbg; it returns, doing an asynchronous call. However, when the cmdlet returns the WinDbg could be still struggling to process the command. At this point, if a Parse cmdlet is called from a script, an exception will happen. To work around this timing issue, the scripts using PowerDbg and even some cmdlets used a sleep call to give WinDbg time to process the command.

The problems with this approach are:

a)If the command is quick and returns the result it called upon, the scripts don’tknow that, and they need to use an idle time just in case, thus, impacting the performance.

b)If the developer using PowerDbg forgets to add Start-Sleep after using Send-PowerDbgCommand, it is almost sure an error will happen when another PowerDbg command is called. It happens because of the timing issue.

c)If you use a long timeout, it may not be enough for specific cases, so your script will break, throwing an exception. For example, try to use it from PowerShell, using the previous PowerDbg library:

If you have a dump or process with too many threads or if the symbols are still being solved, chances are you’ll get an exception. The reason is related to timing. After sending the command to the debugger, PowerShell will try to parse and create a Hash Table from an empty csv file while WinDbg is still processing the command.

To solve it you can use something like Start-Sleep 8, for example. However, what if the command took just 3 seconds? Or what if it took 1 minute?

SOLVING THE TIMING ISSUE

To solve the timing situation exemplified above, the latest PowerDbg version only returns from Send-PowerDbgCommand when WinDbg has finished processing the command!

It means no more idle time, better performance, and no more exceptions after a forced delay.

To do that I considered several approaches and ended up using the approach below:

Send-PowerDbgCommand uses “.pcmd” to send a message to the debugger when any command that affects execution runs (for more, see the WinDbg documentation). So, the user command is sent to the debugger and, just after it, the “r” command is sent to the debugger, too. Because the first command may be still be processing,the second command doesn’t run andstays in the queue.

The “r” command is considered a command the affects the execution, so the message configured with “.pcmd” is triggered when “r” is used. Got it? After executing the user command, the “r” command that is queued to be processed, is processed. Then our custom message is sent to the debugger. In the meantime Send-PowerDbgCommand is monitoring the log file that has the raw output and looking for the message that signals the end of command execution. The default timeout is 3 minutes and can be easily changed. When it finds the message, it removes the garbage from the output file so thatthe parsed file won’t have any differences when compared to previous versions of PowerDbg. (in other words, it won’t break your scripts J)

The only drawback is a message and registers that appear in the WinDbg window whenever you send a command, causing a bit of visual pollution, like:

Anyway, for the benefit of this approach it’s just a minor drawback, and it doesn’t affect the Parsers from PowerShell either in the way you use the library to create your own cmdlets or inscripts.

Note: The command .pcmd is not going to be in the article series Special Commands because, although it’s a special command, it’s very unlikely you end up using it during your debugging. At the same time, it’s very simple to use it.

Below, are examples of using PowerDbg, so you can use it as a reference when building scripts.

Pay attention to this: Because we have a csv file, we have to use another way to put the stack as the value and the thread number as the key. To do that the cmdlet removed the newline and replaced it witha special character sequence that you can get from:

$global:g_frameDelimiter

It’s documented in the header file from Parse-PowerDbgK in case were wondering. J

c)Now, let’s see the call stack for thread 20. Note how I replace the $global:g_frameDelimiter for new line: