嵌入式軟件培訓(xùn)(cortex-m3 內(nèi)存越界)_第1頁
嵌入式軟件培訓(xùn)(cortex-m3 內(nèi)存越界)_第2頁
嵌入式軟件培訓(xùn)(cortex-m3 內(nèi)存越界)_第3頁
嵌入式軟件培訓(xùn)(cortex-m3 內(nèi)存越界)_第4頁
嵌入式軟件培訓(xùn)(cortex-m3 內(nèi)存越界)_第5頁
已閱讀5頁,還剩27頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

嵌入式軟件調(diào)試、測試、問題定位

經(jīng)驗分享AEBELL陸燦2014-11-18內(nèi)容:嵌入式軟件開發(fā)概述常見問題及分析實例分析總結(jié)

嵌入式軟件開發(fā),是指針對嵌入式硬件平臺帶嵌入式操作系統(tǒng)的軟件開發(fā),硬件平臺包括:單片機、ARM、PowerPC、DSP、MIPS等;主流嵌入式操作系統(tǒng)有:嵌入式linux、VxWorks、wince等。廣義的嵌入式軟件開發(fā)還包括單片機軟件開發(fā)。

嵌入式軟件開發(fā)根據(jù)不同的硬件平臺、不同的操作系統(tǒng)、不同的開發(fā)環(huán)節(jié)有著多個的方向,如不帶操作系統(tǒng)的前后臺程序開發(fā);帶操作系統(tǒng)的可以有bootloader開發(fā)、內(nèi)核開發(fā)、驅(qū)動開發(fā)、應(yīng)用開發(fā)等。

相對于強大的PC,嵌入式硬件平臺資源非常有限,低端的CPU其片內(nèi)ram一般為K級至100K級,ROM為10K級至1M級,如單片機、ARM7、Cortex-M3。高端的CPU使用片外ram、rom,能達(dá)到G級,如A8、A9處理器。

由于嵌入式硬件資源的限制,嵌入式軟件不能直接在板子上開發(fā),而是以通用平臺(PC)作為宿主機,板子作為目標(biāo)機,在PC上進行代碼編輯,用交叉編譯器生成目標(biāo)碼,將目標(biāo)碼下載到板子中去才能運行。常見問題及分析錯用運算符運算符優(yōu)先級歧義大小端倒置內(nèi)存越界內(nèi)存泄露任務(wù)優(yōu)先級問題常見問題:

錯用運算符 1)條件判定“==”和賦值“=”: if(i=j) { … } 2)邏輯與&&、或||和位運算與&、或|。 if(a&b) { … }2.運算優(yōu)先級歧義

如果代碼行中運算符比較多,如:if(a|b&&a&c);看起來比較艱澀,搞不好容易出錯。要熟記所有運算符優(yōu)先級比較困難。為防止歧義并提高可讀性,應(yīng)當(dāng)用括號確定表達(dá)式的操作順序,如上式可寫為:if((a|b)&&(a&c));

運算符的優(yōu)先級與結(jié)合律3.大小端倒置

大端,是指數(shù)據(jù)的高位,保存在內(nèi)存的低地址中,而數(shù)據(jù)的低

位,保存在內(nèi)存的高地址中;小端與大端相反。

例如0x11223344,

在大端系統(tǒng)的內(nèi)存中如下:

在小端系統(tǒng)中是相反順序:

…11223344……44332211…內(nèi)存增長方向系統(tǒng)與外界交互數(shù)據(jù)時通常會涉及到大小端問題,例如上位機(PC)將某歌曲信息傳給下位機(設(shè)備),歌曲信息如下,規(guī)定傳輸高位在前,低位在后(大端方式)。

設(shè)備一般會定義相應(yīng)結(jié)構(gòu)體:typedefstruct{ chartype;//分類 shortrate;//采樣率 intlen;//長度}SONG_INFO,*pSONG_INFO;inthandle_song_info(uchar*buf){chartype;shortrate;intlen;pSONG_INFOpsong_info;psong_info=(pSONG_INFO)buf;type=psong_info->type;rate=psong_info->rate;len=psong_info->len;……}buf是接收PC數(shù)據(jù)的緩沖區(qū),假設(shè)接收到數(shù)據(jù)在buf中如下:在大端的CPU得到正確結(jié)果:rate:0x2233,len:0x44556677在小端的CPU得到的是:rate:0x3322,len:0x77665544顯然與協(xié)議規(guī)定的不一致,要做如下大小端轉(zhuǎn)換:rate=htons(psong_info->rate);len=htonl(psong_info->len);單字節(jié)不用考慮大小端問題,如例中的type變量。11223344556677常見問題:4.內(nèi)存越界

內(nèi)存越界難以被發(fā)現(xiàn),往往會導(dǎo)致離奇古怪的問題,如一些變量值無故被修改、程序跑飛、系統(tǒng)重啟等。

內(nèi)存分配有3種:棧內(nèi)存、堆內(nèi)存和靜態(tài)內(nèi)存(全局變量、靜態(tài)變量),相應(yīng)內(nèi)存越界有3種情況:棧內(nèi)存越界、堆內(nèi)存越界、靜態(tài)內(nèi)存越界。

棧內(nèi)存堆內(nèi)存靜態(tài)內(nèi)存 1)棧內(nèi)存越界

