Decompilation of C# code made easy with Visual Studio

Mark Downie

Have you ever found yourself debugging a .NET project or memory dump only to be confronted with a No Symbols Loaded page? Or maybe experienced an exception occurring in a 3rd party .NET assembly but had no source code to figure out why? You can now use Visual Studio to decompile managed code even if you don’t have the symbols, allowing you to look at code, inspect variables and set breakpoints.

We have recently released a new decompilation and symbol creation experience in the latest preview of Visual Studio 2019 version 16.5 that will aid debugging in situations where you might be missing symbol files or source code. As we launch this feature, we want to ensure that we are creating the most intuitive workflows so please provide feedback.

Decompilation and PDB generation with ILSpy

Decompilation is the process used to produce source code from compiled code. In order to accomplish this we are partnering with ILSpy, a popular open source project, which provides first class, cross platform symbol generation and decompliation. Our engineering team is working to integrate ILSpy technology into valuable debugging scenarios.

What are symbol files? Why do you need them?

Symbol files represent a record of how the compiler translates your source code into Common Intermediate Language (CIL), the CIL is compiled by the Common Language Runtime and executed by the processor. The .NET compiler symbol files are represented by program database files (.pdb), and these files are created as part of the build. The symbol file maps statements in the source code to the CIL instructions in the executable.

Debuggers are able to use the information in the symbol file to determine the source file and line number that should be displayed, and the location in the executable to stop at when you set a breakpoint. Debugging without a symbol file would make it difficult to set breakpoints on a specific line of code or even step through code.

Visual Studio currently provides the option to debug code outside your project source code, such as .NET or third-party code your project calls by specifying the location of the .pdb (and optionally, the source files of the external code). However, in many cases finding the correct symbol files or source code may not be feasible.

By integrating decompilation directly into your debugging experiences we hope to provide developers with the most direct route to troubleshooting issues in 3rd party managed code. We are initially integrating the decompilation experiences into the Module Window, No Symbols Loaded, and Source Not Found page.

No Symbols Loaded/Source Not Found

There are a several ways in which Visual Studio will try to step into code for which it does not have symbols or source files available:

  • Break into code from a breakpoint or exception.
  • Step into code.
  • Switch to a different thread.
  • Change the stack frame by double-clicking a frame in the Call Stack window.

Under these circumstances, the debugger displays the No Symbols Loaded or Source Not Found page and provides an opportunity to load the necessary symbols or source.

In the following example I have opened a crash dump in Visual Studio and have hit an exception in framework code. I do not have the original source code so If I try to switch to the main thread, I see the No Symbols Loaded page. However, it is now possible to decompile the code directly on this page and see the origins of the exception.

Image vs decompilation no symbols loaded

Module Window

During debugging the Modules window is a great place to get information related to the assemblies and executables currently in memory. To open the Modules window, select Debug > Windows > Modules.

Once you have identified a module that requires decompilation, you can right-click on the module and select “Decompile Source to Symbol File”. This action creates a symbol file containing decompiled source which in turn permits you to step into 3rd party code directly from your source code.

It will also be possible to extract source code to disk by right clicking on a module with embedded source and clicking “Extract Embedded Source”. This process exports source files to a Miscellaneous files folder for further analysis. In the following example I open an extracted .cs file and set a break point to better understand the 3rd party code I am using.

Shows decompilation and source extraction from Visual Studio Module window

Some Considerations

Decompilation of the CIL format, used in .NET assemblies, back into a higher-level language like C# has some inherent limitations:

  • Decompiled source does not always resemble the original source code. Decompilation is best used to understand how the program is executing and not as a replacement for the original source code.
  • Debugging code that was decompiled from an assembly that was built using compiler optimizations may encounter the following issues:
    • Breakpoints not always binding to the matching sourcing location
    • Stepping may not always step to the correction
    • Async/await and yield state-machines may not be fully resolved
    • Local variables may not have accurate names
    • Some variables may not be able to be evaluated in the IL Stacks is not empty
  • Source code extracted from an assembly are placed in the solution as Miscellaneous file:
    • The name and location of the generated files is not configurable.
    • They are temporary and will be deleted by Visual Studio.
    • Files are placed in a single folder and any folder hierarchy that the original sources had is not used.
    • The file name for each file has a checksum hash of the file.
  • Decompilation of optimized or release modules produces non-user code. If the debugger breaks in your decompiled non-user code, for example, the No Source window will appear. In order to disable Just My Code navigate to Tools > Options (or Debug > Options) > Debugging > General, deselect Enable Just My Code.
  • Decompilation will only generate source code files in C#.

Try it now!

Download the preview and try out decompilation and let us how it works for you! Please reach out and give us feedback over at Developer Community. Finally, we also have a survey for collecting feedback on the new experiences here. We look forward to hearing from you.