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

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

嵌入式軟件調試、測試、問題定位

經驗分享AEBELL陸燦2014-11-18內容:嵌入式軟件開發概述常見問題及分析實例分析總結

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

嵌入式軟件開發根據不同的硬件平臺、不同的操作系統、不同的開發環節有著多個的方向,如不帶操作系統的前后臺程序開發;帶操作系統的可以有bootloader開發、內核開發、驅動開發、應用開發等。

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

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

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

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

運算符的優先級與結合律3.大小端倒置

大端,是指數據的高位,保存在內存的低地址中,而數據的低

位,保存在內存的高地址中;小端與大端相反。

例如0x11223344,

在大端系統的內存中如下:

在小端系統中是相反順序:

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

設備一般會定義相應結構體: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數據的緩沖區,假設接收到數據在buf中如下:在大端的CPU得到正確結果:rate:0x2233,len:0x44556677在小端的CPU得到的是:rate:0x3322,len:0x77665544顯然與協議規定的不一致,要做如下大小端轉換:rate=htons(psong_info->rate);len=htonl(psong_info->len);單字節不用考慮大小端問題,如例中的type變量。11223344556677常見問題:4.內存越界

內存越界難以被發現,往往會導致離奇古怪的問題,如一些變量值無故被修改、程序跑飛、系統重啟等。

內存分配有3種:棧內存、堆內存和靜態內存(全局變量、靜態變量),相應內存越界有3種情況:棧內存越界、堆內存越界、靜態內存越界。

棧內存堆內存靜態內存 1)棧內存越界

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

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

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

內存泄露就是申請的內存在不使用后沒有釋放掉。如果系統在運行過程中不斷的申請內存,用完又沒釋放,勢必造成內存耗盡而無法工作。指針被修改: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.任務優先級問題

對于搶占式操作系統,任務的優先級不同,相同的操作有不同的表現,例如uc_os系統,每個任務的優先級都不同,高優先級的任務就緒后就搶占低優先級任務獲得運行。如下假設系統中有兩個任務task1和task2,在創建任務時指定的優先級不同,得到的執行結果就不一樣。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); … }}從上面執行軌跡可以看出,執行結果為:a=0void*task2(void*parg){ … while(1) {a=0;OSSemPend(pevent);

a=10;

OSTimeDly(500); }}如果task1優先級比task2高,執行流程如下:task1休眠,主動放棄CPU,task2將獲得CPU運行task1拋出信號,OSSemPost系統調用發現task2在等待該信號但優先級低,不切換任務,繼續執行task1。OS_EVENT*pevent;inta;void*task1(void*parg){ … while(1) {a=0;OSSemPost(pevent);

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

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

a=10;

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

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

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

AvaDataSize=GetAudioDataAvaSpaD

溫馨提示

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

最新文檔

評論

0/150

提交評論