tags:

views:

37

answers:

3

If I have following stack trace where I see that a thread is waiting on certain lock. How can I get information about the object this thread is waiting for? I was thinking that I should be able to SyncBlk command but seem like it can only give information about the locks and its owner threads.

0:000> !CLRStack  
OS Thread Id: 0x25a8 (0)  
ESP       EIP       
001af038 77455e74 [GCFrame: 001af038]   
001af108 77455e74 [HelperMethodFrame_1OBJ: 001af108] System.Threading.Monitor.Enter(System.Object)  
001af160 00290192 ConsoleApplication1.MyClass.Main(System.String[])  
001af3c0 70fc1b4c [GCFrame: 001af3c0]   
A: 

I gave the answer in your other SO question:

How to debug managed deadlocks.

feroze
Using SyncBlk I can get the informaiton about a lock and its owner. What I want to do here is finout out what object this thread is waiting for. So for example in the example above by lookng at stack tracem this thread is waiting for a lock. How can I know which object is this thread waiting for from here. You know what i mean?
imak
A: 

In .NET reference parameters to methods are pushed onto the stack prior to calling a method, so you should find the argument for Monitor.Enter at the top of the stack if you do a !dso for the thread in question. That's the object, the code is trying to lock on.

If you correlates the address of this with the output from !threads you can find out which thread currently has this lock (if any).

Brian Rasmussen
A: 

To find out which object the thread is waiting for, you will have to do some debugging.

First, start with the stack trace that you have:

0:000> !CLRStack
OS Thread Id: 0x25a8 (0)
ESP EIP
001af038 77455e74 [GCFrame: 001af038]
001af108 77455e74 [HelperMethodFrame_1OBJ: 001af108] System.Threading.Monitor.Enter(System.Object)
001af160 00290192 ConsoleApplication1.MyClass.Main(System.String[])
001af3c0 70fc1b4c [GCFrame: 001af3c0]

Find out the frame that is calling Monitor.Enter(). In this case it is MyClass::Main(string [] args)

001af160 00290192 ConsoleApplication1.MyClass.Main(System.String[])

Now you need to disassemble the caller. Use !sos.u [eip] to do that.


0:000> !u 00d10177 
Normal JIT generated code
Program.Main(System.String[])
Begin 00d100f8, size 9d
00d100f8 55              push    ebp
00d100f9 8bec            mov     ebp,esp
00d100fb 83ec10          sub     esp,10h
00d100fe 894dfc          mov     dword ptr [ebp-4],ecx
00d10101 833de430970000  cmp     dword ptr ds:[9730E4h],0
00d10108 7405            je      00d1010f
00d1010a e802a63b79      call    mscorwks!JIT_DbgIsJustMyCode (7a0ca711)
00d1010f 33d2            xor     edx,edx
00d10111 8955f8          mov     dword ptr [ebp-8],edx
00d10114 90              nop
*** WARNING: Unable to verify checksum for C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\7bffd7ff2009f421fe5d229927588496\mscorlib.ni.dll
00d10115 b9fc7e3179      mov     ecx,offset mscorlib_ni+0x257efc (79317efc) (MT: System.Threading.ThreadStart)
00d1011a e8ad1fc5ff      call    009620cc (JitHelp: CORINFO_HELP_NEWSFAST_CHKRESTORE)
00d1011f 8945f4          mov     dword ptr [ebp-0Ch],eax
00d10122 b858c09700      mov     eax,97C058h
00d10127 50              push    eax
00d10128 6864203b00      push    3B2064h
00d1012d 8b4df4          mov     ecx,dword ptr [ebp-0Ch]
00d10130 33d2            xor     edx,edx
00d10132 e8b9a45678      call    mscorlib_ni+0x1ba5f0 (7927a5f0) (System.MulticastDelegate.CtorOpened(System.Object, IntPtr, IntPtr), mdToken: 060003bf)
00d10137 b9f8103379      mov     ecx,offset mscorlib_ni+0x2710f8 (793310f8) (MT: System.Threading.Thread)
00d1013c e8c3c41679      call    mscorwks!JIT_NewFast (79e7c604)
00d10141 8945f0          mov     dword ptr [ebp-10h],eax
00d10144 8b55f4          mov     edx,dword ptr [ebp-0Ch]
00d10147 8b4df0          mov     ecx,dword ptr [ebp-10h]
00d1014a e8e1685c78      call    mscorlib_ni+0x216a30 (792d6a30) (System.Threading.Thread..ctor(System.Threading.ThreadStart), mdToken: 060012ab)
00d1014f 8b45f0          mov     eax,dword ptr [ebp-10h]
00d10152 8945f8          mov     dword ptr [ebp-8],eax
00d10155 8b4df8          mov     ecx,dword ptr [ebp-8]
00d10158 3909            cmp     dword ptr [ecx],ecx
00d1015a e861695c78      call    mscorlib_ni+0x216ac0 (792d6ac0) (System.Threading.Thread.Start(), mdToken: 060012b1)
00d1015f 90              nop
00d10160 8b0d30202e02    mov     ecx,dword ptr ds:[22E2030h] ("Acquiring lock")
00d10166 e89d38a878      call    mscorlib_ni+0x6d3a08 (79793a08) (System.Console.WriteLine(System.String), mdToken: 060007c8)
00d1016b 90              nop
00d1016c 8b0dfc1e2e02    mov     ecx,dword ptr ds:[22E1EFCh] (Object: SyncBlock)
00d10172 e8ae281679      call    mscorwks!JIT_MonEnterWorker (79e72a25)
>>> 00d10177 90              nop
00d10178 8b0d34202e02    mov     ecx,dword ptr ds:[22E2034h] ("Releasing lock")
00d1017e e88538a878      call    mscorlib_ni+0x6d3a08 (79793a08) (System.Console.WriteLine(System.String), mdToken: 060007c8)
00d10183 90              nop
00d10184 8b0dfc1e2e02    mov     ecx,dword ptr ds:[22E1EFCh] (Object: SyncBlock)
00d1018a e8102b1679      call    mscorwks!JIT_MonExitWorker (79e72c9f)
00d1018f 90              nop
00d10190 90              nop
00d10191 8be5            mov     esp,ebp
00d10193 5d              pop     ebp
00d10194 c3              ret

Note the call site. At this point you have the following debug spew:

00d1016c 8b0dfc1e2e02    mov     ecx,dword ptr ds:[22E1EFCh] (Object: SyncBlock)
00d10172 e8ae281679      call    mscorwks!JIT_MonEnterWorker (79e72a25)
>>> 00d10177 90              nop
00d10178 8b0d34202e02    mov     ecx,dword ptr ds:[22E2034h] ("Releasing lock")
00d1017e e88538a878      call    mscorlib_ni+0x6d3a08 (79793a08) (System.Console.WriteLine(System.String), mdToken: 060007c8)
00d10183 90              nop

Just before the call to JitMon::Enter() you see the address of the object being moved into the ECX register. This is the object your thread is waiting on.

feroze
Just to be sure that I got it right, are you talking about 00d1016c 8b0dfc1e2e02 mov ecx,dword ptr ds:[22E1EFCh] (Object: SyncBlock) which mean the object thread is waiting on for is the one at 22E1EFCh correct?
imak
Also seem like the approach of using !dso that Brian suggested give me the right object too. Any ideas on pro and cos of using this approach vs what Brian suggested?
imak
Yes, that is correct. The correct object is at "!do poi(22E1EFCh)". !dso can also give you the object you are waiting on. However if you have multiple locks taken on the thread you might have to resort to disassembly. In any case, it is good to be able to read some disassembly :)
feroze