Book Review: Advanced .NET Debugging

Dmitry Vostokov, 12th of February, 2010 Updated 9th of June, 2010
http://www.dumpanalysis.org

When learning software debugging it is extremely useful to know both high level and low level pictures, from architecture to code implementation details. Deviations of expected software behaviour originate from many sources and not only from defects in your own code. This is especially true for Microsoft .NET platform. Typical .NET application is actually an operation system process. Therefore, .NET debugging in real life situations sometimes involves normal application level Windows debugging where loaded unmanaged components may influence the container process behaviour. Sometimes we even need to look at system level and know a bit of hard core kernel stuff. Standard middle level .NET debugging tools don't allow you to debug from low level perspective. That's why we need a powerful low-level debugger WinDbg.

The book, written by Mario Heward, accomplishes that very well. At the beginning of every chapter there is a high level overview and then we dig deeper and deeper into the implementation of .NET, sometimes literally inspecting bits of raw memory.

The best way to learn from this book is to read it from cover to cover and do exercises. I would also advise to play with them, try to see what happens if you change a statement or two. For example, I even changed the platform to x64 .NET.

Let's now look at chapters one by one. The first one provides an introduction to Microsoft debugging tools and software you need to install. The second chapter provides high level overview of .NET architecture and how Windows loads .NET applications. Here we already start using WinDbg to inspect memory and the implementation of .NET programming constructions including their layout in process virtual memory and process heap. The 3rd chapter teaches basic debugging tasks like loading necessary symbol files, setting breakpoints, disassembling code, mapping to source code, listing stack traces, inspecting objects and their types, dumping values and complex structures, looking for exceptions. WinDbg is an extensible debugger. It is not possible to know in advance when you write a debugger what kinds of things you need to inspect or what commands you need. WinDbg achieves extensibility by allowing loading extensions, Windows DLLs for specific tasks. .NET versions provide their own standard extension SOS.dll for such purpose. There are other extensions like SOSEX with extended debugging functionality and the 3rd chapter explores it as well. At the end, the chapter even covers automatic deadlock detection and crash dump generation and loading. Of course, many illustrated debugger commands can be applied to crash dump analysis as well.

The next part has four chapters that deal with more advanced stuff like an assembly loader, managed heap and garbage collection, synchronization and interoperability. All these topics require knowing their internals to fully understand their operations. The more internals you know the better you are at debugging. Typical example here is a notorious heap corruption and memory leaks. Synchronization chapter is particularly useful because .NET synchronization primitives are layered on top of Win32 API and it is important to understand this relationship properly. The interoperability chapter illustrates debugging exceptions coming from outside of managed .NET code and debugging issues involving COM components.

The final part of the book deals with the postmortem debugging. It is not always possible to attach a debugger to a running application especially on distributed enterprise production environments. Here the book shows how to configure certain system settings and what tools to use to save crash dumps automatically for later offline analysis. It also has the very detailed section (30 pages) discussing WER (Windows Error Reporting). The next chapter is devoted to addional power tools like PowerDbg, Visual Studio including history debugging, CLR profiler and even CmdTree WinDbg command to create high level debugging interfaces for repetitive tasks. The last chapter discusses new features in the latest .NET runtime CLR 4.0.

In conclusion, I would recommend this book even if you analyze unmanaged process dumps or debug your unmanaged systems. More and more applications utilize the power of .NET by loading its components like mscorwks.dll. Therefore, it is of great importance to know .NET world for Windows maintenance engineers. The book hands-on practical approaches with crystal clear explanations ease the learning curve. It is a must read if you develop and maintain .NET code written in Managed C++, C# and VB.NET.