深入了解棧,對提高程序的效率、程序調(diào)試、問題的定位都有很大的幫助。棧實際就是一塊連續(xù)內(nèi)存,用于開辟局部變量、傳遞參數(shù)、進入子程序前保存現(xiàn)場,入棧是從高地址向低地址增長。CPU內(nèi)部有一個寄存器作為棧指針SP,指向當(dāng)前棧地址。開始時SP指向棧頂,也就是??臻g的最高地址處。每當(dāng)入棧n字節(jié)數(shù)據(jù),硬件自動將SP減n,出棧時SP自動加n,棧后進先出?!璖P棧空間高地址低地址2023/2/3Socket模型介紹CPU內(nèi)部有一組寄存器R0~R15,其中:R13:就是棧指針SP。R15:為程序計數(shù)寄存器PC,指向當(dāng)前執(zhí)行指令的地址。R14:為連接寄存器LR,在調(diào)用子程序時,由R14保存返回地址。R0~R12:為通用寄存器,用于數(shù)據(jù)操作。內(nèi)存中的數(shù)據(jù)不能在內(nèi)存中作運算,只能先加載到通用寄存器中,在寄存器里完成運算,結(jié)果再存回內(nèi)存。例如:buf[10]++;要先將buf[10]的值加載到寄存器,寄存器作自加,結(jié)果再存回buf[10]。雖然只有一個語句,但并非原子操作,需要執(zhí)行多個指令。這就是在臨界區(qū)有時一個語句都需要加鎖的原因。棧內(nèi)存越界分析:intfun1(void){ … fun2(a,b,c,d,e,f); …}intfun2(inta,intb,intc,intd,inte,intf){ inti; charbuf1[10]; charbuf2[10]; charbuf3[10]; memset(buf2,0,100); … return0;}分析一下函數(shù)fun1調(diào)用子函數(shù)fun2后會產(chǎn)生什么后果intfun1(void){ … fun2(a,b,c,d,e,f); … R0R1R2R3}intfun2(inta,intb,intc,intd,inte,intf){ inti; charbuf1[10]; charbuf2[10]; charbuf3[10]; … memset(buf2,0,100); … return0;}??臻g高地址低地址……fePCRxbuf1buf2buf3……前4個參數(shù)通過R0~R4傳遞超過4個參數(shù)通過棧傳遞進入子函數(shù)PC先入棧調(diào)用前SPbuf2執(zhí)行清空操作越界了,誰先遭殃,有什么后果???intfun2(inta,intb,intc,intd,inte,intf){ inti; charbuf1[10]; charbuf2[10]; charbuf3[10]; … memset(buf2,0,100); … return0;}不要以為buf2越界是向buf3越界,看??臻g布局,buf2后面(高地址)緊跟的是buf1,執(zhí)行memset(buf2,0,100);把buf2地址起后面的100字節(jié)??臻g都清0,包括buf1和入棧的Rx、PC值,當(dāng)子函數(shù)返回時從棧中彈出返回地址給PC,這時PC值為0,程序跳到絕對地址為0處執(zhí)行,程序跑飛!高地址低地址……fePCRxbuf1buf2buf3……SP高地址100字節(jié)清02)堆內(nèi)存越界:

堆空間實際也是一塊連續(xù)內(nèi)存,內(nèi)存分配函數(shù)以鏈表方式將分配的內(nèi)存塊手拉手鏈接起來,因而每塊內(nèi)存都有個鏈表節(jié)點(如下圖)。每次調(diào)用內(nèi)存分配函數(shù),遍歷鏈表,找到空閑的空間足夠的內(nèi)存塊則返回給調(diào)用程序。如果某塊內(nèi)存越界就會把下一塊內(nèi)存的鏈表節(jié)點給沖掉,鏈表指針“指飛”,堆空間崩潰。prenextprenextprenext…堆內(nèi)存結(jié)構(gòu)示意圖3)靜態(tài)內(nèi)存越界:charbuf1[4];charbuf2[4];inta;intb;intmain(void){ … memset(buf2,0,100); …}memset(buf2,0,100);操作使buf2越界,從右邊內(nèi)存布局圖可以看到,變量a、b被沖掉。當(dāng)測試發(fā)現(xiàn)一些全局變量值莫名變掉,首先查看它附近是否有內(nèi)存越界。高地址低地址……babuf2buf1……高地址0x2000000c0x200000080x200000040x20000000內(nèi)存越界總結(jié):

