Exploring UnhandledException in .NET and Watson buckets
I wanted to understand about UnhandledExceptions in .NET because of the few questions that I saw in the CLR Forum ,which had watson buckets in the event viewer. To get deep understanding unhandled exception filter there is a article on MSDN from CLR Team.
In this post I will be demonstrating how to get the Watson Bucket from within your code . FYI this is the same information you can get !WatsonBuckets from sos within Windbg whenever there is a termination of the .NET process. !WatsonBuckets is undocumented. I am using the CLR hosting interfaces to get the watson bucket. Here is the code that throws an unhandled exception and invokes clr to get watson bucket info.
using System;
using System.Runtime.InteropServices;
namespace WatsonTest
{
internal class Test
{
private static void Main(string[] args)
{
var t = AppDomain.CurrentDomain;
t.UnhandledException += (s, e) =>
{
var c = GetWatsonBuckets();
Console.WriteLine(c);
Console.Read();
};
throw new NullReferenceException();
}
private static WatsonBuckets GetWatsonBuckets()
{
var pParams = new WatsonBuckets();
IClrRuntimeHost host = null;
host = Activator.CreateInstance(Type.GetTypeFromCLSID(ClrGuids.ClsIdClrRuntimeHost)) as IClrRuntimeHost;
if (host != null)
{
var clrControl = host.GetCLRControl();
if (clrControl == null)
{
return pParams;
}
var clrErrorReportingManager =
clrControl.GetCLRManager(ref ClrGuids.IClrErrorReportingManager) as IClrErrorReportingManager;
if (clrErrorReportingManager == null)
{
return pParams;
}
clrErrorReportingManager.GetBucketParametersForCurrentException(out pParams);
}
return pParams;
}
}
// BucketParameters Structure to get watson buckets back from CLR
//http://msdn.microsoft.com/en-us/library/ms404466(v=VS.100).aspx
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct WatsonBuckets
{
internal int fInited;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0xff)] internal string pszEventTypeName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0xff)] internal string param0;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0xff)] internal string param1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0xff)] internal string param2;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0xff)] internal string param3;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0xff)] internal string param4;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0xff)] internal string param5;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0xff)] internal string param6;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0xff)] internal string param7;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0xff)] internal string param8;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0xff)] internal string param9;
}
internal static class ClrGuids
{
internal static readonly Guid ClsIdClrRuntimeHost = new Guid("90F1A06E-7712-4762-86B5-7A5EBA6BDB02");
internal static Guid IClrErrorReportingManager = new Guid("980D2F1A-BF79-4c08-812A-BB9778928F78");
internal static readonly Guid IClrRuntimeHost = new Guid("90F1A06C-7712-4762-86B5-7A5EBA6BDB02");
}
[Guid("90F1A06C-7712-4762-86B5-7A5EBA6BDB02"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IClrRuntimeHost
{
void Start();
void Stop();
void SetHostControl(IntPtr pHostControl);
IClrControl GetCLRControl();
void UnloadAppDomain(int dwAppDomainId, bool fWaitUntilDone);
void ExecuteInAppDomain(int dwAppDomainId, IntPtr pCallback, IntPtr cookie);
int GetCurrentAppDomainId();
int ExecuteApplication(string pwzAppFullName, int dwManifestPaths, string[] ppwzManifestPaths,
int dwActivationData, string[] ppwzActivationData);
int ExecuteInDefaultAppDomain(string pwzAssemblyPath, string pwzTypeName, string pwzMethodName,
string pwzArgument);
}
[Guid("9065597E-D1A1-4fb2-B6BA-7E1FCE230F61"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IClrControl
{
[return: MarshalAs(UnmanagedType.IUnknown)]
object GetCLRManager([In] ref Guid riid);
void SetAppDomainManagerType(string pwzAppDomainManagerAssembly, string pwzAppDomainManagerType);
}
// IClrErrorReportingManager to get watson bukets back from CLR
//http://msdn.microsoft.com/en-us/library/ms164367(v=VS.100).aspx
[Guid("980D2F1A-BF79-4c08-812A-BB9778928F78"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IClrErrorReportingManager
{
[PreserveSig]
int GetBucketParametersForCurrentException(out WatsonBuckets pParams);
}
}
The watson bucket information has ten items
- AppName
- Version
- ?
- Assembly and Module Name
- Assembly Version
- ?
- MethodDef
- IL Offset
- Exception Type
- ?
In the above code WatsonBuckets is a structure to get watson bucket information back from CLR. In the code I use 3 hosting interfaces, IClrRuntimeHost which is the main interface, the next interface is IClrControl which has GetCLRManager method to get ErrorReportingManger. IClrErrorReportingManager which has the method to get the exception buckets which is GetBucketParametersForCurrentException. I know that there isn’t going to be much of use for this code. But it gives me better understanding of CLR integrates with watson when ever there is termination of an application.

[...] Exploring UnhandledException in .NET and Watson buckets – Naveen takes a look at the undocumented Windbg SOS extension function !WatsonBuckets, and looks at how you can obtain additional information using the CLR hosting interface to debug exceptions. [...]
The Morning Brew - Chris Alcock » The Morning Brew #587
April 26, 2010 at 3:24 am
[...] Read full story [...]
Chirpir News | Exploring UnhandledException in .NET and Watson buckets « Naveen's …
April 26, 2010 at 9:06 pm
[...] This post was mentioned on Twitter by iAwaaz and iAwaaz, Naveen. Naveen said: Blogged: Exploring UnhandledException in .NET and Watson buckets http://bit.ly/aRrNRh #windbg #dotnet [...]
Tweets that mention Exploring UnhandledException in .NET and Watson buckets « Naveen's Blog -- Topsy.com
April 27, 2010 at 12:03 pm
[...] Reporting message in the event viewer which would have “Event Name: CLR20r3″ along with Watson bucket information like this. Fault bucket , type 0 Event Name: CLR20r3 Response: Not available Cab Id: [...]
Decoding clr20r3 .NET exception – using mono cecil « Naveen's Blog
November 16, 2010 at 9:01 pm