Wednesday, July 15, 2009

Determining if an assembly is compiled in release or debug mode

To determine if an assembly was compiled in debug mode, look for the following Debuggable attribute at the assembly level. You will need to look at the flags set on it which have the following values:

Default = int32(1)
DisableOptimizations = int32(0x100)
EnableEditAndContinue = int32(4)
IgnoreSymbolStoreSequencePoints = int32(2)
None = int32(0)



If the attribute is there, it does not mean it is or is not a debug/release build. What is important to check is the flag values, and what you are looking for. You can have a release build, and still generate PDB information. This pdb information is more limited, since optimizations are still enabled you will not be able to debug this program at a source level.


How do you find this attribute on a compiled assembly?
1. Open the assembly in reflector
2. Click on the assembly at the base level (ie do not click on any classes underneath the root level, make sure the assembly name is highlighted in reflector)
3. Hit the spacebar to make sure you can view the disassembly on the right hand side.
4. Look at the output for the Debuggable attribute.


The scenarios here show:
1. Default Debug release (So no optimizations set and full debug info being generated)
2. Default Release (Enable Optimizations checked off and pdb-only option set)
3. Release mode with no pdb info being generated
4. Release mode with full pdb info being generated
5. Release with optimizations unchecked and full pdb info being generated

Where are the mentioned settings?
In Visual Studio 2008 go into the project properties and then the build section. There is a checkbox there for "Optimize Code". The second option is under the "Advanced" button at the bottom of the screen. The setting is "Debug Info" and the options are "none, pdb-only, full"

Scenario 1
Default debug release the assembly shows the following (other attributes removed)
We see the value is 107, so look at the enum values to figure out the options:
DisableOptimizations (100)
EnableEditAndContinue (4)
IgnoreSymbolStoreSequencePoints (2)
Default (1)
We OR these bits all together (IE add them) and we come up with 107


.assembly DebuggableTest
{
.custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype 

[mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = { int32(0x107) }
}


Scenario 2
Release mode:

Options set:
IgnoreSymbolStoreSequencePoints

.assembly DebuggableTest
{
.custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = { int32(2) }
}


Scenario 3
Release mode with no pdb info being generated (ie debug info set to "none" in the advanced options)
Notice there is no Debuggable attribute set in this option
Options set:
NONE

.assembly DebuggableTest
{

}


Scenario 4
Release mode with the "full" option set for debug info (ie full pdb info being generated )
Options set:
IgnoreSymbolStoreSequencePoints
Default

.assembly DebuggableTest
{
.custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = { int32(3) }
}


Scenario 5
Release mode with optimizations unchecked and full pdb info being generated. In theory this is the same as a debug build. Lets check:
Options set:
DisableOptimizations (100)
EnableEditAndContinue (4)
IgnoreSymbolStoreSequencePoints (2)
Default (1)


.assembly DebuggableTest
{
.custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = { int32(0x107) }
}


To do this in code - I got this I believe from:
http://www.jamesewelch.com/2007/08/30/how-to-tell-if-a-net-assembly-is-debug-or-release/

Assembly assemb = Assembly.LoadFile(Path.GetFullPath(fileName));
bool isDebug = false;
foreach (object attribute in assemb.GetCustomAttributes(false))
{
     if (attribute is DebuggableAttribute)
     {
          isDebug = ((DebuggableAttribute)attribute ).IsJITTrackingEnabled;
     }
}

if(isDebug)
{
  //'got me some debug code!
}


Hope this helps!

1 comment:

  1. Hi Adam,

    The code above is incorrect; it only looks for the IsJITTrackingEnabled which is completely independent of whether or not the code is compiled for optimization and JIT Optimization.

    The DebuggableAttribute is present if you compile in Release mode and choose DebugOutput to anything other than "none".

    You also need to define *exaclty* what is meant by "Debug" vs. "Release"...

    Do you mean that the app is configured with code optimization?
    Do you mean that you can attach the VS/JIT Debugger to it?
    Do you mean that it generates DebugOutput?
    Do you mean that it defines the DEBUG constant? Remember that you can conditionally compile Methods with the System.Diagnostics.Conditional() attribute.

    IMHO, when someone asks whether or not an assembly is "Debug" or "Release", they really mean if the code is optimized...

    Sooo, assuming that you are wanting to know if the code is JITOptimized, here is the correct implementation:

    object[] attribs = ReflectedAssembly.GetCustomAttributes(typeof(DebuggableAttribute),
    false);

    // If the 'DebuggableAttribute' is not found then it is definitely an OPTIMIZED build
    if (attribs.Length > 0)
    {
    // Just because the 'DebuggableAttribute' is found doesn't necessarily mean
    // it's a DEBUG build; we have to check the JIT Optimization flag
    // i.e. it could have the "generate PDB" checked but have JIT Optimization enabled
    DebuggableAttribute debuggableAttribute = attribs[0] as DebuggableAttribute;
    if (debuggableAttribute != null)
    {
    HasDebuggableAttribute = true;
    IsJITOptimized = !debuggableAttribute.IsJITOptimizerDisabled;
    BuildType = debuggableAttribute.IsJITOptimizerDisabled ? "Debug" : "Release";

    // check for Debug Output "full" or "pdb-only"
    DebugOutput = (debuggableAttribute.DebuggingFlags &
    DebuggableAttribute.DebuggingModes.Default) !=
    DebuggableAttribute.DebuggingModes.None
    ? "Full" : "pdb-only";
    }
    }
    else
    {
    IsJITOptimized = true;
    BuildType = "Release";
    }

    I've provided this implementation on my blog at:

    How to Tell if an Assembly is Debug or Release

    ReplyDelete