1. Reflector for .NET
Reflector for .NET is a .NET assembly explorer
tool that includes a powerful disassembler that can reproduce the code
from the MSIL (Microsoft Intermediate Language) to a higher level
language of choice. The language choices are C#, Visual Basic, Delphi,
Managed C++, and Chrome. Additionally, it includes an extensibility
model in the form of an add-in API. There are many add-ins available
ranging from a code review add-in to a code metrics add-in. Figure 1 shows an example of analyzing the Reflector.exe binary itself using Reflector for .NET.
To install the tool, the
download location requires that you enter your name, organization, and
email address. Once entered, the package (ZIP file) can be downloaded
and extracted to a location of choice. To launch Reflector for .NET, run
reflector.exe from the installation folder.
2. PowerDbg
PowerDbg
is a library developed by Roberto Farah that allows you to control the
native debuggers via Powershell (requires 1.0). It is a super useful
tool when you want to control the execution of the debuggers using the
command line. The PowerDbg script returns information to the user in a
neat and easily digestible fashion. The great thing about PowerDbg is
that it is easily extensible and enables calling and formatting your
favorite commands (or a set of commands in common debug scenarios).
To utilize PowerDbg, the easiest way is to
initialize it in the Powershell profile. In my case, I use the following
profile path:
%windir%\System32\WindowsPowerShell\v1.0\profile.ps1
Simply copy the PowerDbg script into that file
and reopen a Powershell command window. You can now utilize the PowerDbg
commands as illustrated in an example in Figure 2.
PowerDbg works on the basis of sending commands
to the running WinDbg instance. The first part of any command execution
is the opening of a log file, followed by running the actual command and
then closing the log file. The logfile is utilized by the PowerDbg
script to analyze the results and produce the output. Please note that
in order for PowerDbg to find the WinDbg instance, it requires that the
title of the window for the WinDbg instance to be named PowerDbg. This
can easily be done via the .wtitle command (in WinDbg) as shown here:
If you have configured your WinDbg to automatically configure at startup via a custom initialization script, you can add the .wtitle command to the script so that it always executes upon startup.
3. Managed Debugging Assistants
Usage scenarios: | General CLR Debugging |
Version: | 2.0 |
Download point: | Part of the CLR |
Managed Debugging Assistants (MDAs) is not a
standalone tool per se; rather, it is a component of the CLR that
provides invaluable information when running and debugging .NET
applications. If you are familiar with Application Verifier for native
code, MDAs serve a very similar purpose. Through elaborate
instrumentation of the runtime, common programming mistakes can be
identified at runtime and subsequently fixed prior to shipping the
application. MDAs fall into several categories. Table 1 lists each of the categories available with .NET 2.0.
Table 1. Managed Debugging Assistant (MDA) Categories Available in CLR 2.0
MDA Assistant Category | Description |
---|
Unmanaged Interop | Debugging assistance related to unmanaged interoperability issues |
Unmanaged Interop COM | Debugging assistance related to COM unmanaged interoperability issues |
Unmanaged Interop P/Invoke | Debugging assistance related to platform invocation unmanaged interoperability issues |
Loader | Debugging issues related to the CLR loader |
Threading | Debugging issues related to threading issues |
BCL | Debugging issues related to the base class libraries |
Miscellaneous | Miscellaneous debugging issues |
Each of the categories listed in Table 1-3
has a number of different MDAs available to troubleshoot problems
within that category. To utilize MDAs, they must first be enabled (prior
to starting the process being debugged). The way to enable the MDAs is
via the registry. More specifically, you need to add the following value
under the registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\MDA="1"
Note that MDA is a string value.
By setting the preceding registry value, you have
notified the CLR that MDAs should be utilized. Before you can actually
make use of them though, you need to enable specific MDAs on a per
application basis. The process of enabling MDAs is done via a
configuration file that must be named according to the rule
where appname is the name of the
application that you want to enable MDAs for. The configuration file
itself contains all the MDAs that you want enabled. The best way to
illustrate this process is to look at an example. We will utilize a
sample application that can be found at the following location:
Source code: c:\adnd\chapter1\MDASample
Assembly: c:\adndbin\01mdasample.exe
The application source code (01mdasample.cs)
is very straightforward and simply starts a worker thread that spins in
an infinite loop while doing a sleep. After the new thread has been
started, the main thread simply terminates the worker thread. The big
problem observed in this code is the fact that one thread terminates
another thread. This may or may not (probably the latter in most cases)
work properly due to resource concerns. The question is, “How we can
utilize MDAs to notify us about this potential disaster?” As discussed
earlier, you need to enable MDAs via the registry. When that is
completed, the MDA application configuration file has to be created. Listing 1 shows the MDA configuration file for our sample application (01MDASample.exe.mda.config).
Listing 1. Sample MDA configuration file
<?xml version="1.0" encoding="UTF-8" ?>
<mdaConfig>
<assistants>
<asynchronousThreadAbort />
</assistants>
</mdaConfig>
|
All MDA configuration files must contain the mdaConfig element, which in turn contains the assistants element. Under the assistants element is a list of MDAs that you want enabled for the application. Please note that the assistant
elements have to be in alphanumeric order or otherwise the MDAs will
not take effect. In the case of our application, we are interested in
the asynchronousThreadAbort MDA. When the MDA configuration file is placed side by side with the application, the MDA will take effect. Listing 2 shows a run of 01MDASample.exe under the debugger with the MDA configuration file located in the same directory.
Listing 2. 01MDASample.exe with asynchronousThreadAbort specified in the configuration file
...
...
...
0:000> g
ModLoad: 76800000 768bf000 C:\Windows\system32\ADVAPI32.dll
ModLoad: 77b60000 77c23000 C:\Windows\system32\RPCRT4.dll
ModLoad: 76ad0000 76b25000 C:\Windows\system32\SHLWAPI.dll
ModLoad: 762e0000 7632b000 C:\Windows\system32\GDI32.dll
ModLoad: 76e80000 76f1e000 C:\Windows\system32\USER32.dll
ModLoad: 76d50000 76dfa000 C:\Windows\system32\msvcrt.dll
ModLoad: 765b0000 765ce000 C:\Windows\system32\IMM32.DLL
ModLoad: 76730000 767f7000 C:\Windows\system32\MSCTF.dll
ModLoad: 765d0000 765d9000 C:\Windows\system32\LPK.DLL
ModLoad: 76e00000 76e7d000 C:\Windows\system32\USP10.dll
ModLoad: 75340000 754d4000 C:\Windows\WinSxS\x86_microsoft.windows.common-
controls_6595b64144ccf1df_6.0.6000.20533_none_4634c4a0218d65c1\comctl32.dll
ModLoad: 79e70000 7a3ff000 C:\Windows\Microsoft.NET\Framework\v2.0.50727
\mscorwks.dll
ModLoad: 755e0000 7567b000 C:\Windows\WinSxS\x86_microsoft.vc80
.crt_1fc8b3b9a1e18e3b_8.0.50727.762_none_10b2f55f9bffb8f8\MSVCR80.dll
ModLoad: 76f50000 77a1e000 C:\Windows\system32\shell32.dll
ModLoad: 76330000 76474000 C:\Windows\system32\ole32.dll
ModLoad: 790c0000 79bf6000 C:\Windows\assembly\NativeImages_v2.0
.50727_32\mscorlib\32e6f703c114f3a971cbe706586e3655\mscorlib.ni.dll
ModLoad: 79060000 790b6000 C:\Windows\Microsoft.NET\Framework
\v2.0.50727\mscorjit.dll
ModLoad: 60340000 60348000 C:\Windows\Microsoft.NET\Framework
\v2.0.50727\culture.dll
ModLoad: 60340000 60348000 C:\Windows\Microsoft.NET\Framework
\v2.0.50727\culture.dll
<mda:msg xmlns:mda="http://schemas.microsoft.com/CLR/2004/10/mda">
<!--
User code running on thread 6332 has attempted to abort thread 8484. This
may result in a corrupt state or resource leaks if the thread being aborted
was in the middle of an operation that modifies global state or uses native
resources. Aborting threads other than the currently running thread is
strongly discouraged.
-->
<mda:asynchronousThreadAbortMsg break="true">
<callingThread osId="6332" managedId="1"/>
<abortedThread osId="8484" managedId="3"/>
</mda:asynchronousThreadAbortMsg>
|
From Listing 2,
we can see (in bold) that our sample application performed a
questionable action (terminating a thread) and that the debuggers
stopped execution when this action was encountered. In addition to
stopping execution, the MDA also outputted more detailed information
such as the thread IDs of the threads that terminated the worker thread
and the worker thread itself.