前面例子是為了說明問題明顯制造的內(nèi)存越界,實際編程中不會這么明顯,很多時候是子函數(shù)對傳入的指針操作引起。intfun(char*buf){ inti; charstr[100]; … … strcpy(buf,str); sprintf(buf,“%s%d”,str,i); …}在調(diào)試、測試中如出現(xiàn)變量無故被修改、設(shè)備無故重啟、程序跑分現(xiàn)象,第一反應(yīng)應(yīng)該是內(nèi)存越界。5.內(nèi)存泄露

內(nèi)存泄露就是申請的內(nèi)存在不使用后沒有釋放掉。如果系統(tǒng)在運行過程中不斷的申請內(nèi)存,用完又沒釋放,勢必造成內(nèi)存耗盡而無法工作。指針被修改:intfun(void){ charstr[10]; char*p;

p=(char*)malloc(128); …

p=str; … free(p);}漏掉釋放:intfun(void){ … char*p; p=(char*)malloc(128); … if(xx){

return0; } … free(p);}6.任務(wù)優(yōu)先級問題

對于搶占式操作系統(tǒng),任務(wù)的優(yōu)先級不同,相同的操作有不同的表現(xiàn),例如uc_os系統(tǒng),每個任務(wù)的優(yōu)先級都不同,高優(yōu)先級的任務(wù)就緒后就搶占低優(yōu)先級任務(wù)獲得運行。如下假設(shè)系統(tǒng)中有兩個任務(wù)task1和task2,在創(chuàng)建任務(wù)時指定的優(yōu)先級不同,得到的執(zhí)行結(jié)果就不一樣。OS_EVENT*pevent;inta;void*task1(void*parg){ … while(1) {a=0;OSSemPost(pevent);printf(“a=%d\r\n”,a);OSTimeDly(1000); }}void*task2(void*parg){ … while(1) {a=0;OSSemPend(pevent);a=10;OSTimeDly(500); }}OS_EVENT*pevent;inta;void*task1(void*parg){ … while(1) {a=0;OSSemPost(pevent);

printf(“a=%d\r\n”,a);

OSTimeDly(1000); … }}從上面執(zhí)行軌跡可以看出,執(zhí)行結(jié)果為:a=0void*task2(void*parg){ … while(1) {a=0;OSSemPend(pevent);

a=10;

OSTimeDly(500); }}如果task1優(yōu)先級比task2高,執(zhí)行流程如下:task1休眠,主動放棄CPU,task2將獲得CPU運行task1拋出信號,OSSemPost系統(tǒng)調(diào)用發(fā)現(xiàn)task2在等待該信號但優(yōu)先級低,不切換任務(wù),繼續(xù)執(zhí)行task1。OS_EVENT*pevent;inta;void*task1(void*parg){ … while(1) {a=0;OSSemPost(pevent);

printf(“a=%d\r\n”,a);

OSTimeDly(1000); … }}從上面執(zhí)行軌跡可以看出,a被task2賦值10,所以執(zhí)行結(jié)果為:a=10void*task2(void*parg){ … while(1) {a=0;OSSemPend(pevent);

a=10;

OSTimeDly(500); }}如果task2優(yōu)先級比task1高,執(zhí)行流程如下:task2得到信號資源搶占CPU獲得運行task1拋出信號,OSSemPost系統(tǒng)調(diào)用發(fā)現(xiàn)task2在等待該信號并且優(yōu)先級高,切換到task2運行task2休眠,主動放棄CPU,task1將獲得CPU運行OSSemPost(pevent)系統(tǒng)調(diào)用流程至此任務(wù)暫停運行軟中斷中實現(xiàn)任務(wù)切換主要操作是:1.保存當(dāng)前任務(wù)的環(huán)境(R0~R15、xPSR)到該任務(wù)的棧;2.將前面找到的新任務(wù)OSPrioHighRdy賦給當(dāng)前任務(wù)OSPrioCur變量,新任務(wù)成為當(dāng)前任務(wù);3.從新任務(wù)的棧中彈出其之前的運行環(huán)境。至此,任務(wù)環(huán)境切換完畢,中斷子程序退出后新任務(wù)就得以運行,實現(xiàn)了任務(wù)切換?!璓CR0~R3R4~R11SP……PCR0~R3R4~R11SP……當(dāng)前任務(wù)環(huán)境入棧新任務(wù)環(huán)境出棧OSPrioCur=OSPrioHighRdy當(dāng)前任務(wù)棧空間新任務(wù)??臻g123實例分析丟包問題死機問題爆音問題

