我正在阅读这篇关于Windows上的SEH的文章 。 这里是myseh.cpp的源代码
我debugging了myseh.cpp。 我在printf("Hello from an exception handler\n");
处设置了2个断点printf("Hello from an exception handler\n");
在行:24和DWORD handler = (DWORD)_except_handler;
在线:36分别。
然后,我跑了,它在线:36。 我看到堆栈跟踪如下。
随着去,由于mov [eax], 1
发生了AccessViolationException mov [eax], 1
然后它在线:24打破。 我看到堆栈跟踪如下。
同样的线程,但main
的框架已经消失了! 而不是_except_handle
。 ESP从0018f6c8
跳到0018f6c8
,经过Exception处理, 0018f6c8
和0018ef34
之间差距很大。
我知道_except_handle
必须在用户模式而不是内核模式下运行。 在返回_except_handle
之后,线程转到ring0,然后windows内核修改CONTEXT EAX
到&scratch
&然后返回到ring3。 因此,线程不断运行。
我很好奇窗口处理exception的机制:为什么调用main
的帧不见了?
为什么ESP从0018f6c8
跳到0018ef34
?(我的意思是一个很大的音高),那些ESP地址属于同一个线程的堆栈? 内核在ring3上玩ESP的一些技巧? 如果是这样,为什么select0018ef34
的地址作为处理程序callback的框架? 非常感谢!
您正在使用默认的调试器设置,不足以查看所有细节。 他们被选中来帮助您专注于您自己的代码,并尽快启动调试会话。
[External Code]块会告诉你堆栈框架的某些部分不属于你写的代码。 他们不,他们属于操作系统。 使用工具>选项>调试>常规,并取消“启用只是我的代码”选项。
[下面的框架可能不正确…]警告告诉您,调试器没有准确的PDB来正确地走栈。 使用工具>选项>调试>符号,然后勾选“Microsoft Symbol servers”选项并选择一个缓存位置。 调试器现在将通过操作系统DLL下载您需要调试的PDB。 可能需要一段时间,它只做一次。
你可以推断出大的ESP变化,CONTEXT结构相当大,占用堆栈空间。
这些变化之后,你现在应该看到类似的东西:
ConsoleApplication1942.exe!_except_handler(_EXCEPTION_RECORD * ExceptionRecord, void * EstablisherFrame, _CONTEXT * ContextRecord, void * DispatcherContext) Line 22 C++ ntdll.dll!ExecuteHandler2@20() Unknown ntdll.dll!ExecuteHandler@20() Unknown ntdll.dll!_KiUserExceptionDispatcher@8() Unknown ConsoleApplication1942.exe!main() Line 46 C++ ConsoleApplication1942.exe!invoke_main() Line 64 C++ ConsoleApplication1942.exe!__scrt_common_main_seh() Line 255 C++ ConsoleApplication1942.exe!__scrt_common_main() Line 300 C++ ConsoleApplication1942.exe!mainCRTStartup() Line 17 C++ kernel32.dll!@BaseThreadInitThunk@12() Unknown ntdll.dll!__RtlUserThreadStart() Unknown ntdll.dll!__RtlUserThreadStart@8() Unknown
记录在Win10版本1607和VS2015更新2.这不是正确的方式来编写SEH处理程序,在这篇文章中找到一个更好的例子。