About how to use WinDebug to view thread deadlocks, windebug to view threads
Recently, the project is coming to an end. However, when the project reaches the test stage, there is a big problem. Occasionally, the interface is stuck so that it cannot be tested in the future. I initially suspect that it is deadlocked because I am not very familiar with WinDebug, I only know that WinDebug has the functions such as memory leakage, thread deadlock, and so on. So I told the following users to use winDebug to find the problem. There are many network resources, after some research, we found a solution to WInDebug deadlock search. However, as a project development manager, it is naturally necessary to provide corresponding help when deadlocks cannot be solved at the same time, so I learned how to find the deadlock in WinDebug with this mentality, which is summarized as follows:
Deadlock:
(1) There are at least two or more locks. If there are only two locks, and they are locks A and B;
(2) thread 1 has taken A lock A and wants to get the lock B. Thread 2 has taken A lock B and wants to get the lock;
(3) failing to obtain another lock does not forcibly release the lock obtained by itself;
So the deadlock came ~
Implement all instances:
(1) initialize two locks, A and B, and start two threads (one main thread and one subthread );
(2) The first thread has taken lock A, the second thread has taken lock B, the first thread tries to get lock B, and the second thread tries to get lock;
Based on the above idea, I wrote a Demon, a deadlock occurred, and then used WinDebug to find the deadlock. The method is described as follows:
(1) enable the user stack function of the application-the winDebug binding process fails because I didn't enable it when I started using WinDebug;
Worker uses gflags.exe in windebugdirectory to open the command line and enter the WinDebug directory to run: gflag.exe/I debug exe full path + ust
Press enter, and ust is the user stack;
(2) Open WinDebug and SELECT File --> Attach to Process to Attach the Process exe to be debugged;
To view all thread stacks, enter the following in the Command window :~ * Kv
Output all the following thread stacks:
In this case, the stack of all threads can be opened. To view the stack of a thread, enter * 1kv, that is, the stack of thread 1; we can see the stack information of each thread from the stack of all threads. If there is a stack lock at this time, there will usually be an API call at the top of the stack: ntdll! RtlpWaitOnCriticalSection, that is, we can find the corresponding deadlock thread information by finding all the calls to this API;
0 Id: 11264.10f20 Suspend: 1 Teb: 7efdd000 Unfrozen
ChildEBP RetAddr Args to Child
003eecd8 77709e2e 00000124 00000000 00000000 ntdll! ZwWaitForSingleObject + 0x15 (FPO: [3, 0])
003eed3c 77709d12 00000000 00000000 00000001 ntdll! RtlpWaitOnCriticalSection + 0x13e (FPO: [Non-Fpo])
003eed64 0113e289 0161cd80 c3c8e76a 00000001 ntdll! RtlEnterCriticalSection + 0x150 (FPO: [Non-Fpo])
003eee7c 011548ff 003ef808 003eeeb4 757d62fa LockDemon! CLockDemonDlg: OnInitDialog + 0x179 (FPO: [Non-Fpo]) (CONV: thiscall) [e: \ work \ c ++ \ test \ lockdemon \ lockdemondlg. cpp 122]
003eee88 757d62fa 002d1984 00000110 001d1b26 LockDemon! AfxDlgProc + 0x3f (CONV: stdcall) [f: \ dd \ vctools \ vc7libs \ ship \ atlmfc \ src \ mfc \ dlgcore. cpp @ 28]
003eeeb4 757ff9df 01119035 002d1984 00000110 USER32! InternalCallWinProc + 0x23
003eef30 757ff784 00000000 01119035 002d1984 USER32! UserCallDlgProcCheckWow + 0xd7 (FPO: [Non-Fpo])
003eef80 757ff889 0409a140 00000000 00000110 USER32! DefDlgProcWorker + 0xb7 (FPO: [Non-Fpo])
003eefa0 757d62fa 002d1984 00000110 001d1b26 USER32! DefDlgProcW + 0x29 (FPO: [Non-Fpo])
003 eefcc 757d6d3a 77734308 002d1984 00000110 USER32! InternalCallWinProc + 0x23
003ef044 757e0d27 00000000 77734308 002d1984 USER32! UserCallWinProcCheckWow + 0x109 (FPO: [Non-Fpo])
003ef07c 757e0d4d 77734308 002d1984 00000110 USER32! CallWindowProcAorW + 0xab (FPO: [Non-Fpo])
003ef09c 0115e4d4 77734308 002d1984 00000110 USER32! CallWindowProcW + 0x1b (FPO: [Non-Fpo])
003ef0c0 0115c5fd 00000110 001d1b26 00000000 LockDemon! CWnd: DefWindowProcW + 0x34 (CONV: thiscall) [f: \ dd \ vctools \ vc7libs \ ship \ atlmfc \ src \ mfc \ wincore. cpp @ 1043]
003ef0dc 01156235 003ef808 003ef0f8 012282d3 LockDemon! CWnd: Default + 0x3d (CONV: thiscall) [f: \ dd \ vctools \ vc7libs \ ship \ atlmfc \ src \ mfc \ wincore. cpp @ 274]
003ef100 011603e5 001d1b26 00000000 c3c8fb46 LockDemon! CDialog: HandleInitDialog + 0xd5 (CONV: thiscall) [f: \ dd \ vctools \ vc7libs \ ship \ atlmfc \ src \ mfc \ dlgcore. cpp @ 673]
003ef250 0115fb62 00000110 001d1b26 00000000 LockDemon! CWnd: OnWndMsg + 0x835 (CONV: thiscall) [f: \ dd \ vctools \ vc7libs \ ship \ atlmfc \ src \ mfc \ wincore. cpp @ 2018]
003ef270 0115c400 00000110 001d1b26 00000000 LockDemon! CWnd: WindowProc + 0x32 (CONV: thiscall) [f: \ dd \ vctools \ vc7libs \ ship \ atlmfc \ src \ mfc \ wincore. cpp @ 1755]
003ef2ec 0115cb16 003ef808 002d1984 00000110 LockDemon! AfxCallWndProc + 0xf0 (CONV: stdcall) [f: \ dd \ vctools \ vc7libs \ ship \ atlmfc \ src \ mfc \ wincore. cpp @ 240]
003ef30c 757d62fa 002d1984 00000110 001d1b26 LockDemon! AfxWndProc + 0xa6 (CONV: stdcall) [f: \ dd \ vctools \ vc7libs \ ship \ atlmfc \ src \ mfc \ wincore. cpp @ 403]
003ef338 757d6d3a 01127310 002d1984 00000110 USER32! InternalCallWinProc + 0x23
003ef3b0 757d6de8 00000000 01127310 002d1984 USER32! UserCallWinProcCheckWow + 0x109 (FPO: [Non-Fpo])
003ef40c 757d6e44 0409a140 00000000 00000110 USER32! DispatchClientMessage + 0xe0 (FPO: [Non-Fpo])
003ef448 776e010a 003ef460 00000000 003ef694 USER32! _ FnDWORD + 0x2b (FPO: [Non-Fpo])
003ef45c 0409a140 00000000 00000110 001d1b26 ntdll! KiUserCallbackDispatcher + 0x2e (FPO: [0, 0])
WARNING: Frame IP not in any known module. Following frames may be wrong.
003ef4c0 7580206f 0409a140 00000000 01127310 0x409a140
003ef594 758010d3 00f00000 00000006 000000a4 USER32! InternalCreateDialog + 0xb9f (FPO: [Non-Fpo])
003ef5b8 757ec659 00f00000 0163fdc8 00000000 USER32! CreateDialogIndirectParamAorW + 0x33 (FPO: [Non-Fpo])
003ef5d8 01155513 00f00000 0163fdc8 00000000 USER32! CreateDialogIndirectParamW + 0x1b (FPO: [Non-Fpo])
003ef6a0 01155e39 0163fdc8 00000000 00f00000 LockDemon! CWnd: CreateDlgIndirect + 0x263 (CONV: thiscall) [f: \ dd \ vctools \ vc7libs \ ship \ atlmfc \ src \ mfc \ dlgcore. cpp @ 312]
003ef714 0113da0d c3c8f1a6 00000000 00000000 LockDemon! CDialog: DoModal + 0x199 (CONV: thiscall) [f: \ dd \ vctools \ vc7libs \ ship \ atlmfc \ src \ mfc \ dlgcore. cpp @ 576]
003ef8b0 0153da94 757d9ee1 003ef8c0 00280026 LockDemon! CLockDemonApp: InitInstance + 0xad (CONV: thiscall) [e: \ work \ c ++ \ test \ lockdemon. cpp @ 64]
003ef8d4 0153d98a 00f00000000000 006710b4 LockDemon! AfxWinMain + 0x84 (CONV: stdcall) [f: \ dd \ vctools \ vc7libs \ ship \ atlmfc \ src \ mfc \ winmain. cpp @ 37]
003ef8ec 014c1015 00f00000 00000000 006710b4 LockDemon! WWinMain + 0x1a (CONV: stdcall) [f: \ dd \ vctools \ vc7libs \ ship \ atlmfc \ src \ mfc \ appmodul. cpp @ 34]
003ef990 014c0e9f 003ef9a4 76e0336a 7efde000 LockDemon! _ TmainCRTStartup + 0x165 (CONV: cdecl) [f: \ dd \ vctools \ crt_bld \ self_x86 \ crt \ src \ crt0.c @263]
003ef998 76e0336a 7efde000 003ef9e4 777092b2 LockDemon! WWinMainCRTStartup + 0xf (CONV: cdecl) [f: \ dd \ vctools \ crt_bld \ self_x86 \ crt \ src \ crt0.c @182]
003ef9a4 777092b2 7efde000 61654582 00000000 kernel32! BaseThreadInitThunk + 0xe (FPO: [Non-Fpo])
003ef9e4 77709285 0111a958 7efde000 00000000 ntdll! _ RtlUserThreadStart + 0x70 (FPO: [Non-Fpo])
003ef9fc 00000000 0111a958 7efde000 00000000 ntdll! _ RtlUserThreadStart + 0x1b (FPO: [Non-Fpo])
1 Id: 11264.11284 Suspend: 1 Teb: 7efda000 Unfrozen
ChildEBP RetAddr Args to Child
0631fe7c 759714ab 00000104 00000000 00000000 ntdll! ZwWaitForSingleObject + 0x15 (FPO: [3, 0])
0631fee8 76e01194 00000104 ffffffff 00000000 KERNELBASE! WaitForSingleObjectEx + 0x98 (FPO: [Non-Fpo])
0631ff00 76e01148 00000104 ffffffff 00000000 kernel32! WaitForSingleObjectExImplementation + 0x75 (FPO: [Non-Fpo])
0631ff14 7235366b 00000104 ffffffff 76e010ff kernel32! WaitForSingleObject + 0x12 (FPO: [Non-Fpo])
WARNING: Stack unwind information not available. Following frames may be wrong.
0631ff58 7235290a 72377db8 76e0336a 72377db8 CKSee + 0x0000b
0631ff6c 777092b2 72377db8 676a43ca 00000000 CKSee! Kinkoo_GetInterface + 0x13aa
0631 ffac 77709285 72352900 72377db8 00000000 ntdll! _ RtlUserThreadStart + 0x70 (FPO: [Non-Fpo])
0631ffc4 00000000 72352900 72377db8 00000000 ntdll! _ RtlUserThreadStart + 0x1b (FPO: [Non-Fpo])
2 Id: 11264.9238 Suspend: 1 Teb: 7efd7000 Unfrozen
ChildEBP RetAddr Args to Child
064efbf4 77709e2e 00000120 00000000 00000000 ntdll! ZwWaitForSingleObject + 0x15 (FPO: [3, 0])
064efc58 77709d12 00000000 00000000 005819a0 ntdll! RtlpWaitOnCriticalSection + 0x13e (FPO: [Non-Fpo])
064efc80 01140f78 0161cd68 00000000 00000000 ntdll! RtlEnterCriticalSection + 0x150 (FPO: [Non-Fpo])
064efd58 014c22e3 003ef808 c5b8f482 00000000 LockDemon! MyFunc + 0x48 (FPO: [Non-Fpo]) (CONV: stdcall) [e: \ work \ c ++ \ test \ lockdemon \ lockdemondlg. cpp @ 79]
064efd94 014c2254 00000000 064 efdac 76e0336a LockDemon! _ Callthreadstartex + 0x53 (CONV: cdecl) [f: \ dd \ vctools \ crt_bld \ self_x86 \ crt \ src \ threadex. c @ 348]
064efda0 76e0336a 005819a0 064 efdec 777092b2 LockDemon! _ Threadstartex + 0xa4 (CONV: stdcall) [f: \ dd \ vctools \ crt_bld \ self_x86 \ crt \ src \ threadex. c @ 331]
064 efdac 777092b2 005819a0 6715418a 00000000 kernel32! BaseThreadInitThunk + 0xe (FPO: [Non-Fpo])
064 efdec 77709285 014c21b0 005819a0 00000000 ntdll! _ RtlUserThreadStart + 0x70 (FPO: [Non-Fpo])
064efe04 00000000 014c21b0 005819a0 00000000 ntdll! _ RtlUserThreadStart + 0x1b (FPO: [Non-Fpo])
#3 Id: 11264.1175c Suspend: 1 Teb: 7ef9f000 Unfrozen
ChildEBP RetAddr Args to Child
0580fcf8 7776fb96 64db414e 00000000 00000000 ntdll! DbgBreakPoint (FPO: [0, 0])
0580fd28 76e0336a 00000000 0580fd74 777092b2 ntdll! DbgUiRemoteBreakin + 0x3c (FPO: [Non-Fpo])
0580fd34 777092b2 00000000 64db4112 00000000 kernel32! BaseThreadInitThunk + 0xe (FPO: [Non-Fpo])
0580fd74 77709285 7776fb5a 00000000 00000000 ntdll! _ RtlUserThreadStart + 0x70 (FPO: [Non-Fpo])
0580fd8c 00000000 7776fb5a 00000000 00000000 ntdll! _ RtlUserThreadStart + 0x1b (FPO: [Non-Fpo])
From this we can see that there are a total of 0-3 4 threads, green represents the thread index number, blue represents the thread address (11264-bit thread ID in 11264.1175c, 1175c is the thread address ), of course, it is difficult for all threads to find the lock one by one to observe the deadlock. In order to print the deadlock between threads in the process, directly use the following command
First, check all the locks in the process and enter the command :! Locks, as follows:
0: 003>! Locks
In this case, all lock information in the process is printed:
CritSec LockDemon! G_LockA + 0 at 0161cd80
WaiterWoken No
LockCount 1
RecursionCount 1
OwningThread 9238
EntryCount 0
ContentionCount 1
* ** Locked
CritSec LockDemon! G_LockB + 0 at 0161cd68
WaiterWoken No
LockCount 1
RecursionCount 1
OwningThread 10f20
EntryCount 0
ContentionCount 1
* ** Locked
The first lock address is 0161cd80, LockCount indicates the number of locks occupied, and RecursionCount indicates the number of times the owner thread enters the lock (after obtaining the lock, it can also enter multiple times ), the owner thread of OwningThread is 9238, that is, the 0161cd80 lock is occupied by the address 9238 thread, that is, the thread index number is 2, and the thread ID is 11264. The thread with the thread address 9238 has obtained the 0161cd80 lock, while waiting for the lock 0161cd68
The second lock address is 0161cd68, LockCount indicates the number of locks occupied, and RecursionCount indicates the number of times the owner thread enters the lock (after obtaining the lock, it can also enter multiple times ), owningThread owner thread is 10f20, that is, the 0161cd68 lock is occupied by the 10f20 thread address, that is, the thread index is 0, and the thread ID is 11264. The thread whose thread address is 10f20 has obtained the 0161cd68 lock, while waiting for the lock 0161cd80
In this way, the deadlock is determined, and Thread 0 and thread 2 are mutually locked!
Stack column information is described as follows:
2 Id: 11264.9238 Suspend: 1 Teb: 7efd7000 Unfrozen
ChildEBP RetAddr Args to Child
064efbf4 77709e2e 00000120 00000000 00000000 ntdll! ZwWaitForSingleObject + 0x15 (FPO: [3, 0])
064efc58 77709d12 00000000 00000000 005819a0 ntdll! RtlpWaitOnCriticalSection + 0x13e (FPO: [Non-Fpo])
064efc80 01140f78 0161cd68 00000000 00000000 ntdll! RtlEnterCriticalSection + 0x150 (FPO: [Non-Fpo])
064efd58 014c22e3 003ef808 c5b8f482 00000000 LockDemon! MyFunc + 0x48 (FPO: [Non-Fpo]) (CONV: stdcall) [e: \ work \ c ++ \ test \ lockdemon \ lockdemondlg. cpp @ 79]
064efd94 014c2254 00000000 064 efdac 76e0336a LockDemon! _ Callthreadstartex + 0x53 (CONV: cdecl) [f: \ dd \ vctools \ crt_bld \ self_x86 \ crt \ src \ threadex. c @ 348]
064efda0 76e0336a 005819a0 064 efdec 777092b2 LockDemon! _ Threadstartex + 0xa4 (CONV: stdcall) [f: \ dd \ vctools \ crt_bld \ self_x86 \ crt \ src \ threadex. c @ 331]
064 efdac 777092b2 005819a0 6715418a 00000000 kernel32! BaseThreadInitThunk + 0xe (FPO: [Non-Fpo])
064 efdec 77709285 014c21b0 005819a0 00000000 ntdll! _ RtlUserThreadStart + 0x70 (FPO: [Non-Fpo])
064efe04 00000000 014c21b0 005819a0 00000000 ntdll! _ RtlUserThreadStart + 0x1b (FPO: [Non-Fpo])
The third column is the first parameter of the subsequent API. The first parameter of the API, namely the RtlEnterCriticalSection, is the lock address of the third column, that is, when the thread id is 2 (the thread address is 0x9238), the thread is waiting for the lock 0x0161cd68
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.