Using IL exception filters for a better debugger experience

Visual Studio 2005 brings with it a new technology -- Just My Code. One nice feature that comes with Just My Code is the ability to stop on exceptions that you care about, without stopping on all exceptions. Usually this just works for you because something in a library that you are using (say WinForms), is eating all the exceptions that you want to stop on. Since your code didn't handle the exception, the debugger will stop.

However, sometimes your program might want to be able to tell the debugger when to stop. It turns out that it is possible to do this by using IL exception filters. With exception filters, you can divide the world into critical exceptions (which you want to stop on), and expected exceptions (which you don't want to stop on).

I think its easiest to show this with an example. Suppose you have some C# code, and you always want to stop on NullReferenceExceptions, but you don't actually care about anything else. Here is how you could do this.

    enum DebuggerExceptionDisposition






    delegate void UserRoutine();

    delegate DebuggerExceptionDisposition DebuggerExceptionFilter(Exception e);



    static class ExceptionBoundry



        static public extern Exception Invoke(UserRoutine routine, DebuggerExceptionFilter filter);




    class Program


        static void Main(string[] args)


            UserRoutine userRoutine = delegate()


                //throw new ArgumentException();

                throw new System.IO.FileNotFoundException();


            DebuggerExceptionFilter filter = delegate(Exception e)


                if (e is NullReferenceException)


                    return DebuggerExceptionDisposition.DebuggerStop;



                return DebuggerExceptionDisposition.DebuggerIgnore;





                ExceptionBoundry.Invoke(userRoutine, filter);







The idea behind ExceptionBoundry.Invoke is that non-user code that will catch any exception that 'filter' tells it to catch (by returning DebuggerStop).

Here is the implementation for ExceptionBoundry.Invoke:

.class private abstract auto ansi sealed beforefieldinit cs.ExceptionBoundry
       extends [mscorlib]System.Object
  .custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 )
  .method public hidebysig static class [mscorlib]System.Exception
          Invoke(class cs.UserRoutine routine,
                 class cs.DebuggerExceptionFilter 'filter') cil managed
    .maxstack 2
    .locals init ([0] class [mscorlib]System.Exception e)

      callvirt   instance void cs.UserRoutine::Invoke()
      leave.s EOF
    }  // end .try
      castclass class [mscorlib]System.Exception
      callvirt   instance valuetype cs.DebuggerExceptionDisposition cs.DebuggerExceptionFilter::Invoke(class [mscorlib]System.Exception)
      leave.s EOF
    }  // end handler
    EOF: ldloc.0 // return the first local
  } // end of method ExceptionBoundry::Invoke

} // end of class cs.ExceptionBoundry

To add it to your program, you could:

  1. Put it in another assembly

  2. Add a post build step that will disassembly your program, add the new IL, and reassemble your program

To disassemble your program:
"<Visual Studio Directory>\SDK\v2.0\Bin\ildasm.exe" ..\cs\bin\debug\cs.exe / /linenum

To assemble your program:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ilasm.exe /quiet /exe /debug=impl /OUTPUT=..\ILExceptionFilter.exe

Comments (4)
  1. Shahar Prish says:

    Nice. I often wondered if there was an easy way to add filters to C#.

  2. A vectored exception handler (see kernel32!AddVectoredExceptionHandler) lets you add to a global list…

  3. Rick Byers says:

    Often, when an unexpected exception occurs in production code, applications want to generate (and potentially

Comments are closed.

Skip to main content