本文正在参与 CSDN 博文大赛,如果你觉得本文对您有有,请投一票:投票WWW网址(投票按键在文章最后)
做为程序员,最怕什么?Bug?大家都清楚,调试期的 Bug 并不可怕,那怕是那些神龙见首不见尾的 INT(随机、没有规律) Bug。
做为嵌入式程序员,也是一样的。一般来说嵌入式系统都提供了异常分析的方法,特别是强大的调试工具,这些工具使用在 PC 上编程使用的工具是一样的,例如:Visual Studio 系列。但是一些专用的、或小的嵌入式系统,可能会提供专用的调试工具。虽然从功能上来说,没有微软提供的 VS 功能强大,使用起来也不太方便,但也会提供类似的调试功能。这里我主要讨论的还是微软提供的工具。对于如下的测试代码:
void TestCrashFunc(void)
{
int *pNullPoint = NULL;
RETAILMSG(1,(L"-----------------------------%d\r\n",pNullPoint));
*pNullPoint = 0;
RETAILMSG(1,(L"-----------------------------%d,%d\r\n",pNullPoint,*pNullPoint));
}
void CallCrashFunc(void)
{
TestCrashFunc();
}
void CSmartDeviceMFCDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if(1 == nIDEvent)
{
KillTimer(1);
CallCrashFunc();
// 其它的功能
}
CDialog::OnTimer(nIDEvent);
}
Exception 'Data Abort' (0x4): Thread-Id=0780000a(pth=c08e24e0), Proc-Id=077e000a(pprc=c088da7c) 'SmartDeviceMFC.exe', VM-active=077e000a(pprc=c088da7c) 'SmartDeviceMFC.exe'
PC=00011738(SmartDeviceMFC.exe+0x00001738) RA=4002ac4c(coredll.dll+0x0001ac4c) SP=0004f6a8, BVA=00000000
Exception 'Raised Exception' (0x116): Thread-Id=0780000a(pth=c08e24e0), Proc-Id=00400002(pprc=8360b5e0) 'NK.EXE', VM-active=077e000a(pprc=c088da7c) 'SmartDeviceMFC.exe'
PC=eff6ed60(k.coredll.dll+0x0001ed60) RA=8052a62c(kernel.dll+0x0000e62c) SP=d9bbf3b4, BVA=ffffffff
SmartDeviceMFC
Timestamp is 539fa9e3 (Tue Jun 17 10:37:23 2014)
Preferred load address is 00010000
......
0001:000006a8 ?InitInstance@CSmartDeviceMFCApp@@UAAHXZ 000116a8 f SmartDeviceMFC.obj
0001:00000708 ?OnCbnDropdownCombo1@CSmartDeviceMFCDlg@@QAAXXZ 00011708 f SmartDeviceMFCDlg.obj
0001:00000714 ?TestCrashFunc@@YAXXZ 00011714 f SmartDeviceMFCDlg.obj
0001:0000075c ?BeginModalState@CWnd@@UAAXXZ 0001175c f i SmartDeviceMFCDlg.obj
0001:00000768 ?EndModalState@CWnd@@UAAXXZ 00011768 f i SmartDeviceMFCDlg.obj
0001:00000774 ??_GCComboBox@@UAAPAXI@Z 00011774 f i SmartDeviceMFCDlg.obj
#define SAFE_BEGIN __try {
#define SAFE_END ;} __except (SafeException(_exception_info())) {}
__try
{
// guarded code
}
__except ( expression )
{
// exception handler code
}
static int ProcessThread(player_base* p)
{
int Result = ERR_NONE;
#ifdef MULTITHREAD
SAFE_BEGIN
while (p->Wnd)
{
......
if (p->RunProcess)
{
processstate State;
State.Fill = p->Fill;
p->Timer->Get(p->Timer,TIMER_TIME,&State.Time,sizeof(tick_t));
//DEBUG_MSG1(DEBUG_PLAYER,T("Process Time:%d"),State.Time);
Result = p->Format->Process(p->Format,&State);
if (Result == ERR_SYNCED)
{
......
}
else if (p->Fill && (Result == ERR_END_OF_FILE || Result == ERR_BUFFER_FULL
|| (Result == ERR_NEED_MORE_DATA && (p->NoMoreInput || State.BufferUsedAfter >= p->CurrBufferSize2-2))))
{
......
}
......
}
......
}
SAFE_END
return 0;
}
int SafeException(void* p)
{
EXCEPTION_POINTERS* Data = (EXCEPTION_POINTERS*)p;
// 删除了无关的代码 - 此部分代码是 TCPMP 中的代码,所以未做排版。
{
{
const uint8_t* ContextRecord = (const uint8_t*) Data->ContextRecord;
EXCEPTION_RECORD* Record = Data->ExceptionRecord;
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;
case 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 (Record->ExceptionCode == STATUS_ACCESS_VIOLATION)
{
if (Record->ExceptionInformation[0])
Name = T("Write to");
else
Name = T("Read from");
}
//...... 关键是处理 EXCEPTION_POINTERS 结构体相关的成员
// 其它一些相关的,如可执行程序文件名等,根据需要来获取
}
}
PVOID WINAPI AddVectoredExceptionHandler(__in ULONG FirstHandler, __in PVECTORED_EXCEPTION_HANDLER VectoredHandler);
以下代码,演示了如何使用 AddVectoredExceptionHandler() 函数:
(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.
*/
typedef struct _CallSnapshotEx
{
DWORD dwReturnAddr;
DWORD dwFramePtr;
DWORD dwCurProc;
DWORD dwParams[4];
}CallSnapshotEx;
// 打印 Dump 信息
......
// 打印 SP 堆栈
......
ULONG *punSp = (ULONG *)pExceptionInfo->ContextRecord->Sp;
// 获取线程堆栈调用
HMODULE hCore = LoadLibrary(L"coredll.dll");
if(NULL != hCore)
{
lpGetThreadCallStack pGetThreadCallStack = (lpGetThreadCallStack)GetProcAddress(hCore,L"GetThreadCallStack");
if(NULL != pGetThreadCallStack)
{
}
}
// 获取进程内 dll 信息
MODULEENTRY32 CurrentModule;
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,GetCurrentProcessId());
if((HANDLE)-1 != hSnapShot)
{
// 调用 Module32First 和 Module32Next 完成 Module 枚举
}
}