www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當前位置:首頁 > 芯聞號 > 充電吧
[導讀]做為程序員,最怕什么?Bug?大家都清楚,調(diào)試期的 Bug 并不可怕,那怕是那些神龍見首不見尾的 INT(隨機、沒有規(guī)律) Bug。做為嵌入式程序員,也是一樣的。一般來說嵌入式系統(tǒng)都提供了異常分析的方

做為程序員,最怕什么?Bug?大家都清楚,調(diào)試期的 Bug 并不可怕,那怕是那些神龍見首不見尾的 INT(隨機、沒有規(guī)律) Bug。

做為嵌入式程序員,也是一樣的。一般來說嵌入式系統(tǒng)都提供了異常分析的方法,特別是強大的調(diào)試工具,這些工具使用在 PC 上編程使用的工具是一樣的,例如:Visual Studio 系列。但是一些專用的、或小的嵌入式系統(tǒng),可能會提供專用的調(diào)試工具。雖然從功能上來說,沒有微軟提供的 VS 功能強大,使用起來也不太方便,但也會提供類似的調(diào)試功能。這里我主要討論的還是微軟提供的工具。
目前,在車載與 PND 市場,使用 WinCE 系統(tǒng)的比較多。在 WinCE6.0 系統(tǒng)中,如果應用發(fā)生較嚴重的錯誤時,一般都會彈出系統(tǒng)標準的、令人十分討論的應用錯誤對話框。大概提示:XXX.exe出現(xiàn)嚴重錯誤,必須被關閉。
如何解決此類問題呢?
只要能接上調(diào)試串口,或與調(diào)試工具連接,如VS2008等,獲取出錯時的異常信息后,就可以來分析異??赡艿脑颉?br />但如果設備已經(jīng)處于量產(chǎn)狀態(tài),無法連接輸出 LOG 的串口和調(diào)試 USB 口時,如何能捕捉到異常信息呢?
在無法徹底解決此類問題的情況下,有人就想能不能不讓系統(tǒng)顯示那個錯誤對話框。為了能使應用“優(yōu)美”的退出(網(wǎng)絡上的說法),即程序退出時不出現(xiàn)述的錯誤對話框,有人曾試著去修改 WinCE 提供的內(nèi)核代碼,但這部分應該是屬于未開源的部分。所以此方法也行不通的!


解決此類問題的根本辦法當然是提高編碼的質(zhì)量,然后加強質(zhì)量保證(即測試),盡量將 Bug 消滅在研發(fā)階段。因為研發(fā)階段,有大量的調(diào)試工具可以使用,如下述的第一種方法。
在沒有調(diào)試工具可以依賴時,有沒有辦法獲取到異常信息呢?方法當然是有的,如下述第二種和第三種方法。為什么要說第一種方法呢,因為它提供的信息是最基礎的,是后面兩種方法都要用到的基礎。在這里,我重點推薦的是第三種方法。因為它的處理比較獨立、在 WinCE 系統(tǒng)中比較有效、且方便集成到已有代碼中,實現(xiàn)異常捕獲。


第一種方法:如果有輸出 LOG 串口可說時,串口輸出的異常信息,加 MAP 文件一起分析錯誤的出處,可以到函數(shù)一級。所以要求在調(diào)試時一定要將對應版本的 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(UINT_PTR?nIDEvent)
{
??//?TODO:?在此添加消息處理程序代碼和/或調(diào)用默認值
??if(1?==?nIDEvent)
??{
????KillTimer(1);
????CallCrashFunc();
????
????//?其它的功能
??}
??CDialog::OnTimer(nIDEvent);
}


在 WinCE6.0 和 WinCE7.0 下運行時,串口的輸出內(nèi)容基本上是相同的,但在 WinCE7.0 下沒有出錯的對話框。
串口中輸出的 Crash 信息如下:



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


從對應的 MAP 文件中查到是 TestCrashFunc 函數(shù)出錯(PC 指針 0x00001738 + MAP 文件中的 Preferred load address 偏移量),此例中出錯時位置為:0x00001738 + 00010000 = 00011738:



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


由此可見 WinCE7.0 系統(tǒng)對這種對空指針賦值等異常是做了一些處理的,至少不再彈出那個令人十分討厭的對話框,也不影響后繼其它功能的執(zhí)行。在 WinCE6.0 下如果出現(xiàn)類似的對話框,則應用就會退出。


第二種方法:使用 __try 和 __except。在開源的多媒體播放器 TCPMP 中,就有如下的用法。
先定義兩個宏,然后將重要的處理線程代碼包含在定義的這兩個宏中,以捕捉兩個宏之間代碼出現(xiàn)的異常。這樣做有一個缺點:但代碼量很大時,就需要增加很多對這兩個宏的調(diào)用。



#define?SAFE_BEGIN?__try?{
#define?SAFE_END?;}?__except?(SafeException(_exception_info()))?{}


可以看到 WinCE 下的使用方法,與 PC 上 SEH(Structured Exception Handling)是一樣的。如下所示:



__try?
{
???//?guarded?code
}
__except?(?expression?)
{
???//?exception?handler?code
}