1.丟包問題現(xiàn)象:IP廣播設(shè)備連續(xù)播放10分鐘到半小時內(nèi)出現(xiàn)不可自動回復(fù)的丟包,大約每5隔5秒丟100包,造成音頻播放嚴(yán)重卡頓。解決過程:首先問題定位以縮小查找范圍,將問題出處設(shè)定在:服務(wù)器、設(shè)備端應(yīng)用層代碼、tcp/ip協(xié)議棧。觀察設(shè)備端應(yīng)用層代碼和telnet打印信息,發(fā)現(xiàn)應(yīng)用層從協(xié)議接收到的數(shù)據(jù)包都沒有丟失,基本排除應(yīng)用層;服務(wù)器日志顯示確實有數(shù)據(jù)包發(fā)不出,范圍再次縮?。菏欠?wù)器問題導(dǎo)致發(fā)不出還是設(shè)備端接收有問題。懷疑可能設(shè)備端協(xié)議棧分配不到內(nèi)存導(dǎo)致接收不了數(shù)據(jù),調(diào)試發(fā)現(xiàn)確實出現(xiàn)分配內(nèi)存失敗。后來開啟協(xié)議棧的打印信息,發(fā)現(xiàn)協(xié)議棧的內(nèi)存池分配失敗。查看協(xié)議棧代碼得知分配內(nèi)存有2種方式:內(nèi)存池和內(nèi)存堆,原來默認(rèn)的是內(nèi)存池方式。后來嘗試改成內(nèi)存堆方式,不再丟包。tcp/ip協(xié)議棧底層接收數(shù)據(jù)時申請緩沖內(nèi)存,程序片段:if(len>0){

//p=pbuf_alloc(PBUF_RAW,len,PBUF_POOL); p=pbuf_alloc(PBUF_RAW,len,PBUF_RAM); /*Copyreceivedframefromethernetdriverbuffertostackbuffer*/ if(p!=NULL) { for(q=p;q!=NULL;q=q->next) { memcpy((u8_t*)q->payload,(u8_t*)&buffer[l],q->len); l=l+q->len; } }}

原來的內(nèi)存池方式改后的內(nèi)存堆方式2.死機問題現(xiàn)象:IP廣播設(shè)備連續(xù)播放4~10小時不等,基本出現(xiàn)與服務(wù)器失聯(lián),CPU指示燈不閃,telnet不通,ping不通。解決過程:這種問題一般是程序進入了某個死循環(huán)出不來,非常難定位,即使把全部代碼都仔細(xì)去看一遍也難以看出來,況且開源的tcp/ip協(xié)議棧代碼不大可能去通讀。這時最好的方法就是硬件調(diào)試,讓調(diào)試器一直開著,直到出現(xiàn)問題,暫停運行看程序停在哪個代碼段,那里一般就是死循環(huán)的地方。while(pcb!=NULL){ if(pcb->last_timer!=tcp_timer_ctr){ structtcp_pcb*next; pcb->last_timer=tcp_timer_ctr; /*senddelayedACKs*/ if(pcb->flags&TF_ACK_DELAY){ LWIP_DEBUGF(TCP_DEBUG,("delayedACK\n")); tcp_ack_now(pcb); tcp_output(pcb); pcb->flags&=~(TF_ACK_DELAY|TF_ACK_NOW); } next=pcb->next; …… pcb=next; } else{ pcb=pcb->next; }}當(dāng)這個條件不成立時,這段程序就死循環(huán)了修正,if條件不成立時使pcb指向鏈表下一節(jié)點3.爆音問題現(xiàn)象:IP廣播設(shè)備在播放,突然音量自動變得非常大,出現(xiàn)很隨機。解決過程:首先查看所有修改音量的代碼,沒發(fā)現(xiàn)異常。懷疑是不是服務(wù)器發(fā)指令修改音量,修改音量telnet會打印相關(guān)信息,爆音時telnet沒有打印修改音量信息,排除掉服務(wù)器引起。偶爾觀察到爆音時打?。骸敖邮諗?shù)據(jù)xx,有效數(shù)據(jù)xxx”。搜索代碼出現(xiàn)在接收音頻數(shù)據(jù)的代碼段如下:

AvaDataSize=GetAudioDataAvaSpaD

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論