Decoding clr20r3 .NET exception – using mono cecil

I have often seen Devs trying to figure out the cause of the app crash without a memory dump. The only information that is available to analyze is the Windows Error 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: 0

Problem signature:
P1: unhandledexception.exe
P2: 1.0.0.0
P3: 4ce1e0f1
P4: LibraryCode
P5: 1.0.0.0
P6: 4ce1e0f1
P7: 7
P8: 1f
P9: System.NullReferenceException
P10:

I will demonstrate the steps in identifying the code that caused the app to crash with the above information.Here is the explanation on the Watson Bucket items

  1. P1: unhandledexception.exe – is the Exe File Name
  2. P2:1.0.0.0 – is the Exe File assembly version number
  3. P3:4ce1e0f1- is the Exe File Stamp
  4. P4:LibraryCode- is the Faulting full assembly name
  5. P5:1.0.0.0- is the Faulting assembly version
  6. P6:4ce1e0f1- is the Faulting assembly timestamp
  7. P7:7- is the Faulting assembly method def
  8. P8:1f-  is Faulting method IL Offset within the faulting method
  9. P9:System.NullReferenceException- is Exception type that was thrown

 

Here is the LibraryCode that is mentioned in P4 of the watson bucket

using System;

namespace LibraryCode
{
    public class Foo
    {
        public Foo()
        {
            Console.WriteLine("Constructor");
        }
        public void Test()
        {
            Console.WriteLine("Test");
        }
        public string Bar(string test)
        {
            var x = test;
            return x.ToUpper();
        }
        public string Bar1(string test)
        {
            var x = test;
            return x.ToUpper();
        }
        public string Bar2(string test)
        {
            var x = test;
            return x.ToUpper();
        }
        public string Bar3(string test)
        {
            var x = test;
            return x.ToUpper();
        }
        public string Bar4(string test)
        {
            int j = 10;
            for (int i = 0; i < 10; i++)
            {
                j += i;
            }
            var x = test;
            return x.ToUpper();
        }
    }
}


And here is the code for the Main method calling the LibraryCode

  static void Main(string[] args)
        {
            var f = new Foo();
            var x = Console.ReadKey();
            f.Bar4(null);
        }

The most important items in the above watson bucket are 4,7 ,8 and 9. The item 4 is the assembly that was responsible for the crash which is “LibraryCode”. The item 7 is methoddef that threw the exception which is “7”. To identify the method we would have to dump the IL and here is the command to do that.

ildasm /tokens "C:tempLibraryCode.dll" /out=libcode.il

Open the libcode.il in a text editor and look for 06000007. The methoddef starts with 06 and 7 is the hex value and when converted to decimal it is still 7 and that’s how we ended with 06000007. The IL content for the corresponding method def

