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

下載本文檔

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

文檔簡(jiǎn)介

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

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

嵌入式軟件開(kāi)發(fā),是指針對(duì)嵌入式硬件平臺(tái)帶嵌入式操作系統(tǒng)的軟件開(kāi)發(fā),硬件平臺(tái)包括:?jiǎn)纹瑱C(jī)、ARM、PowerPC、DSP、MIPS等;主流嵌入式操作系統(tǒng)有:嵌入式linux、VxWorks、wince等。廣義的嵌入式軟件開(kāi)發(fā)還包括單片機(jī)軟件開(kāi)發(fā)。

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

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

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

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

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

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

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

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

例如0x11223344,

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

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

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

設(shè)備一般會(huì)定義相應(yīng)結(jié)構(gòu)體:typedefstruct{ chartype;//分類(lèi) shortrate;//采樣率 intlen;//長(zhǎng)度}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é)不用考慮大小端問(wèn)題,如例中的type變量。11223344556677常見(jiàn)問(wèn)題:4.內(nèi)存越界

內(nèi)存越界難以被發(fā)現(xiàn),往往會(huì)導(dǎo)致離奇古怪的問(wèn)題,如一些變量值無(wú)故被修改、程序跑飛、系統(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)存越界

深入了解棧,對(duì)提高程序的效率、程序調(diào)試、問(wèn)題的定位都有很大的幫助。棧實(shí)際就是一塊連續(xù)內(nèi)存,用于開(kāi)辟局部變量、傳遞參數(shù)、進(jìn)入子程序前保存現(xiàn)場(chǎng),入棧是從高地址向低地址增長(zhǎng)。CPU內(nèi)部有一個(gè)寄存器作為棧指針SP,指向當(dāng)前棧地址。開(kāi)始時(shí)SP指向棧頂,也就是??臻g的最高地址處。每當(dāng)入棧n字節(jié)數(shù)據(jù),硬件自動(dòng)將SP減n,出棧時(shí)SP自動(dòng)加n,棧后進(jìn)先出?!璖P??臻g高地址低地址2023/2/3Socket模型介紹CPU內(nèi)部有一組寄存器R0~R15,其中:R13:就是棧指針SP。R15:為程序計(jì)數(shù)寄存器PC,指向當(dāng)前執(zhí)行指令的地址。R14:為連接寄存器LR,在調(diào)用子程序時(shí),由R14保存返回地址。R0~R12:為通用寄存器,用于數(shù)據(jù)操作。內(nèi)存中的數(shù)據(jù)不能在內(nèi)存中作運(yùn)算,只能先加載到通用寄存器中,在寄存器里完成運(yùn)算,結(jié)果再存回內(nèi)存。例如:buf[10]++;要先將buf[10]的值加載到寄存器,寄存器作自加,結(jié)果再存回buf[10]。雖然只有一個(gè)語(yǔ)句,但并非原子操作,需要執(zhí)行多個(gè)指令。這就是在臨界區(qū)有時(shí)一個(gè)語(yǔ)句都需要加鎖的原因。棧內(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后會(huì)產(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;}棧空間高地址低地址……fePCRxbuf1buf2buf3……前4個(gè)參數(shù)通過(guò)R0~R4傳遞超過(guò)4個(gè)參數(shù)通過(guò)棧傳遞進(jìn)入子函數(shù)PC先入棧調(diào)用前SPbuf2執(zhí)行清空操作越界了,誰(shuí)先遭殃,有什么后果???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ù)返回時(shí)從棧中彈出返回地址給PC,這時(shí)PC值為0,程序跳到絕對(duì)地址為0處執(zhí)行,程序跑飛!高地址低地址……fePCRxbuf1buf2buf3……SP高地址100字節(jié)清02)堆內(nèi)存越界:

堆空間實(shí)際也是一塊連續(xù)內(nèi)存,內(nèi)存分配函數(shù)以鏈表方式將分配的內(nèi)存塊手拉手鏈接起來(lái),因而每塊內(nèi)存都有個(gè)鏈表節(jié)點(diǎn)(如下圖)。每次調(diào)用內(nèi)存分配函數(shù),遍歷鏈表,找到空閑的空間足夠的內(nèi)存塊則返回給調(diào)用程序。如果某塊內(nèi)存越界就會(huì)把下一塊內(nèi)存的鏈表節(jié)點(diǎn)給沖掉,鏈表指針“指飛”,堆空間崩潰。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)測(cè)試發(fā)現(xiàn)一些全局變量值莫名變掉,首先查看它附近是否有內(nèi)存越界。高地址低地址……babuf2buf1……高地址0x2000000c0x200000080x200000040x20000000內(nèi)存越界總結(jié):

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

內(nèi)存泄露就是申請(qǐng)的內(nèi)存在不使用后沒(méi)有釋放掉。如果系統(tǒng)在運(yùn)行過(guò)程中不斷的申請(qǐng)內(nèi)存,用完又沒(méi)釋放,勢(shì)必造成內(nèi)存耗盡而無(wú)法工作。指針被修改: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)先級(jí)問(wèn)題

對(duì)于搶占式操作系統(tǒng),任務(wù)的優(yōu)先級(jí)不同,相同的操作有不同的表現(xiàn),例如uc_os系統(tǒng),每個(gè)任務(wù)的優(yōu)先級(jí)都不同,高優(yōu)先級(jí)的任務(wù)就緒后就搶占低優(yōu)先級(jí)任務(wù)獲得運(yùn)行。如下假設(shè)系統(tǒng)中有兩個(gè)任務(wù)task1和task2,在創(chuàng)建任務(wù)時(shí)指定的優(yōu)先級(jí)不同,得到的執(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)先級(jí)比task2高,執(zhí)行流程如下:task1休眠,主動(dòng)放棄CPU,task2將獲得CPU運(yùn)行task1拋出信號(hào),OSSemPost系統(tǒng)調(diào)用發(fā)現(xiàn)task2在等待該信號(hào)但優(yōu)先級(jí)低,不切換任務(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)先級(jí)比task1高,執(zhí)行流程如下:task2得到信號(hào)資源搶占CPU獲得運(yùn)行task1拋出信號(hào),OSSemPost系統(tǒng)調(diào)用發(fā)現(xiàn)task2在等待該信號(hào)并且優(yōu)先級(jí)高,切換到task2運(yùn)行task2休眠,主動(dòng)放棄CPU,task1將獲得CPU運(yùn)行OSSemPost(pevent)系統(tǒng)調(diào)用流程至此任務(wù)暫停運(yùn)行軟中斷中實(shí)現(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ù)的棧中彈出其之前的運(yùn)行環(huán)境。至此,任務(wù)環(huán)境切換完畢,中斷子程序退出后新任務(wù)就得以運(yùn)行,實(shí)現(xiàn)了任務(wù)切換。……PCR0~R3R4~R11SP……PCR0~R3R4~R11SP……當(dāng)前任務(wù)環(huán)境入棧新任務(wù)環(huán)境出棧OSPrioCur=OSPrioHighRdy當(dāng)前任務(wù)??臻g新任務(wù)??臻g123實(shí)例分析丟包問(wèn)題死機(jī)問(wèn)題爆音問(wèn)題

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

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

AvaDataSize=GetAudioDataAvaSpaD

溫馨提示

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

評(píng)論

0/150

提交評(píng)論