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.
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.
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.
My problem with this is that it is so painfully slow compared to plain ILSpy decompilation. It seems to take it half a minute to generate several files from a large assembly (think PresentationFramework – I know the sources are available anyway, it’s just a good example), compared to a few seconds for the entire assembly by using ILSpy directly.
This is rather disappointing, but I am sure it will improve eventually.
For those scared of decompilation, you could just join the open source movement… but to the main point, decompilation has been around for a long time and this is just a tool to help developers. If someone wants to decompile your code and rebuild your project there are better applications out there.
Best feature I like is being able to debug into source that’s not even referenced by my solution.
I think that instead of placing all generated source code files in a single folder it could be useful to (optionally) place them in a directory tree by namespace of the class in the file - the same way IL Spy does it. Large assemblies contain thousands of classes and this would make finding what I'm looking for easier. Also I would welcome if there was an option to generate not only C# code, but...
This is great, but puhleeaaaaase make it so that F12 on a .NET Standard library member will forward to an actual implementation and not the useless reference assemblies. Based on my tests it does not do this currently. I think the best choice would be to pick the latest installed .NET Core version that supports the .NET Standard version but there could also be a mechanism to pick which .NET Core version is used in...
#ReSharperDoesThat
I know, I used to have resharper, but I've found a configuration of open-source extensions that works better and faster than resharper. Literally the only thing I'm currently missing which nobody can seem to figure out is having .NET Standard F12 go to an implementation instead of the empty reference assemblies, so if this solves that then we are home free.
Roslyn analyzers + a few extensions do pretty much everything resharper does now and it...
Resharper comes with 2 costs:
- Small cost for money
- Huge cost for developer experience as everything is slower. This is especially when you are developing a solution of some 20 projects. If you are working on a few projects it should be fine but I'm more in favour of a built-in solution, which should be faster as well. The only Resharper features I actually use are navigating to decompiled code and 3rd party...
Lack of ReSharper has bigger costs than that, I am afraid. You're basically paying for Visual Studio 10 years into the future as "features" being developed into VS today have been around for at least that amount of time. Case in point, this very article!
I for one can always tell when code has been developed without R# as the gutter lights up like a Christmas tree with all the analysis and...
Big developer hugs, Hai Ha. Or should I say elbow bumps, considering the climate today. 😆
I don't think there's anything useful that R# can pick up while VS 2017/2019 code analysis cannot. What you say about the "Christmas tree" is correct back in VS 2010 and maybe in VS 2015.
VS analysis tools has improved too but I have to agree Dot Trace is easier to use and more thorough than VS CPU analysis. For other things it's personal preference. For me R# is struggling to pack things in a...
This is a great feature. I do debug of 3rd-party code a lot, most of the time to find out what they are doing wrong or see how they work to fix our code. To those who are worried their application being de-compiled: People do debug of 3rd-party library usually because the library itself involves in an issue. I myself care ZERO about your code because most codes are garbage, don't over-estimate it. Also if...
This could be a killer feature. I've lost count how many times I've installed the .Net Reflector VS addin to get just-in-time decompilation (and very nearly bought it last month). Every time, it's to debug a single issue where ILSpy code isn't quite matching up with what the debugger is telling me I've got....even if the add-in doesn't get the source exactly right, just being able to add watches makes all the difference in...
How about built-in obfuscation?
I would say that obfuscation is an anti-feature, and shouldn’t be available by default.
It’s really great how Microsoft cares about its customers’ intellectual property. Instead of making sure that at least basic protection is finally available, you are now making it even easier for crackers and other criminals to rob developers of their livelihood. And then to say: “You can protect your source code by your EULA. Simply forbid decompiling…”. I think this feature will cause great grief.
This complain of “how do I protect my code from being decompiled then?!” and "Microsoft does not care about its customers’ intellectual property." is completely absurd. Since its inception in 2002 .NET compiled code can be decompiled and read crystal clear with popular tools like .NET Reflector, IL Spy, dotPeak… This is a direct consequence of having IL/byte code and a CLR with a JIT compiler.
Since 2002 those that want to protect their compiled...
I'm of the belief that obfuscation is an ultimately pointless endeavor. There's some WinRT assemblies that don't like being opened up ILSpy/Reflector, but pretty much anything is still going to be able to be readable. If you want to protect your business logic, you can copyright it (or *maybe* patent it, but that's a gamble), or you can just host it on a web server, where your business logic stays on the secured...
Thanks for the comment Rene. I hear your concern on protecting intellectual property and the desire for some form of protection. Your feedback is definitely welcome as we continue to evolve this feature. If you are willing, we could talk on a call, I would like to hear more about the kinds of protection you would anticipate .NET provide more generally.
ILSpy is the best decompiler but was missing debugging capabilities like another decompiler.
Did the team consider how integrating ILSpy and giving it debugging/breakpoint abilities makes it more convenient and easier to find any company's secret sauce? All that needs to be added is the ability to save an assembly after removing the license check (like another tool does) and Microsoft has created the perfect cracking tool - all integrating into Visual Studio - And many...
My concern is the obvious script the Visual Studio development team is consistantly using to address the many areas where your customers do not like what you are doing. In the end it all boils down to “we are releasing this no matter what you think, we know best, but we will make some cosmetic changes to appease you”.
In addition, if the CS files are to be saved for later review, they should be encrypted and only be readable with the decompiler.
My proposed solution: It should be an opt-in. Only digitally signed software with an Allow Decompilation option in the application manifest should be decompilable. Decompiling programs that do not comply should be considered illegal and their authors should be held liable for damages.
Coool feature. If you care about intellectual property you must use pro obfuscator. I am personally strugling with a No Symbols Loaded page debugging my own code in nuget package. I hope to move all my sharing code into nuget packages if this feature really works.
You should consider using SourceLink: https://github.com/dotnet/sourcelink