首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用WinDbg查找谁持有本机进程的SRW

使用WinDbg查找谁持有本机进程的SRW
EN

Stack Overflow用户
提问于 2020-03-31 09:55:15
回答 2查看 1.2K关注 0票数 1

我有一个由c++编写的程序,我很难找到哪个线程已经获得了Slim阅读器/作家(SRW)锁。我搜索并找到了确定保存ReaderWriterLockSlim WriteLock的方法,但它是关于C#编写的一个程序的。此外,一些命令,例如.rwlock,是不可接受的。

代码语言:javascript
运行
复制
0:796> !handle 0 ff Mutant
Handle c
  Type          Mutant
  Attributes    0
  GrantedAccess 0x1f0001:
         Delete,ReadControl,WriteDac,WriteOwner,Synch
         QueryState
  HandleCount   4
  PointerCount  103240
  Name          \BaseNamedObjects\DBWinMutex
  Object Specific Information
    Mutex is Free
Handle 474
  Type          Mutant
  Attributes    0
  GrantedAccess 0x1f0001:
         Delete,ReadControl,WriteDac,WriteOwner,Synch
         QueryState
  HandleCount   2
  PointerCount  65536
  Name          \BaseNamedObjects\SM0:928:304:WilStaging_02
  Object Specific Information
    Mutex is Free
