Generating a Dump In Your Code Using DebugBreak

There are many issues that pop up that really require a user mode dump in order to successfully diagnose root cause. I will occasionally visit the ASP.NET newsgroups, and when I do, I read only those posts with a subject that interests me. I find that I gravitate towards crashes, high memory issues, hangs . . . in other words, those issues that require a user-mode debug in order to reach resolution.

Hangs, high memory, crashes, and other such issues lend themselves well to getting a dump easily. Adplus is a great tool for such things, and if you're dealing with any of the aforementioned issues, getting a dump is a no-brainer. However, there are many issues that require dump analysis that aren't so straight-forward. I'm working just such an issue right now.

I have a high-visibility customer experiencing a pretty serious problem. Their Web application is occasionally allowing one person to see another person's data. When this happens, the nature of the issue causes a System.Net.WebException to occur. In order to really dig into what's going on, we need to look into the down and dirty details of the HttpRequest and HttpResponse object at precisely the moment that the issue occurs. (When I say "precisely", I mean just that. A tenth of a second too late and we're toast.) We need a dump at just that moment.

We can use an adplus configuration file to dump when a WebException occurs, but that causes us to dump like crazy for every single occurrence of this exception type. That won't do. The application is throwing that exception for other reasons and we fill up disk space pretty quickly with dump files that are useless to us. We need a way to focus on just the specific WebException that's occurring when the problem occurs. Fortunately, we know the page that is executing when the error occurs. We can use that to get a dump by making an explicit call to kernel32!DebugBreak via P/Invoke. I have never tried this before, but the concept is a proven technique. No doubt about it; this is the way to go in this case.

In this particular case, the customer is making an HttpWebRequest call that sometimes results in the WebException we're interested in. The first step is to wrap the WebRequest call in a try...catch block and catch the WebException.

try
{
    // make the HttpWebRequest call

}
catch(System.Net.WebException e)
{
    // call DebugBreak
    DebugBreak();
}

Now we need to add the P/Invoke call to DebugBreak.

[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError=true)]
internal static extern void DebugBreak();

In order for all of this to work, we need to use Adplus to hook up the debugger (CDB in this case) and monitor for the BreakpointException breakpoint. I'll use an Adplus configuration file to do that. It looks like this.

<ADPlus>
  <Exceptions>
    <Option> NoDumpOnFirstChance </Option>
    <Config>
      <Code> bpec </Code>
      <Actions1> FullDump </Actions1>
      <ReturnAction1> gh </ReturnAction1>
    </Config>
  </Exceptions>
</ADPlus>

This is a pretty simple config file. The <Code> section defines a BreakpointException via the use of bpec. <Actions1> indicates the action we will take on first-chance exceptions that match the code. <ReturnAction1> specifies what we'll do after we dump. In this case, after dumping, we're executing a "gh" command which means "go / consider the exception handled." I've saved this config file into the same directory where the Debugging Tools for Windows are installed and named it debugbreak.cfg.

Now we need to run Adplus with the following command line.

cscript adplus.vbs -crash -pn w3wp.exe -c debugbreak.cfg -o c:\dbrkdump

Everything's set up now and we're ready to capture a dump when the problem occurs.

You can use this same technique anytime that you need to make your code cause a dump to be created. In fact, if you are writing code that you think might produce issues where a dump is required, you can put such code in your application in various places so that you can create a dump in various situations. If you decide to do that, it's advisable to check a Registry key or use some other method to determine if you should be calling DebugBreak.