版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年氮化硅陶瓷軸承球合作協(xié)議書(shū)
- 室外廣告位租賃合同
- 電視劇演員合同范本
- 影視素材許可使用合同
- 工業(yè)互聯(lián)網(wǎng)平臺(tái)建設(shè)與運(yùn)營(yíng)優(yōu)化方案
- 品牌廣告投放優(yōu)化合作協(xié)議
- 服裝行業(yè):服裝定制生產(chǎn)方案
- 家居行業(yè)智能家居與家居安全系統(tǒng)方案
- 產(chǎn)品創(chuàng)新設(shè)計(jì)與市場(chǎng)需求匹配分析指南
- 建筑行業(yè)信息化管理服務(wù)合同
- 基坑監(jiān)測(cè)課件ppt版(共155頁(yè))
- 開(kāi)發(fā)區(qū)開(kāi)發(fā)管理模式及發(fā)展要素PPT課件
- 急診科科主任述職報(bào)告范文
- 基于MATLAB語(yǔ)音信號(hào)降噪處理
- 試訓(xùn)運(yùn)動(dòng)員協(xié)議書(shū)
- 淮海工學(xué)院數(shù)據(jù)庫(kù)原理與技術(shù)復(fù)習(xí)題及答案
- 建龍資料備案正版表格
- 化工原理期末考試練習(xí)題及答案
- 數(shù)值分析課后習(xí)題答案(共81頁(yè))
- 網(wǎng)絡(luò)安全運(yùn)維培訓(xùn)測(cè)試題
- 民政部主管社團(tuán)管理辦法
評(píng)論
0/150
提交評(píng)論