Click here to Skip to main content
15,880,405 members
Articles / Programming Languages / C#
Article

A Release Mode Breakpoint Using Reflection Emit

Rate me:
Please Sign up or sign in to vote.
4.00/5 (5 votes)
9 Oct 20022 min read 85.9K   26   6
C#'s release mode doesn't allow break points to be set. This function emits an IL break, forcing a breakpoint in the debugger.

Introduction

OK, for some silly reason, I needed to look at the code generated in release mode vs. debug mode. Why? Because I'm writing an article about the differences using the Debug and Trace classes, and I wanted to see what really is going on behind the scenes when I compile code in release mode. Also, I figure that just because C# is "managed", that doesn't mean that I won't get weird behavior when I switch over to a release version, and I may in the future want to set a breakpoint.

As was recently pointed out to me, you can't set a breakpoint in release mode because there's no symbolic information. This is silly, because I should still be able to set a breakpoint based on the instruction address. However, living with the inevitable, the following code emits a "Break" opcode in a module created on the fly and invokes the module's function. Whether in release or debug mode, this results in the application breaking when run under the debugger.

This was also a fun exercise in dynamic code generation and shows some of the nightmarish steps necessary to generate code dynamically. Still, I think it's a really awesome feature of the language!

The Easy Way

As Fredrik Tonn pointed out in a message, adding a breakpoint in release mode can be easily accomplished by inserting System.Diagnostics.Debugger.Break() in your code where you wish the breakpoint to occur.

What else is there to say? So much for the easy way.

The Hard Way

This requires generating some IL on the fly, which invokes the IL opcode Break. The following code documents how to do this.

C#
/*
    *    Credits:
    *        Visual Studio Magazine
    *        Octobor 2002 Issue
    *        "Generate Assemblies With Reflection Emit" by Randy Holloway
    *        http://www.fawcette.com/vsm/2002_10/magazine/columns/blackbelt/ 
*/
// the interface serves as a stub to invoke the generated function
public interface IRMBP
{
    void Break();
}

public class ReleaseMode
{
    static public void Break()
    {
        Assembly asm=new ReleaseMode().GenerateBreak();
        IRMBP bp=null;
        bp=(IRMBP)asm.CreateInstance("RMBP");
        bp.Break();
    }

    private Assembly GenerateBreak()
    {
        // create an instance of the assembly name...
        AssemblyName asmbName=new AssemblyName();
        // ... and name it.
        asmbName.Name="ReleaseModeBreakPoint";

        // get an instance of the assembly builder,
        // indicating that the assembly can be saved and executed
        // If we don't specify "RunAndSave", we get the error
        // "cannot have a persistent module in a transient assembly"
        AssemblyBuilder asmbBuilder=
          AppDomain.CurrentDomain.DefineDynamicAssembly(asmbName, 
          AssemblyBuilderAccess.RunAndSave);

        // create a module builder, giving it the module name,
        // the filename, and whether or not symbolic information is written
        ModuleBuilder mdlBuilder=
          asmbBuilder.DefineDynamicModule("ReleaseModeBreakPoint", 
          "rmbp.dll", false);

        // create a type.  As in "public class RMBP"
        TypeBuilder typBuilder=mdlBuilder.DefineType("RMBP", 
                                      TypeAttributes.Public);

        // add an interface.  As in "public class RMBP : IRMBP"
        typBuilder.AddInterfaceImplementation(typeof(IRMBP));

        // create the "Break" method.  "public virtual void Break();"
        Type[] paramTypes=new Type[0];
        Type returnType=typeof(void);
        MethodBuilder mthdBuilder=typBuilder.DefineMethod("Break", 
           MethodAttributes.Public | MethodAttributes.Virtual, 
           returnType, paramTypes);

        // generate the code:
        ILGenerator ilg=mthdBuilder.GetILGenerator(); // get the generator
        ilg.Emit(OpCodes.Break); // issue a break statement
        ilg.Emit(OpCodes.Ret);    // return afterwards

        // get info about our Break method in the interface class IRMBP
        MethodInfo mthdInfo=typeof(IRMBP).GetMethod("Break");

        // associate our generated method with the interface method
        typBuilder.DefineMethodOverride(mthdBuilder, mthdInfo);

        // create the type
        typBuilder.CreateType();

        return asmbBuilder;
    }
}

Usage

Usage is quite simple. Put the statement ReleaseMode.Break(); where you want the debugger to break. Once the debugger breaks, you can single step through the two returns and then inspect your program's assembly code.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect Interacx
United States United States
Blog: https://marcclifton.wordpress.com/
Home Page: http://www.marcclifton.com
Research: http://www.higherorderprogramming.com/
GitHub: https://github.com/cliftonm

All my life I have been passionate about architecture / software design, as this is the cornerstone to a maintainable and extensible application. As such, I have enjoyed exploring some crazy ideas and discovering that they are not so crazy after all. I also love writing about my ideas and seeing the community response. As a consultant, I've enjoyed working in a wide range of industries such as aerospace, boatyard management, remote sensing, emergency services / data management, and casino operations. I've done a variety of pro-bono work non-profit organizations related to nature conservancy, drug recovery and women's health.

Comments and Discussions

 
QuestionWhy? Pin
FredrikT9-Oct-02 5:38
FredrikT9-Oct-02 5:38 
AnswerRe: Why? Pin
Marc Clifton9-Oct-02 8:13
mvaMarc Clifton9-Oct-02 8:13 
GeneralInteresting Pin
Kannan Kalyanaraman9-Oct-02 0:35
Kannan Kalyanaraman9-Oct-02 0:35 
GeneralRe: Interesting Pin
Anonymous9-Oct-02 15:32
Anonymous9-Oct-02 15:32 
why use this thing?
do you think that the .net enviroment is enough?
and you use other tech to achieve this thing , I think
it is not nessensary.......
GeneralRe: Interesting Pin
Marc Clifton10-Oct-02 1:38
mvaMarc Clifton10-Oct-02 1:38 
GeneralRe: Interesting Pin
Anonymous11-Nov-02 18:09
Anonymous11-Nov-02 18:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.