博客專欄

EEPW首頁 > 博客 > 一個半小時,遠程解決一個 APP跳轉(zhuǎn) BUG

一個半小時,遠程解決一個 APP跳轉(zhuǎn) BUG

發(fā)布人:魚鷹談單片機 時間:2022-03-19 來源:工程師 發(fā)布文章

昨天有一位讀者剛關(guān)注魚鷹,并且很快加了魚鷹微信,描述了以下問題:

圖片

圖片

當時也沒有細看問題,只是大概看了一下,然后簡單的提供了一個思路給對方,畢竟魚鷹也比較忙,不可能花太多時間在別人的問題上。


而且也是看對方的問題描述比較清楚,比較有誠意,所以才會提供一個思路,否則可能懶得回復了。所以大家問問題的時候一定要直接詳細描述,否則沒人不愿意回答。畢竟很多人問完并回復之后,可能一句謝謝都沒有就沒有下文了,這種事情見多了。好像別人幫助你是理所應(yīng)當?shù)摹?/p>


只是沒想到,對方會提出給報酬,所以看他挺有誠意的,就開玩笑的問問多少錢。然后開始報價,并且對方也同意我的報價,并愿意多給一倍。

圖片


既然他那么有誠意,晚上也沒啥事情,所以還是按自己的報價(有原則的魚鷹)確定下來 20 點左右開始遠程解決問題。


8 點半左右開始正式遠程解決,原本以為半小時能搞定,實際上花了一個半小時。這里稍微總結(jié)一下。


首先是讓對方復現(xiàn)問題,然后和正常的情況一并復現(xiàn),這里花了幾分鐘,確定了好的代碼與不好的代碼不同現(xiàn)象。


這里可能有點奇怪,為啥有好的代碼(boot 能正常跳轉(zhuǎn)到 APP),還要找魚鷹解決,魚鷹開始也有點納悶,后來才知道,原來好的代碼只要稍微改點代碼,就不能正常跳轉(zhuǎn)了,這肯定是不行的,因此找上了魚鷹(其實描述也說了,只是魚鷹沒太在意)。


根據(jù)目前了解的情況來看,怎么說也是 APP 的問題,畢竟 Boot 有成功跳轉(zhuǎn)的情況。


開始的時候,魚鷹的方向確實在 APP 上,還仔細的看了看 APP 的編譯警告問題(很多人不注意警告,總是在工程里面遺留很多警告,雖然很多情況下,這些警告不會有問題,但是萬一呢。所以建議大家盡量解決工程的警告, 0 error 0 warning還是相當舒服的),這里也花了幾分鐘確認,發(fā)現(xiàn)確實無關(guān)大雅。

圖片


之后又是嘗試了幾次好代碼與壞代碼的差別,發(fā)現(xiàn)在跳轉(zhuǎn)代碼部分,沒有任何區(qū)別,跳轉(zhuǎn)地址: 0x00010000 棧頂?shù)刂罚?nbsp;0xE000ED08(通過匯編代碼分析)。


但這個反常的現(xiàn)象卻引起了魚鷹的警惕, 因為據(jù)魚鷹了解到的 Cortex-M3  內(nèi)核知識《STM32固件升級之基礎(chǔ)知識(一)》,兩個不同的 APP 這兩個地址大概率是不同的。


雖然它是 M33 的內(nèi)核,但也不應(yīng)該差別那么大。


而且內(nèi)存地址也不應(yīng)該是 0xE000 開頭的,所以又是查 map 文件,又是看鏈接文件,又是上網(wǎng)(魚鷹對 M33 的跳轉(zhuǎn)不熟悉,所以需要了解情況,否則解決時間可以縮短不少),又是和提問者溝通,最終得到以下信息:


1、兩個代碼確實不同(這個可以確定編譯沒有問題),通過 map 可以分析出來,但為什么一份可以,一份不可以?boot的跳轉(zhuǎn)地址和棧頂?shù)刂愤€一樣?不符合常理!


