How to control a debugger engine?

In the previous post, I’ve introduced a tool that helps finding managed memory leaks based on output obtained via WinDBG and the SOS extension. Even though the clipboard interception makes the process easier and faster, it is still boring to open dumps in WinDBG, then load sos before copying the output of !dumpheap -stat.
It would be great if all this could be automated: this post will quickly present one way to write code that controls the debugging engine instead of manually dealing with WinDBG.

Looking for an API

After a few research, I ended up into the native API provided by dbghelp.dll that I used a long time ago. It was presented by Matt Pietrek in MSDN Magazine. It reminded me the old IMAGEHLP days when Matt and John Robbins detailed the symbolsoriented API in MSJ (any souvenir of SUPERASSERT? :^)

In addition to MSDN Magazine, John detailed part of the dbghelp API in one of his books.

But most of the API was related to symbol management and things have changed a little since that time. When you take a look at the include files, DbgEng.h contains 16.000+ lines and DbgHelp.h has more than 4.500 lines. The former defines a long list of COM interfaces with IDebugClient.OpenDumpFile to open a dump file. The latter allows you to access the different streams (defined in MINIDUMP_STREAM_TYPE) of a dump file with MiniDumpReadDumpStream() once it has been mapped into memory as a memory mapped files.

Since I want to access to a dump file in managed code, load extensions and send commands to be parsed, these two APIs are way too complicated for what I have in mind. CodePlex also provides two wrappers and a PowerShell interface for the debugger engine API but I’ve found another solution.

As stated on the download page, “the Debug Diagnostic Tool (DebugDiag) is designed to assist in troubleshooting issues such as hangs, slow performance, memory leaks or fragmentation, and crashes in any user-mode process. The tool includes additional debugging scripts focused on Internet Information Services (IIS) applications, web data access components, COM+ and related Microsoft technologies”.
Even better, “the Debugger Host (DbgHost.exe) hosts the Windows Symbolic Debugger Engine (dbgeng.dll) to attach to processes and generate memory dumps. It also hosts the main analyzer module to analyze memory dumps” and exposes high level services as a COM server.

Note that beta 2 version of DebugDiag is also available for x86 and x64.

Using DbgHost in C#

Once DebugDiag installed, the DbgHost COM server is here to help you. Open your favorite Visual Studio and add a COM reference into your C# project

But what do we get exactly?
Well… First, the IDbgControl interface allows you to open a dump file

by giving its path in addition to three other parameters:

  • SymbolPath: you give the symbol store path so the engine will find the .pdb files for the loaded modules.
  • ImagePath: you give the symbol store path so the engine will find the loaded .dlls when needed.
  • pProgress: I have no idea what is its purpose…

If you are working with WinDBG, you already know how the symbol store is important. Otherwise… well… read Advanced .NET Debugging by Mario Hewardt and Patrick Dussud.
You will see in a forthcoming post how important the symbol store is when dealing with the sos.dll extension.

Once a dump file is loaded by the debugging engine, you access it through the IDbgObj interface returned by IDbgControl.OpenDumpFile().


The Execute method takes the command to run as a string and returns the result as a string too.
Simple!

First code sample

It is easy to write a couple of lines that load a dump file and get a few details about it. In addition to the two already described methods, the following code shows how to use other IDbgObj properties.

    string dumpPath;
    dumpPath = @"c:\dumps\WpfLeaky_x86_3.5.dmp";
 
    DbgControl dbgControl = new DbgControl();
    DbgObj dbgSession = dbgControl.OpenDump(dumpPath, @"c:\symbols"@"c:\symbols"null);
    Console.WriteLine("dump '{0}' loaded.", dbgSession.DumpType);
    Console.WriteLine("exe: {0}", dbgSession.ExecutableName);
    Console.WriteLine("OSVersion: {0}", dbgSession.OSVersion);
    Console.WriteLine("   Major:       {0}", dbgSession.OSVersionMajor);
    Console.WriteLine("   Minor:       {0}", dbgSession.OSVersionMinor);
    Console.WriteLine("   ServicePack: {0}", dbgSession.OSServicePack);
    Console.WriteLine("   Build:       {0}", dbgSession.OSBuild);
 
    string result;
    string command;
    // look for additionnal details about the dump file
    command = "vertarget";
    Console.WriteLine(string.Format("\r\n{0}\r\n--------------------", command));
    result = dbgSession.Execute(command);
    Console.WriteLine(result);

As you can see in the result, the OSVersion does not seem to be meaningful.

dump 'MINIFULLDUMP' loaded.
exe: C:\Personel\dev\ManagedLeaks\Current\WpfLeaky\bin\Debug\WpfLeaky.exe
OSVersion: Unexpected
Major: 6
Minor: 1
ServicePack:
Build: 6.1.7600.16385 (win7_rtm.090713-1255)

vertarget
--------------------
Windows 7 Version 7600 MP (8 procs) Free x86 compatible
Product: WinNt, suite: SingleUserTS
kernel32.dll version: 6.1.7600.16385 (win7_rtm.090713-1255)
Machine Name:
Debug session time: Mon Apr 18 06:07:41.000 2011 (UTC + 2:00)
System Uptime: 2 days 21:29:04.007
Process Uptime: 0 days 0:00:26.000
Kernel time: 0 days 0:00:00.000
User time: 0 days 0:00:00.000

Interestingly enough, you are able to figure out if a dump is 32 bit or 64 bit by parsing the first line of the “vertarget” command result: “x86” for 32 bit and “x64” for 64 bit. It is very important because you should always use the 32 bit version of the debugging engine to work with a 32 bit dump. Same rule for a 64 bit dump: always use the 64 bit version of the engine in that case.
The solution I’ve chosen is to compile two versions of my application: one for x86 and the other for x64. Each one checks that the dump to load has the expected bitness.

The next post will discuss the issues related to using the sos.dll extension.

Other Reference

Advertisements
This entry was posted in .NET, Development. Bookmark the permalink.

2 Responses to How to control a debugger engine?

  1. Pingback: Sending an SOS | Code & Debug

  2. Pingback: S.A.D. or S(imple) A(fter) D(ump) | Code & Debug

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s