WinCE下异常捕获方法_第1页
WinCE下异常捕获方法_第2页
免费预览已结束,剩余1页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 6/6WinCE下异常捕获方法 WinCE系统下应用崩溃原因的分析方法 做为程序员,最怕什么?Bug?大家都清楚,调试期的 Bug 并不可怕,那怕是那些神龙见首不见尾的 INT(随机、没有规律) Bug。做为嵌入式程序员,也是一样的。一般来说嵌入式系统都提供了异常分析的方法,特别是强大的调试工具,这些工具使用在 PC 上编程使用的工具是一样的,例如:Visual Studio 系列。但是一些专用的、或小的嵌入式系统,可能会提供专用的调试工具。虽然从功能上来说,没有微软提供的 VS 功能强大,使用起来也不太方便,但也会提供类似的调试功能。这里我主要讨论的还是微软提供的工具。目前,在车载与 PN

2、D 市场,使用 WinCE 系统的比较多。在 WinCE6.0 系统中,如果应用发生较严重的错误时,一般都会弹出系统标准的、令人十分讨论的应用错误对话框。大概提示:XXX.exe出现严重错误,必须被关闭。如何解决此类问题呢?只要能接上调试串口,或与调试工具连接,如VS2008等,获取出错时的异常信息后,就可以来分析异常可能的原因。但如果设备已经处于量产状态,无法连接输出 LOG 的串口和调试 USB 口时,如何能捕捉到异常信息呢?在无法彻底解决此类问题的情况下,有人就想能不能不让系统显示那个错误对话框。为了能使应用“优美”的退出(网络上的说法),即程序退出时不出现述的错误对话框,有人曾试着去修

3、改 WinCE 提供的内核代码,但这部分应该是属于未开源的部分。所以此方法也行不通的!解决此类问题的根本办法当然是提高编码的质量,然后加强质量保证(即测试),尽量将 Bug 消灭在研发阶段。因为研发阶段,有大量的调试工具可以使用,如下述的第一种方法。在没有调试工具可以依赖时,有没有办法获取到异常信息呢?方法当然是有的,如下述第二种和第三种方法。为什么要说第一种方法呢,因为它提供的信息是最基础的,是后面两种方法都要用到的基础。在这这里,我重点推荐第三种方法。因为它的处理比较独立、在 WinCE 系统中比较有效、且方便集成到已有代码中,实现异常捕获。第一种方法:如果有输出 LOG 串口可说时,串口