2、調(diào)試過程中發(fā)現(xiàn)跳轉(zhuǎn)時不會運行到啟動文件(*.s),這有悖常理!


3、內(nèi)存地址實際從 0x20000000 開始;


4、APP 鏈接文件修改的地方由 NXP 的 FAE 告知,跳轉(zhuǎn)到 APP 部分的代碼也是 FAE 提供的(一開始就了解了這個情況,所以沒有一開始就懷疑這部分代碼)。


5、通過查看 flash 0x0001 0000 地址處的內(nèi)容,發(fā)現(xiàn)兩份代碼有不同,確定下載沒有問題。


結(jié)合上面的兩個地址(跳轉(zhuǎn)地址和棧頂?shù)刂罚ㄏ燃僭O(shè)是這樣,因為 M3 內(nèi)核就是這樣,M33 內(nèi)核估計差不了多少)),魚鷹開始重點查看這個跳轉(zhuǎn)代碼(NXP FAE 提供)




















#define ApplicationAddress    0x10000
void JumpToUserApplication(unsigned long userSP, unsigned long userStartup){ // set up stack pointer  __asm("msr msp, r0");  __asm("msr psp, r0");
 // Jump to PC (r1)  __asm("mov pc, r1"); }
void StartUp(void){ // relocate vector table SCB->VTOR = ApplicationAddress;   // Jump to user application JumpToUserApplication(*((unsigned long*)ApplicationAddress), *((unsigned long*)(ApplicationAddress+4)));    }


乍看,和魚鷹理解的 M3 類似,都是在跳轉(zhuǎn)時取出 APP 首地址處的 8 個字節(jié)作為 棧頂指針 和 PC 指針。


但是從 C 語言的角度,你看不出任何毛病,很正常,但是它最終到 JumpToUserApplication 時卻是 0x0001 0000 和 0xE000ED08,這個和前面的分析完全不符。


沒辦法,只能拿出魚鷹的殺手锏,匯編


之后就發(fā)現(xiàn),這個嵌入式匯編在跳轉(zhuǎn)時,并沒有取出 0x0001 0000 地址的 8個數(shù)據(jù),而是直接沿用前面的 SCB->VTOR = ApplicationAddress;  運行后的 R0、 R1作為參數(shù)傳遞進去,最終導致跳轉(zhuǎn)失敗。


也就是說,問題出在 BOOT 上,而不是 APP 里面,所謂的好代碼只是湊巧趕上了,這也就能解釋為什么跳轉(zhuǎn)時不會運行到啟動文件了。


找到問題,但因為對匯編不熟,又是一頓改寫,測試,總算成功跳轉(zhuǎn)了。也算是完成了任務(wù)。

圖片

從這次解決 BUG 的經(jīng)歷中,各位道友可以發(fā)現(xiàn),這里運用了非常多的基礎(chǔ)知識(內(nèi)存分配、向量表、map文件、鏈接文件、匯編等等),正因為有這些知識的積累,此案才能順利告破。


解 BUG,就像一個破案的警察,不僅需要從蛛絲馬跡中尋找線索,還需要很多理論基礎(chǔ)支撐,足夠敏感,才能順利解決,否則只能干瞪眼了。


但個人覺得,自己的行為像一個殺手,你出錢,我辦事,各取所需。


這次是魚鷹第一次有償且親自遠程解決疑難問題,覺得挺有意義的,故此記錄。


另外如果其他道友有難解的 BUG,同時又愿意付費解決的話,歡迎咨詢魚鷹,魚鷹視情況收費(可能不低,但可以節(jié)省時間,項目緊急的話歡迎找魚鷹),當然也可以雇傭魚鷹作為 MCU 技術(shù)顧問,幫助公司解決一些難解問題。


在此感謝大家對魚鷹的關(guān)注與支持!


*博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點,如有侵權(quán)請聯(lián)系工作人員刪除。



關(guān)鍵詞: 單片機

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