通常,您可能希望在调试器中跟踪的一类问题(除了崩溃)是某个特定函数以某种方式失败。在大多数Win32函数的情况下,通常会得到某种(希望是有意义的)最后的错误代码。有时,您可能需要知道返回错误的原因或错误的来源(在最后一个错误值通过几个函数向上传播的情况下)。
一种可能的方法是使用条件断点,但是SetLastError路径通常会被命中,因此这在性能方面经常是有问题的,即使在本地计算机上的用户模式调试中也是如此。
在Windows Vista上,NTDLL内部有一个未记录的钩子(它现在负责set last error背后的大部分逻辑),允许您配置一个程序,以便在将特定错误代码设置为最后一个错误时进入调试器。这是Vista的新功能,由于没有文档记录(至少在我能看到的任何地方都没有),它可能不会无限期地存在。

不过,现在可以设置ntdll!g_dwLastErrorToBreakOn设置为非零值(通过调试器中的ed命令),以便在NTDLL看到设置了最后一个错误值时要求它执行断点。显然,这不会直接捕获修改TEB中字段的内容,但是使用setlastererror或RtlSetLastWin32Error的任何内容都将根据该值进行检查(在debuggee的上下文中)。
例如,如果要求NTDLL在错误5(错误访问被拒绝)时中断,然后尝试打开您无权访问的文件或目录,您可能会看到类似的情况:

0:002> ed ntdll!g_dwLastErrorToBreakOn 5
0:002>g

[...] Perform an operation to cause ERROR_ACCESS_DENIED

(
1864.2774): Break instruction exception- code 80000003(first chance)
ntdll
!DbgBreakPoint:00000000`76d6fdf0 cc int 3 0:004>k
Call Site
ntdll
!DbgBreakPoint
ntdll
! ?? ::FNODOBFM::`string'+0x377b kernel32!BaseSetLastNTError+0x16kernel32!CreateFileW+0x325SHELL32!CEnumFiles::InitAndFindFirst+0x7aSHELL32!CEnumFiles::InitAndFindFirstRetry+0x3eSHELL32!CFileSysEnum::_InitFindDataEnum+0x5eSHELL32!CFileSysEnum::Init+0x135SHELL32!CFSFolder::EnumObjects+0xd3SHELL32!_GetEnumerator+0x189SHELL32!CEnumThread::_RunEnum+0x6dSHELL32!CEnumThread::s_EnumThreadProc+0x13SHLWAPI!WrapperThreadProc+0xfckernel32!BaseThreadInitThunk+0xdntdll!RtlUserThreadStart+0x1d

标签: none

添加新评论