在CE系统上,当程序发生异常特别是不可重现的异常时,通过事后调试协助快速定位问题
在windows系统中,当应用程序出现严重错误无法运行时,系统会启动JIT调试器,JIT调试器可以做两类事情:1)直接附加到出错进程上通过调试来分析、定位问题。2)收集、记录错误发生时的现场数据提供事后分析。在WinCE上,希望利用第二种方式:也就是使用WER(Windwos Error Reporting)功能生成转储文件(dump文件)来进行事后分析。
转储文件是对特定进程、线程在内存中运行状态的快照,只有在异常发生时产生的快照才对我们查找问题有意义,因此首先需要捕获异常,捕获异常为我们生成转储文件提供了时机以及必要的上下文环境,例如只有在异常被捕获的状态下,Native的GetExceptionInformation和CLR的GetExceptionPointers才能获取到PEXCEPTION_POINTERS指针。我把捕获异常的方式分成3种:
编程语言都提供了异常捕获的语法关键字,例如对于C++和VB .NET:
C++ SEH |
vb .net |
__try __except |
try catch |
在try 块中发生异常以后,程序跳转到异常处理块中,在异常处理块中我们可以进行异常转储。
使用VB.NET的try catch得到异常转储的时机(仅仅是个时机)
Windows Native |
Windows CLR |
SetUnhandledExceptionFilter |
Application..::.ThreadException |
_AppDomain..::.UnhandledException |
l SetUnhandledExceptionFilter
为一个应用的所有进程和线程设置一个顶级异常处理函数
l Application..::.ThreadException
UI线程产生的异常处理事件
l _AppDomain..::.UnhandledException
非UI线程产生的异常处理事件
WinCE不提供SetUnhandledExceptionFilter
cf .net 不提供Application..::.ThreadException和_AppDomain..::.UnhandledException
如果所有其它异常捕获机制都没有生效,系统根据注册表的设置尝试使用JIT调试器来分析问题。windows默认的jit调试器是Dr.Watson,它将为出错程序生成一个转储文件。
WinCE从5.0开始加入WER模块(windowserror reporting),也是为出错的程序生成转储文件。
这种方式下系统自动生成dump。
EVC程序可以生成dump,VB.NET程序无法生成dump。
因为3.1.2和3.1.3都不可行,因此采用3.1.1的方式继续尝试。在捕获异常以后,要想保存转储文件,需要先获取异常结构指针。系统提供了以下函数
Windows Native |
Windows CLR |
GetExceptionInformation |
GetExceptionPointers |
WinCE提供了GetExceptionInformation,但GetExceptionInformation并不是函数,而是一个宏,并且只允许在异常处理过滤表达式中调用,这意味着VB.NET代码无法通过P/Invoke调用GetExceptionInformation。
cf .net不提供GetExceptionPointers
结论是VB.NET无法获取异常结构体指针
在Windows中获取到正确的异常结构指针以后,就可以调用MiniDumpWriteDump保存转储文件,但是在CE5.0并没有MiniDumpWriteDump,它使用了CaptureDumpFileOnDevice和ReportFault。
Windows Native |
WinCE 5.0 |
MiniDumpWriteDump |
CaptureDumpFileOnDevice |
ReportFault |
VB.NET适用性:
1. 虽然wince提供了ReportFault,但是因为3.2的结论,导致VB.NET无法调用ReportFault(异常结构指针参数无法获取)。
2. CaptureDumpFileOnDevice通过试验可以产生dump,但是这个函数的参数是进程号和线程号,也就是说它无法保存异常发生时的状态。尝试了在VB.NET程序中P/InvokeCaptureDumpFileOnDevice,分析产生的dump文件发现堆栈信息缺少了托管代码的部分:
1)EVC程序既可以使用JIT也可以使用编程方式实现异常转储
2)VB.NET程序无法实现异常转储