Opening a Crash Dump File (Automating Crash Dump Analysis Part 1)

So let's assume for the moment that you have a collection of crash dump files from your team's application. These files may be generated from your stress tests, betas, etc. But where they come from really isn't important, what is important is that we want some way to dig into these files and gather information, evaluate priority, etc., without having to manually open each one in the debugger.

 

Once you install WinDBG, you are given a COM interface allowing you to integrate debugging functionality into your own application. We can then use this to drive the task of opening and querying a crash dump file. When installing, just make sure you select the SDK option, which will give you the header files you will need. To make you life happier, you should also install the symbol packages for all the Operating Systems you support (also available from the above link) - doing so will give you function names from system binaries in the stack traces we will eventually create.

 

To start with we will go over the minimum code to initialize the debugging library and open a crash dump file.

 

#include <windows.h>

#include "dbgeng.h" // windbg header

int __cdecl main(int argc, char* argv[])

    {

    HRESULT hr = E_FAIL;

    IDebugClient *client = NULL;

    IDebugControl *control = NULL;

    IDebugSymbols *symbols = NULL;

 

    // Initialize COM

    hr = CoInitialize(NULL);

    if(FAILED(hr))

        goto cleanup;

 

    // Create the base IDebugClient object

    hr = DebugCreate(__uuidof(IDebugClient), (LPVOID*)&client);

    if(FAILED(hr))

        goto cleanup;

 

    // from the base, create the Control and Symbols objects

    hr = client->QueryInterface(__uuidof(IDebugControl), (LPVOID*)&control);

    if(FAILED(hr))

        goto cleanup;

 

    hr = client->QueryInterface(__uuidof(IDebugSymbols), (LPVOID*)&symbols);

    if(FAILED(hr))

        goto cleanup;

 

    // we can supplement the _NT_SYMBOL_PATH environment variable

    // by adding a path here

    symbols->SetSymbolPath("c:\\myApp\\release");

 

    // the debugger will need to look at the actual binaries

    // so provide the path to the exsecutable files

    symbols->SetImagePath("c:\\myApp\\release");

 

    // open the crash dump

    hr = client->OpenDumpFile("c:\\myApp\\myApp.dmp");

    if(FAILED(hr))

        goto cleanup;

 

    // wait for the engine to finish processing

    control->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);

 

 

    cleanup:

 

    // cleanup and destroy the objects

    if(symbols)

        {

        symbols->Release();

        symbols = NULL;

        }

    if(control)

        {

        control->Release();

        control = NULL;

        }

    if(client)

        {

        client->Release();

        client = NULL;

        }

 

    // cleanup COM

    CoUninitialize();

 

    return 0;

    }

The semicolon separated path you pass into SetSymbolPath() should provide the location of the .pdb symbol files for all binaries consumed by your application. The same goes for the paths to the actual binary files themselves, which is passed in via SetImagePath(). Without the symbols or the actual binaries, your investigations won't be as successful.

MSDN References

· DebugCreate() which is used to instantiate the initial IDebugClient interface.

· IDebugClient

· IDebugControl

· IDebugSymbols