Thursday, July 30, 2009

Finding CLR exceptions without visual studio

(If you want to understand what exception code 0xe0434352 is, read this post)



Often exceptions are thrown and caught and you don't see them. You probably know how to debug this in Visual Studio, so let me show you how to do it in cdb.

Sample Code:





class Program
{
static void Main(string[] args)
{
foreach (var x in Enumerable.Range(0,2000))
{
Thread.Sleep(TimeSpan.FromSeconds(1));
Console.WriteLine("Hello World");
ThrowAndCatchException();
}

}

private static void ThrowAndCatchException()
{
try
{
throw new NotImplementedException();
}
catch(Exception)
{
}
}
}
Output of the application:

Hello World
Hello World
Hello World
Nothing about an exception, but you're sure it's happening behind the covers -- fire up cdb:

C:\Program Files\Debugging Tools for Windows (x64)>cdb -pn consoleapplication3.exe

<SNIP>

ModLoad: 000007fe`f7e90000 000007fe`f7eb4000 C:\Windows\Microsoft.NET\Framework64\v4.0.20506\culture.dll
(ff8.17a8): Break instruction exception - code 80000003 (first chance)
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\SYSTEM32\ntdll.dll -
ntdll!DbgBreakPoint:
00000000`77b7d7b0 cc int 3
Continue debugging:

0:004> g
Exceptions - lots of them:

(ff8.16dc): CLR exception - code e0434352 (first chance)
(ff8.16dc): CLR exception - code e0434352 (first chance)
(ff8.16dc): CLR exception - code e0434352 (first chance)
(ff8.16dc): CLR exception - code e0434352 (first chance)
(ff8.16dc): CLR exception - code e0434352 (first chance)
(ff8.16dc): CLR exception - code e0434352 (first chance)
(ff8.1860): Break instruction exception - code 80000003 (first chance)
Break on CLR exceptions:

0:004> sxe clr
0:004> g

(ff8.16dc): CLR exception - code e0434352 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\system32\KERNELBASE.dll -
KERNELBASE!RaiseException+0x3d:
000007fe`fdb8bb5d 4881c4c8000000 add rsp,0C8h
Load sos ( in .Net 2/3 use use !loadby sos mscorwks):

0:000> !loadby sos clr
View Stack:

0:000> !CLRStack
PDB symbol for clr.dll not loaded
OS Thread Id: 0x16dc (0)
Child SP IP Call Site
000000000096e6a8 000007fefdb8bb5d [HelperMethodFrame: 000000000096e6a8]
000000000096e7c0 000007ff00170360 ConsoleApplication3.Program.ThrowAndCatchException()
000000000096e810 000007ff001701fb ConsoleApplication3.Program.Main(System.String[])
000000000096ec90 000007feef474ca4 [GCFrame: 000000000096ec90]
View Exception:

0:000> !PrintException
Exception object: 0000000002c88c18
Exception type: System.NotImplementedException
Message: The method or operation is not implemented.
InnerException: <none>
StackTrace (generated):
<none>
StackTraceString: <none>
HResult: 80004001
0:000>
Pretty neat - eh?

Saturday, July 18, 2009

Why write programs that don't modify variables?

Slews of bugs happen because variable have values you aren't expecting. To minimize this class of bugs I use a technique a lot of people find surprising. I try to only assign and never modify variables. In C++, I make almost all my variables const.

C++ people are now saying -- Um if all your values are const how do you write a for loop?

In C++ I can't help myself, I'm stuck with a variable modification eg:

for (size_t x=0;x<6;x++) printf("%d",x)
In python the for loop naturally iterates over a sequence so you don't need to modify a value:
for x in range(6): print x
In C#, you can use either the C++ syntax or a more python syntax via foreach:
for (int x=0;x<6;x++) Console.WriteLine(x);
or
foreach (var x in Enumerable.Range(0,6)) Console.WriteLine(x)

I use the foreach syntax which people initially find confusing. But its value starts to shine when using non zero starting values. Assume I need to generate 113 numbers starting at 27. Which statement do you find expresses it better.
for (int x=27;x<=139;x++) Console.WriteLine(x)

or
foreach (var x in Enumerable.Range(27,113)) Console.WriteLine(x)

Saturday, July 4, 2009

How to attach to an already running debugger target using cdb.

For the last year when I wanted to attach to a process using cdb, I'd attach by PID. This meant i'd need to the following dance:
    C:\Program Files\Debugging Tools for Windows (x64)>tlist |findstr firefox
9128 cmd.exe findstr firefox
276 firefox.exe Restore Session - Vimperator

C:\Program Files\Debugging Tools for Windows (x64)>cdb -p 276
It turns out you can just do:

C:\Program Files\Debugging Tools for Windows (x64)>cdb -pn firefox.exe

Microsoft (R) Windows Debugger Version 6.11.0001.404 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.


If there are multiple instances of your process, you'll still need to use tlist
to find the PID you're interested in.