4、输出的异常信息,加 MAP 文件一起分析错误的出处,可以到函数一级。所以要求在调试时一定要将对应版本的 MAP 文件一起保留,用于后继异常问题的分析。对于如下的测试代码:void TestCrashFunc(void)int *pNullPoint = NULL;RETAILMSG(1,(L%drn,pNullPoint);*pNullPoint = 0;RETAILMSG(1,(L%d,%drn,pNullPoint,*pNullPoint);void CallCrashFunc(void)TestCrashFunc();void CSmartDeviceMFCDlg:OnTimer( UI

5、NT_PTR nIDEvent) / TODO: 在此添加消息处理程序代码和/或调用默认值if(1 = nIDEvent)KillTimer(1);CallCrashFunc();/ 其它的功能CDialog:OnTimer(nIDEvent);串口输出的内容与下面 WinCE7.0 的基本是相同的。在 WinCE6.0 和 WinCE7.0 下运行时,串口的输出内容基本上是相同的,但在 WinCE7.0 下没有出错的对话框。串口中输出的 Crash 信息如下:Exception Data Abort (0 x4): Thread-Id=0780000a(pth=c08e24e0), Proc

6、-Id=077e000a(pprc=c088da7c) SmartDeviceMFC.exe, VM-active=077e000a(pprc=c088da7c) SmartDeviceMFC.exePC=00011738(SmartDeviceMFC.exe+0 x00001738) RA=4002ac4c(coredll.dll+0 x0001ac4c) SP=0004f6a8, BVA=00000000Exception Raised Exception (0 x116): Thread-Id=0780000a(pth=c08e24e0), Proc-Id=00400002(pprc=8

7、360b5e0) NK.EXE, VM-active=077e000a(pprc=c088da7c) SmartDeviceMFC.exePC=eff6ed60(k.coredll.dll+0 x0001ed60) RA=8052a62c(kernel.dll+0 x0000e62c) SP=d9bbf3b4, BVA=ffffffff从对应的 MAP 文件中查到是 TestCrashFunc 函数出错(PC 指针 0 x00001738 + MAP 文件中的 Preferred load address 偏移量),此例中出错时位置为:0 x00001738 + 00010000 = 0001

8、1738:SmartDeviceMFCTimestamp is 539fa9e3 (Tue Jun 17 10:37:23 2014)Preferred load address is 000100000001:000006a8 ?InitInstanceCSmartDeviceMFCAppUAAHXZ 000116a8 f SmartDeviceMFC.obj0001:00000708 ?OnCbnDropdownCombo1CSmartDeviceMFCDlgQAAXXZ 00011708 f SmartDeviceMFCDlg.obj0001:00000714 ?TestCrashFun

9、cYAXXZ 00011714 f SmartDeviceMFCDlg.obj0001:0000075c ?BeginModalStateCWndUAAXXZ 0001175c f i SmartDeviceMFCDlg.obj0001:00000768 ?EndModalStateCWndUAAXXZ 00011768 f i SmartDeviceMFCDlg.obj0001:00000774 ?_GCComboBoxUAAPAXIZ 00011774 f i SmartDeviceMFCDlg.obj由此可见 WinCE7.0 系统对这种对空指针赋值等异常是做了一些处理的,至少不再弹出那

10、个令人十分讨厌的对话框,也不影响后继其它功能的执行。在 WinCE6.0 下如果出现类似的对话框,则应用就会退出。第二种方法:使用 _try 和 _except。在开源的多媒体播放器 TCPMP 中,就有如下的用法。先定义两个宏,然后将重要的处理线程代码包含在定义的这两个宏中,以捕捉两个宏之间代码出现的异常。这样做有一个缺点:但代码量很大时,就需要增加很多对这两个宏的调用。#define SAFE_BEGIN _try #define SAFE_END ; _except (SafeException(_exception_info() 可以看到 WinCE 下的使用方法,与 PC 上 SEH

11、(Structured Exception Handling)是一样的。如下所示:_try/ guarded code_except ( expression )/ exception handler code以下是 TCPMP 中一个关键线程的异常处理代码(TCPMP 线程的代码,没有完整的给出,有兴趣的童鞋请自己去看 TCPMP 的源代码),其中两个 定义的异常处理宏,将线程的所有代码包含在内。 static int ProcessThread(player_base* p)int Result = ERR_NONE;#ifdef MULTITHREADSAFE_BEGINwhile (p

12、-Wnd)if (p-RunProcess)processstate State;State.Fill = p-Fill;p-Timer-Get(p-Timer,TIMER_TIME,/DEBUG_MSG1(DEBUG_PLAYER,T(Process Time:%d),State.Time);Result = p-Format-Process(p-Format,if (Result = ERR_SYNCED)else if (p-Fill此种实现方法,最最关键是 SafeException() 函数中分析与记录异常信息的办法。但由于在 TCPMP 中,获取异常的信息与 TCPMP 的软件框架

13、结合在一起。需要移植此部分代码到其它工程时,需要将有用的代码分离出来,其实这个也比较简单。只要将与 EXCEPTION_POINTERS 相关的代码拿出来即可。int SafeException(void* p)EXCEPTION_POINTERS* Data = (EXCEPTION_POINTERS*)p;/ 删除了无关的代码 - 此部分代码是 TCPMP 中的代码,所以未做排版。const uint8_t* ContextRecord = (const uint8_t*) Data-ContextRecord;EXCEPTION_RECORD* Record = Data-Excepti

14、onRecord;switch (Record-ExceptionCode)case STATUS_ACCESS_VIOLATION: Name = T(Access violation); break;case STATUS_BREAKPOINT: Name = T(Breakpoint); break;case STATUS_DATATYPE_MISALIGNMENT: Name = T(Datatype misalignment); break;case STATUS_ILLEGAL_INSTRUCTION: Name = T(Illegal instruction); break;ca

15、se STATUS_INTEGER_DIVIDE_BY_ZERO: Name = T(Int divide by zero); break;case STATUS_INTEGER_OVERFLOW: Name = T(Int overflow); break;case STATUS_PRIVILEGED_INSTRUCTION: Name = T(Priv instruction); break;case STATUS_STACK_OVERFLOW: Name = T(Stack overflow); break;default: Name = T(Unknown); break;if (Re

16、cord-ExceptionCode = STATUS_ACCESS_VIOLATION)if (Record-ExceptionInformation0)Name = T(Write to);elseName = T(Read from);/ 关键是处理 EXCEPTION_POINTERS 结构体相关的成员/ 其它一些相关的,如可执行程序文件名等,根据需要来获取第三种方法:使用函数 AddVectoredExceptionHandler()。在 WinCE 下使用此函数,需要包含头文件: TlHelp32.h 和库文件: toolhelp.lib。由于此函数属于 WinCE 示公开的 AP

17、I,所以帮忙只要以 PC 上为准。使用此函数,是向 WinCE 系统注册一个矢量异 常处理程序,但有异常发生时会调用此处理程序。 函数的原型如下(MSDN),各参数具体的含义,请参考 MSDN。这里就不做翻译了。PVOID WINAPI AddVectoredExceptionHandler(_in ULONG FirstHandler, _in PVECTORED_EXCEPTION_HANDLER VectoredHandler);以下代码,演示了如何使用 AddVectoredExceptionHandler() 函数:(1) AddVectoredExceptionHandler(1,

18、MyVectoredExceptionHandler);(2) 定义异常处理程序LONG WINAPI MyVectoredExceptionHandler(struct _EXCEPTION_POINTERS *pExceptionInfo)typedef ULONG (WINAPI *lpGetThreadCallStack)(HANDLE,ULONG,LPVOID,DWORD,DWORD);/* 在使用时,必须包含一些头文件。这些头文件,需要从 WinCE 的安装目录中获得。OS Versions: Windows CE 5.0 and later.Header: Pkfuncs.h.*

19、/typedef struct _CallSnapshotExDWORD dwReturnAddr;DWORD dwFramePtr;DWORD dwCurProc;DWORD dwParams4;CallSnapshotEx;/ 打印 Dump 信息/ 打印 SP 堆栈ULONG *punSp = (ULONG *)pExceptionInfo-ContextRecord-Sp;/ 获取线程堆栈调用HMODULE hCore = LoadLibrary(Lcoredll.dll);if(NULL != hCore)lpGetThreadCallStack pGetThreadCallStac

20、k = (lpGetThreadCallStack)GetProcAddress(hCore,LGetThreadCallStack);if(NULL != pGetThreadCallStack)/ 获取进程内 dll 信息MODULEENTRY32 CurrentModule;HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,GetCurrentProcessId();if(HANDLE)-1 != hSnapShot)/ 调用 Module32First 和 Module32Next 完成 Module 枚举是否还需要其它信息来分析程序出现异常的原因,可以参考 MSDN 中对结构 _EXCEPTION_POINTERS 中各成员的说明。然后将有用的信息,写到

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论