Windows 上的 SEH,调用堆栈回溯消失了
SEH on Windows, call stack traceback is gone
我正在 Windows 上阅读这篇关于 SEH 的 article。
这是 myseh.cpp
的源代码
我调试了myseh.cpp。我分别在 line:24 的 printf("Hello from an exception handler\n");
和第 36 行的 DWORD handler = (DWORD)_except_handler;
处设置了 2 个断点。
然后我 运行 它在 line:36 处坏了。我看到堆栈跟踪如下。
随着进展,AccessViolationException 由于 mov [eax], 1
而发生
然后它在 line:24 处中断。我看到堆栈跟踪如下。
同一个线程,但是 main
的 frame 不见了!而不是 _except_handle
。 ESP 从 0018f6c8
跃升至 0018ef34
;0018f6c8
和 0018ef34
差距很大
异常处理后。
我知道 _except_handle
在用户模式下必须是 运行 而不是内核模式。
_except_handle
返回后线程转到ring0然后windows内核修改CONTEXTEAX
为&scratch
&然后返回ring3。因此线程 运行 不断。
很好奇windows处理异常的机制:
为什么调用 main
的 frame 不见了?
为什么 ESP 从 0018f6c8
跳到 0018ef34
?(我的意思是一个大间距),这些 ESP 地址是否属于同一个线程的堆栈??? ring3 内核对 ESP 耍了什么花招???如果是这样,为什么它选择 0018ef34
的地址作为处理程序回调的框架?非常感谢!
您使用的是默认调试器设置,不足以查看所有详细信息。选择它们是为了帮助您专注于自己的代码并尽快启动调试会话。
[External Code] 块告诉您堆栈帧的某些部分不属于您编写的代码。他们不,他们属于操作系统。使用工具 > 选项 > 调试 > 常规并取消勾选 "Enable Just My Code" 选项。
[下面的帧可能不正确...] 警告告诉您调试器没有准确的 PDB 来正确遍历堆栈。使用工具 > 选项 > 调试 > 符号并勾选 "Microsoft Symbol Servers" 选项并选择缓存位置。调试器现在将下载您需要通过操作系统 DLL 进行调试的 PDB。可能需要一段时间,它只完成一次。
你可以推断出 ESP 的大变化,CONTEXT 结构相当大,在堆栈上占用 space。
进行这些更改后,您现在应该会看到类似以下内容:
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 处理程序的正确方法,在 this post 中找到更好的示例。
我正在 Windows 上阅读这篇关于 SEH 的 article。 这是 myseh.cpp
的源代码我调试了myseh.cpp。我分别在 line:24 的 printf("Hello from an exception handler\n");
和第 36 行的 DWORD handler = (DWORD)_except_handler;
处设置了 2 个断点。
然后我 运行 它在 line:36 处坏了。我看到堆栈跟踪如下。
mov [eax], 1
而发生
然后它在 line:24 处中断。我看到堆栈跟踪如下。
同一个线程,但是 main
的 frame 不见了!而不是 _except_handle
。 ESP 从 0018f6c8
跃升至 0018ef34
;0018f6c8
和 0018ef34
差距很大
异常处理后。
我知道 _except_handle
在用户模式下必须是 运行 而不是内核模式。
_except_handle
返回后线程转到ring0然后windows内核修改CONTEXTEAX
为&scratch
&然后返回ring3。因此线程 运行 不断。
很好奇windows处理异常的机制:
为什么调用 main
的 frame 不见了?
为什么 ESP 从 0018f6c8
跳到 0018ef34
?(我的意思是一个大间距),这些 ESP 地址是否属于同一个线程的堆栈??? ring3 内核对 ESP 耍了什么花招???如果是这样,为什么它选择 0018ef34
的地址作为处理程序回调的框架?非常感谢!
您使用的是默认调试器设置,不足以查看所有详细信息。选择它们是为了帮助您专注于自己的代码并尽快启动调试会话。
[External Code] 块告诉您堆栈帧的某些部分不属于您编写的代码。他们不,他们属于操作系统。使用工具 > 选项 > 调试 > 常规并取消勾选 "Enable Just My Code" 选项。
[下面的帧可能不正确...] 警告告诉您调试器没有准确的 PDB 来正确遍历堆栈。使用工具 > 选项 > 调试 > 符号并勾选 "Microsoft Symbol Servers" 选项并选择缓存位置。调试器现在将下载您需要通过操作系统 DLL 进行调试的 PDB。可能需要一段时间,它只完成一次。
你可以推断出 ESP 的大变化,CONTEXT 结构相当大,在堆栈上占用 space。
进行这些更改后,您现在应该会看到类似以下内容:
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 处理程序的正确方法,在 this post 中找到更好的示例。