.method /*06000007*/ public hidebysig instance string
Bar4(string test) cil managed
{
// Code size       42 (0x2a)

With this we know the method that caused the app to crash.

The next step is to identify the faulting IL code within the method. The IL offset that caused the exception to be thrown is 1f (decimal value is 31), and here is the IL Code

IL_001d:  ldarg.1
IL_001e:  stloc.2
IL_001f:  ldloc.2
IL_0020:  callvirt   instance string [mscorlib/*23000001*/]System.String/*01000013*/::ToUpper() /* 0A000012 */
IL_0025:  stloc.3
IL_0026:  br.s       IL_0028

Now mapping the IL code back to C# shouldn’t be hard.

And If you are like me then you would probably want to automate things , so here is doing the same using Mono Cecil

AssemblyFactory.GetAssembly(@"C:TempLibraryCode.dll")
		.MainModule.Types.Cast<TypeDefinition>()
		.ElementAt(1)
		.Methods.Cast<MethodDefinition>().First(md => md.MetadataToken.RID == 7)
		.Body.Instructions.Cast<Instruction>()
		.Select (i => 
			new {Offset = i.Offset, 
			OpCode = i.OpCode.ToString() , 
			Operand = i.Operand != null ? i.Operand.ToString() : string.Empty} )
		.Dump();

Notice the above code looks for methoddef “7” which is the P7 item in the Watson bucket.The code could have just dumped 31st IL offset which is “ldloc.2” but that would not help , I like to see the entire method to figure out the cause of the exception.

And here is the output from above code.

We cannot get the call-stack for the crash with just watson buckets.

 

Customizing Witty Twitter Client Part 1- using C# as Compiler Service

This is going to be a multipart blog post where I am going to be demonstrating how I have customized Witty twitter client for my need. I chose Witty because it is the only OSS .NET twitter client I know of.

One of the reasons for customizing is primarily using C# as compiler service to extend it for my needs dynamically. For example I follow this twitter list http://twitter.com/shanselman/programmers , it’s a cool list that Scott maintains, thanks to him. But there is one person in this list who keeps tweeting about weight loss, which I am least interested and I didn’t have control over it but to ignore, until now. And it is always fun to write  software for your daily needs, which for me saves time.  Thanks to Mono for C# as compiler service. FYI I have shown a simple usage of Mono Csharp compiler service in this post.

Here are things that I could get done by just spending few hours of my weekend time

Here is my the default witty

Filter the list by user name  which I am not interested in


new Func<Tweet, bool>(t => !t.User.Name.Contains("CNN"));

Here is the same without CNN

FYI the filter C# code is in the Filter Text box

The next filter criteria is to look for tweets that have hashtag as fsharp and also at least have one link


new Func<Tweet, bool>(t => t.HashTags.DefaultIfEmpty().Contains("#fsharp") && t.Urls.DefaultIfEmpty().Count() > 0);

And here is the filtered list

Be even crazier look for tweets that have hashtag as fsharp and at least one link and then open the link automatically

new Func<Tweet, bool>(t => {
 if (t.HashTags.DefaultIfEmpty().Contains("#fsharp") && t.Urls.DefaultIfEmpty().Count() > 0)
 System.Diagnostics.Process.Start(t.Urls.First().ToString());
 return t.HashTags.DefaultIfEmpty().Contains("#fsharp") && t.Urls.DefaultIfEmpty().Count() > 0; });

The browser with the link opened automatically.

It’s a hack and I shouldn’t be doing the above, but it does the job.

There is so much more possibilities. I could easily provide a save feature for these search scripts and reuse the same.  At the end of the series I will post the entire code in GitHub. But if you want to try it before that here are the simple changes I started doing to the code.

Extension Method for Compilation


static class Extensions
 {
 public static object Compile(this string code)
 {
 return Mono.CSharp.Evaluator.Evaluate(code);
 }
 public static void Run(this string code)
 {
 Mono.CSharp.Evaluator.Run(code);
 }
 }

The filter code


public bool TweetFilter(object item)
 {
 Tweet tweet = item as Tweet;

 // this will prevent the fade animation from starting when the tweet is filtered
 tweet.IsNew = false;
 try
 {
 Func<Tweet, bool> compare = (Func<Tweet, bool>)FilterTextBox.Text.Compile();
 return compare.Invoke(tweet);
 }
 catch(Exception ex)
 {
 Console.WriteLine(ex);

 }
 return true;
 }

The hashtags and Links weren’t part of the tweet class , but they were part of the UI class. So I had to bring them to the tweet class and populate them.

public IEnumerable<Uri> Urls
 {
 get
 {
 return links;
 }
 set
 {
 links.Clear();
 links.AddRange(value);
 }
 }
 public IEnumerable<string> HashTags
 {
 get
 {
 return hashTags;
 }
 set
 {
 hashTags.Clear();
 hashTags.AddRange(value);
 }
 }

And here is the code to populate the above properties

private IEnumerable<Uri> GetLinks(string text)
 {
 string[] words = Regex.Split(text, @"([ (){}[]])");
 return (from word in words
 let isUrl = new Func<string, bool>(s => UrlShorteningService.IsUrl(s))
 where isUrl(word)
 select new Uri(word) ).ToList();
 }
 private IEnumerable<string> GetHashTags(string text)
 {
 string[] words = Regex.Split(text, @"([ (){}[]])");
 return (from word in words
 let ishash = new Func<string, bool>(s => s.StartsWith("#"))
 where ishash(word)
 select word).ToList();
 }

I know for the above 2 functions I could have written a High-Order Function