以下是 TCPMP 中一個關鍵線程的異常處理代碼(TCPMP 線程的代碼,沒有完整的給出,有興趣的童鞋請自己去看 TCPMP 的源代碼),其中兩個定義的異常處理宏,將線程的所有代碼包含在內(nèi)。



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;
}


此種實現(xiàn)方法,最最關鍵是 SafeException() 函數(shù)中分析與記錄異常信息的辦法。
但由于在 TCPMP 中,獲取異常的信息與 TCPMP 的軟件框架結合在一起。需要移植此部分代碼到其它工程時,需要將有用的代碼分離出來,其實這個也比較簡單。
只要將與 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->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?結構體相關的成員
??????//?其它一些相關的,如可執(zhí)行程序文件名等,根據(jù)需要來獲取
??}
}


第三種方法:使用函數(shù) AddVectoredExceptionHandler()。
在 WinCE 下使用此函數(shù),需要包含頭文件: TlHelp32.h 和庫文件: toolhelp.lib。由于此函數(shù)屬于 WinCE 示公開的 API,所以幫忙只要以 PC 上為準。
使用此函數(shù),是向 WinCE 系統(tǒng)注冊一個矢量異常處理程序,但有異常發(fā)生時會調(diào)用此處理程序。
函數(shù)的原型如下(MSDN),各參數(shù)具體的含義,請參考 MSDN。這里就不做翻譯了。



PVOID?WINAPI?AddVectoredExceptionHandler(__in?ULONG?FirstHandler,?__in?PVECTORED_EXCEPTION_HANDLER?VectoredHandler);

以下代碼,演示了如何使用 AddVectoredExceptionHandler() 函數(shù):
(1) AddVectoredExceptionHandler(1,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.
??*/
??typedef?struct?_CallSnapshotEx
??{
????DWORD?dwReturnAddr;
????DWORD?dwFramePtr;
????DWORD?dwCurProc;
????DWORD?dwParams[4];
??}CallSnapshotEx;
??//?打印?Dump?信息?
??......
??//?打印?SP?堆棧
??......
??ULONG?*punSp?=?(ULONG?*)pExceptionInfo->ContextRecord->Sp;
??//?獲取線程堆棧調(diào)用
??HMODULE?hCore?=?LoadLibrary(L"coredll.dll");
??if(NULL?!=?hCore)
??{
????lpGetThreadCallStack?pGetThreadCallStack?=?(lpGetThreadCallStack)GetProcAddress(hCore,L"GetThreadCallStack");
????if(NULL?!=?pGetThreadCallStack)
????{
????}
??}
??//?獲取進程內(nèi)?dll?信息
??MODULEENTRY32?CurrentModule;
??HANDLE?hSnapShot?=?CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,GetCurrentProcessId());
??if((HANDLE)-1?!=?hSnapShot)
??{
????//?調(diào)用??Module32First??和?Module32Next?完成?Module?枚舉
??}
}


是否還需要其它信息來分析程序出現(xiàn)異常的原因,可以參考 MSDN 中對結構 _EXCEPTION_POINTERS 中各成員的說明。然后將有用的信息,寫到 SD 卡等可永久存貯的設備中。這樣就不必為擔心找不到用于分析異常的資源,且此記錄的文件中的信息遠大于串口輸出的異常信息。同時,也可以根據(jù)需要輸入一些應用(進程)的相關信息。
可以將此異常捕獲功能的代碼,封裝成一個 LIB 來供使用程序調(diào)用。


相對于 PC Windows 下感知程序崩潰(其實就是運行時的嚴重錯誤)的方法,WinCE 還是比較少的,且真正被用的更是少之又少。
PC 下除了以上第二和第三種方法外,還有以下 3 個核心的函數(shù)可以感知程序的異常,分別是:
SetUnhandledExceptionFilter(HandleException),功能是確定出現(xiàn)沒有控制的異常發(fā)生時調(diào)用的函數(shù)為 HandleException;函數(shù)在 WinCE 上是不可用的,無100%替代函數(shù)。
_set_invalid_parameter_handler(HandleInvalidParameter),功能是確定出現(xiàn)無效參數(shù)調(diào)用發(fā)生時調(diào)用的函數(shù)為 HandleInvalidParameter;
_set_purecall_handler(HandlePureVirtualCall),功能是確定純虛函數(shù)調(diào)用發(fā)生時調(diào)用的函數(shù)為 HandlePureVirtualCall。


充分利用 Bug 的解決方法,是一個程序員成長的必由之路。因為程序員的工作不只是編碼,還包括前期設計與后期的產(chǎn)品問題的修復等。
好的應用,就應該像 TCPMP 一樣,在異常來臨時能正確的提示用戶,這樣的程序的崩潰也朝“優(yōu)美”邁進了一步。同時,也提供的開發(fā)人員分析異常的信息:記錄在文件中。


本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務連續(xù)性,提升韌性,成...

關鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權最終是由生態(tài)的繁榮決定的。

關鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務引領增長 以科技創(chuàng)新為引領,提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術學會聯(lián)合牽頭組建的NVI技術創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術創(chuàng)新聯(lián)...

關鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關鍵字: BSP 信息技術
關閉
關閉