2 handles of type Mutant
0:796> kb
RetAddr           : Args to Child                                                           : Call Site
00007ff9`b6e3d33a : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!ZwWaitForAlertByThreadId+0x14
00007ff9`a85726a9 : 00000000`00000000 00000000`00000000 00000192`83338180 00000000`00000000 : ntdll!RtlAcquireSRWLockExclusive+0x13a
00007ff9`a6231724 : c000000d`00000000 00000000`00000000 00000192`83338180 00000000`00000002 : MSVCP140!mtx_do_lock+0x7d [d:\agent\_work\2\s\src\vctools\crt\crtw32\stdcpp\thr\mutex.cpp @ 106]
00007ff9`a626749e : 00000192`f6a26e38 00000193`4aaa3d80 00000052`897fea60 00000000`00000000 : AZSDK!AZConnection::Post+0x54 [g:\prod\sdk\src\connection.cpp @ 1147]
...
00007ff9`9c8ba9c1 : 00000192`c3b3d770 00000000`00000000 00000192`f5d616b0 00000000`00000000 : prod!Task::Execute+0x28 [g:\prod\src\task.cpp @ 51]
00007ff9`b6e97529 : 00000193`491b9830 00000000`7ffe0386 00000052`897ff998 00000193`491b98f8 : prod!Proxy::TaskExecuter+0x11 [g:\prod\src\proxy.cpp @ 2042]
00007ff9`b6e3bec4 : 00000000`00000000 00000192`f1dd03a0 00000000`00000000 00000000`00000000 : ntdll!TppSimplepExecuteCallback+0x99
00007ff9`b6c47e94 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!TppWorkerThread+0x644
00007ff9`b6e87ad1 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x14
00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21
0:796> !rwlock
No export rwlock found

C++代码片段:

代码语言:javascript
运行
复制
std::mutex m_mutex;

Status AZConnection::Post(const Request* request, Result** pResult)
{
    std::lock_guard<std::mutex> sbguard(m_mutex);
}

更新:

根据鲁斯特克斯的回答的说法,我明白了。现在我必须放弃。

事实上,我的程序还在运行,但已经停止使用了。我得找出原因。我发现有806个线程,其中大多数都在焦急地等待Post。此外,如果它不能再现,我不能重新开始添加一个日志打印谁已经获得了锁。因此,我只想检查持有锁的线程正在执行什么操作。

EN

Stack Overflow用户

发布于 2020-04-01 15:05:32

我可以使用!foreachframe!ifWinDbg的MEX调试扩展中对调用堆栈进行grep,并执行一个命令(不支持由;;(指挥分离员)分隔的多个命令),以查找不是为锁而瓦特但其上一次调用为Post的线程。扩展可以从这里下载。下载后,可以将其放入C:\WinDDK\7600.16385.1\Debuggers\winext (也请参阅加载调试器扩展DLL)。

在下面的代码中,我用msvcrt!_threadstartex替换了msvcrt!_threadstartex,用KERNEL32!BaseThreadInitThunk替换了AZSDK!AZConnection::Post,举个例子:

代码语言:javascript
运行
复制
~*e r @$t0 = -1; !foreachframe -q -f 'KERNEL32!BaseThreadInitThunk' r @$t0= @#FrameNum - 1; .if(0<=@$t0) { !if -DoesNotContainRegex 'msvcrt!_threadstartex' -then '.printf /D "Thread: <link cmd=\"~~[%x]\">0x%x</link> (<link cmd=\"!mex.t %d\">%d</link>)", $tid, $tid, $dtid, $dtid' .frame @$t0 }

!foreachthread -q !foreachframe -q -f 'KERNEL32!BaseThreadInitThunk' !if -DoesNotContainRegex 'msvcrt!_threadstartex' -then '.printf /D "Thread: <link cmd=\"~~[%x]\">0x%x</link> (<link cmd=\"!mex.t %d\">%d</link>)", $tid, $tid, $dtid, $dtid' .frame @#FrameNum - 1

它用于notepad进程的输出示例:

代码语言:javascript
运行
复制
Thread: 0xd14c (0)
Thread: 0x4f88 (1)
Thread: 0xd198 (7)

所有线程的调用堆栈

代码语言:javascript
运行
复制
0:001> !foreachthread k
Child-SP          RetAddr           Call Site
00000062`fabaf8c8 00007ffd`54c7409d win32u!ZwUserGetMessage+0x14
00000062`fabaf8d0 00007ff7`bb4c449f USER32!GetMessageW+0x2d
00000062`fabaf930 00007ff7`bb4dae07 notepad+0x449f
00000062`fabafa30 00007ffd`570f7974 notepad+0x1ae07
00000062`fabafaf0 00007ffd`5841a261 KERNEL32!BaseThreadInitThunk+0x14
00000062`fabafb20 00000000`00000000 ntdll!RtlUserThreadStart+0x21

Changing to thread: 0xda94 (1)
Child-SP          RetAddr           Call Site
00000062`fae7fbc8 00007ffd`5847f01b ntdll!DbgBreakPoint
00000062`fae7fbd0 00007ffd`570f7974 ntdll!DbgUiRemoteBreakin+0x4b
00000062`fae7fc00 00007ffd`5841a261 KERNEL32!BaseThreadInitThunk+0x14
00000062`fae7fc30 00000000`00000000 ntdll!RtlUserThreadStart+0x21

Changing to thread: 0xdb60 (7)
Child-SP          RetAddr           Call Site
00000062`fb17f968 00007ffd`54c7004d win32u!ZwUserMsgWaitForMultipleObjectsEx+0x14
00000062`fb17f970 00007ffc`e4e7d078 USER32!MsgWaitForMultipleObjectsEx+0x9d
00000062`fb17f9b0 00007ffc`e4e7cec2 DUser!GetMessageExA+0x2f8
00000062`fb17fa50 00007ffd`54c77004 DUser!GetMessageExA+0x142
00000062`fb17fab0 00007ffd`584534a4 USER32!Ordinal2582+0x64
00000062`fb17fb50 00007ffd`54101164 ntdll!KiUserCallbackDispatcher+0x24
00000062`fb17fbc8 00007ffd`54c7409d win32u!ZwUserGetMessage+0x14
00000062`fb17fbd0 00007ffd`2e4efa3c USER32!GetMessageW+0x2d
00000062`fb17fc30 00007ffd`1d0b30f8 DUI70!StartMessagePump+0x3c
00000062`fb17fc90 00007ffd`1d0b31ce msctfuimanager!DllCanUnloadNow+0xf3e8
00000062`fb17fd50 00007ffd`570f7974 msctfuimanager!DllCanUnloadNow+0xf4be
00000062`fb17fd80 00007ffd`5841a261 KERNEL32!BaseThreadInitThunk+0x14
00000062`fb17fdb0 00000000`00000000 ntdll!RtlUserThreadStart+0x21

Changing to thread: 0xc490 (8)
Child-SP          RetAddr           Call Site
00000062`fb1ff708 00007ffd`54c7004d win32u!ZwUserMsgWaitForMultipleObjectsEx+0x14
00000062`fb1ff710 00007ffc`e4e7d1ca USER32!MsgWaitForMultipleObjectsEx+0x9d
00000062`fb1ff750 00007ffc`e4e7cde7 DUser!GetMessageExA+0x44a
00000062`fb1ff7f0 00007ffc`e4e7ca53 DUser!GetMessageExA+0x67
00000062`fb1ff840 00007ffd`5505b0ea DUser!GetGadgetFocus+0x33b3
00000062`fb1ff8d0 00007ffd`5505b1bc msvcrt!_callthreadstartex+0x1e
00000062`fb1ff900 00007ffd`570f7974 msvcrt!_threadstartex+0x7c
00000062`fb1ff930 00007ffd`5841a261 KERNEL32!BaseThreadInitThunk+0x14
00000062`fb1ff960 00000000`00000000 ntdll!RtlUserThreadStart+0x21

更新:

我发现有人也有同样的想法(如果链接是死气沉沉的,经常发生):

超薄的读写器锁不记得主人是谁,所以你必须用其他方式找到它们 2011年8月10日 超薄读写器锁是一种非常方便的同步工具,但缺点之一是它不>跟踪当前所有者是谁。 当您的线程被困在等待获得一个苗条的读取器/写入器锁时,需要知道的一件自然的事情是,哪些线程拥有被卡住的线程>等待的资源。 由于没有从等待线程转到拥有线程的功能,所以您只需要以其他方式找到拥有的线程。下面是在共享模式下等待锁的线程>: ntdll!ZwWaitForKeyedEvent+0xc ntdll!RtlAcquireSRWLockShared+0x126 dbquery!CSearchSpace::Validate+0x10b dbquery!CQuery::AddConfigs+0xdc dbquery!CQuery::ResolveProviders+0x89 dbquery!CResults::CreateProviders+0x85 dbquery!CResults::GetProviders+0x61 dbquery!CResults::CreateResults+0x11c 好吧,你是怎么找到锁的线程的? 首先,苗条的读取器/写入器锁只能在进程中使用,因此候选线程是进程中的线程。 其次,锁的使用模式几乎总是类似于 进入锁,做一些出口锁 对于一个函数来说,取一个锁并退出到 持有锁的外部代码。(它可能退出到同一组件中的其他代码,将退出锁的义务转移到该其他代码。) 因此,您希望查找仍然在dbquery.dll中的线程,甚至可能仍然在CSearch­Space中(如果锁是每个对象的锁,而不是全局锁)。 当然,可能是进入锁的代码搞砸了,忘记了释放它,但如果是这样的话,搜索它的数量就不会>找到任何东西,因为罪魁祸首早就消失了。 既然是调试是一项乐观的练习。,我们也可以假设“我们不是这种情况”。如果它找不到锁所有者,那么我们可能不得不重新考虑这个假设。 最后,最后一个诀窍是了解哪些线程要忽略?。现在,您还可以忽略等待锁的线程,因为它们是受害者,而不是原因。(同样,如果我们找不到锁所有者,我们>可以重新考虑它们不是原因的假设;例如,他们可能试图递归地获取锁。) 碰巧, 进程中只有一个线程可以传递所有上述过滤器。 dbquery!CProp::Marshall+0x3b dbquery!CRequest::CRequest+0x24c dbquery!CQuery::Execute+0x668 dbquery!CResults::FillParams+0x1c4 dbquery!CResults::AddProvider+0x4e dbquery!CResults::AddConfigs+0x1c5 dbquery!CResults::CreateResults+0x145 这可能不是问题的根源,但这是一个好的开始。 (实际上,它看上去很有希望,因为问题可能是 (封送处理程序的另一端的进程被卡住了。)

票数 2
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60947806

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档