The approach you will take for debugging crashes is very similar between looking at the live process vs looking at a crash dump, there are some small differences that I will talk about in this post.

 The first question: What is wrong?

If the program is throwing an exception and exiting

 If the program has just crashed, the easiest thing to do it to attach a debugger to the process and see the last exception in the stack

   0:005> .loadby sos clr

The !threads command will show me all threads, the thread with an exception will have an exception on top of the stack

0:005> !threads

PDB symbol for clr.dll not loaded

ThreadCount:      2

UnstartedThread:  0

BackgroundThread: 1

PendingThread:    0

DeadThread:       0

Hosted Runtime:   no

                                                                         Lock 

   ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception

   0    1 14d0 00492eb8     2a020 Preemptive  02639428:00000000 00483e38 0     MTA System.InvalidOperationException 024f2968

   3    2 14f8 0049dd78     2b220 Preemptive  00000000:00000000 00483e38 0     MTA (Finalizer)



Now we use the !pe command to dump the exception object



0:005> !pe 024f2968

Exception object: 024f2968

Exception type:   System.InvalidOperationException

Message:          Path does not exist!

InnerException:   <none>

StackTrace (generated):

    SP       IP       Function

    001FECE8 00520155 CompareCSV!CompareCSV.Program.Main(System.String[])+0xd5

 

StackTraceString: <none>

HResult: 80131509 

Ok, now we know that it is a path does not exist exception, but which path? We can do this in two ways, if it is a small program like the one I have here I could do !dso

 0:000> !dso

OS Thread Id: 0x11fc (0)

ESP/REG  Object   Name

001FEB88 024f2968 System.InvalidOperationException

001FEBD0 024f2968 System.InvalidOperationException

001FEC20 024f22a4 System.Object[]    (System.String[])

001FEC50 024f22a4 System.Object[]    (System.String[])

001FEC98 024f22a4 System.Object[]    (System.String[])

001FECA8 024f22bc System.String    c:\invalid1

001FECC8 024f2968 System.InvalidOperationException

001FECCC 024f2968 System.InvalidOperationException

001FECE8 024f29bc System.String    Path does not exist!

001FECEC 024f2968 System.InvalidOperationException

001FECF8 024f22a4 System.Object[]    (System.String[])

001FED90 024f22a4 System.Object[]    (System.String[])

001FEEF4 024f22a4 System.Object[]    (System.String[])

001FEF2C 024f22a4 System.Object[]    (System.String[])

 

Another way to do this would be showing the CLRStack with the parameters

 

0:000> !clrstack -p

OS Thread Id: 0x11fc (0)

Child SP       IP Call Site

001fec2c 7613b9bc [HelperMethodFrame: 001fec2c]

001fece8 00520155 CompareCSV.Program.Main(System.String[]) [d:\Projects\CompareCSV\CompareCSV\Program.cs @ 25]

    PARAMETERS:

        args (0x001fecf8) = 0x024f22a4

 

And now I can dump the args passed to main, the !do command will not be very helpful since it is an array

 

0:000> !do 0x024f22a4

Name:        System.String[]

MethodTable: 6b4dfc38

EEClass:     6b1b7a50

Size:        24(0x18) bytes

Array:       Rank 1, Number of elements 2, Type CLASS

Fields:

None

 

The right thing to use is !da, which will list the array items

 

0:000> !da 0x024f22a4

Name:        System.String[]

MethodTable: 6b4dfc38

EEClass:     6b1b7a50

Size:        24(0x18) bytes

Array:       Rank 1, Number of elements 2, Type CLASS

Element Methodtable: 6b52cb5c

[0] 024f22bc

[1] 024f22e0

 

                        Now I can dump the objects and see the invalid paths!

                        0:000> !do 024f22bc

Name:        System.String

MethodTable: 6b52cb5c

EEClass:     6b15431c

Size:        36(0x24) bytes

File:        C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

String:      c:\invalid1

Fields:

      MT    Field   Offset                 Type VT     Attr    Value Name

6b52e784  40000aa        4         System.Int32  1 instance       11 m_stringLength

6b52d564  40000ab        8          System.Char  1 instance       63 m_firstChar

6b52cb5c  40000ac        c        System.String  0   shared   static Empty

    >> Domain:Value  003f7838:NotInit  <<

0:000> !do 024f22e0

Name:        System.String

MethodTable: 6b52cb5c

EEClass:     6b15431c

Size:        36(0x24) bytes

File:        C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

String:      c:\invalid2

Fields:

      MT    Field   Offset                 Type VT     Attr    Value Name

6b52e784  40000aa        4         System.Int32  1 instance       11 m_stringLength

6b52d564  40000ab        8          System.Char  1 instance       63 m_firstChar

6b52cb5c  40000ac        c        System.String  0   shared   static Empty

    >> Domain:Value  003f7838:NotInit  <<

If the program is Behaving in an unexpected way

There are various types of problems that could cause unexpected behavior, but the one I hit the most is first chance exceptions taking the code in some unexpected path, for more details check This post.

Hope you find that helpful!