Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I view the local variables on the evaluation stack when debugging a .NET CLR application?

I'm using Windbg (with the sos extention) and trying to debug a crashed application. I was able to dump the IL of the call that threw the exception and by examining the code, it seems like I could obtain the information that I need if I could dump the contents of the evaluation stack. Is it possible to do what with WinDbg & sos ?

Here's what I did:

  1. Started WinDbg
  2. Attached to the crashed process
  3. loadby sos mscorwks (to load the sos extension)
  4. !token2ee theModuleName 0600009a (where theModuleName is the name of the app(and assembly) t hat I'm debuging and 9a is the method offset of the method that crashed as reported by the Windows Error Reporting tool. I got this output:

    Module: 000e2c3c (theApplicationName.exe)
    Token: 0x0600009a
    MethodDesc: 000e67c8
    Name: MyNamespace.MyClassName.theCulpritFn(MyOtherClass)
    JITTED Code Address: 0081b1d0

  5. !dumpil 00e67c8 (which dumped the IL for the method in question). This is the output:

    
    // ..
    // .. the previous code omitted for brevity
    .catch
    {
     IL_0071: stloc.0
     IL_0072: nop
     IL_0073: ldstr "Can't set CurrentServer property for: "
     IL_0078: ldarg.0
     IL_0079: ldfld MyNamespace.MyClassName::_currentServer
     IL_007e: brtrue.s IL_0087
     IL_0080: ldstr ""
     IL_0085: br.s IL_0092
     IL_0087: ldarg.0
     IL_0088: ldfld MyNamespace.MyClassName::_currentServer
     IL_008d: callvirt MyNamespace.MyOtherClass::get_Name
     IL_0092: call System.String::Concat
     IL_0097: ldloc.0
     IL_0098: newobj MyNamespace.MySpecialExceptionType::ctor
     IL_009d: throw
    } 
    

    The question is: is there a way for me to see what was pushed on the stack before the exception was thrown. If I'm not mistaken, the argument passed into the exception constructor should be the local variable at index 0 on the evaluation stack.

    P.S. When I tried to call !clrstack -a I got a message saying: Unable to walk the managed stack. The current thread is likely not a managed thread. You can run !threads to get a list of managed threads in the process.

Thanks!

like image 321
Mike Dinescu Avatar asked Feb 06 '09 22:02

Mike Dinescu


People also ask

How do I show variables in debug mode?

The most commonly used way to look at variables is the DataTip. When stopped in the debugger hover the mouse cursor over the variable you want to look at. The DataTip will appear showing you the value of that variable.

Where are local variables on the stack?

The stack is used for dynamic memory allocation, and local variables are stored at the top of the stack in a stack frame.

How do I show local variables in Visual Studio?

To open the Locals window, while debugging, select Debug > Windows > Locals, or press Alt+4. This topic applies to Visual Studio on Windows.


2 Answers

You need to identify and select the right thread. The id of the current thread is displayed in the WinDbg prompt.

!threads will display all managed threads in your application. Once identified you can switch threads using ~Xs where X is the WinDbg id for the thread.

!clrstack will show you the stack trace. If you want locals and/or parameters use -l / -p (or -a for both).

You can go through all the threads and list their call stack with ~*e!clrstack.

If local/parameters doesn't give you what you need, use !dso to display objects pushed onto the stack.

like image 188
Brian Rasmussen Avatar answered Oct 14 '22 14:10

Brian Rasmussen


Wow, this hard without an actual dump to poke through. :-)

Here are a couple of questions.. and then I'll add one command that was not listed previously in the answers above..

Questions:

  1. Are you sure you are catching the first exception and not just the last one that was unhandled and torn down the process?

  2. Can you take a look at the native call stack for the thread that threw the exception.
    Note: there should be a call to RaiseException() or a access violation.

  3. Beware of Asynchronous exceptions that have absolutely nothing to do with your code and can come in and pop you into a catch block... or worse (Thread.AbortException/System.OutofMemoryException and... StackOverflowException :-)

To dig in further you run !dumpstack on the faulting thread.. The output is not exact however it does do an amazing job of walking the threads call stack and you may get lucky and see a @ symbol that references a exception with .cxr and .exr in the message. If you do, then you can run .cxr -cxr-address and see what the first exception was in the exception chain.

Point: Although I may be side stepping the question, if the exception invoked WER it was not handled and took down the process you may want to Log the initial call stack or add the previous exception as an inner exception so you can determine the root cause.

Thanks, Aaron

like image 34
AaronBa Avatar answered Oct 14 '22 13:10

AaronBa