[英]call stack unwinding in ARM cortex m3
我想創建一個調試工具,它將幫助我更好地調試應用程序。 我正在使用准系統(沒有操作系統)。 在Atmel的SAM3上使用IAR嵌入式工作台。
我有一個看門狗定時器,它在超時的情況下會調用特定的IRQ(它將在發行時由軟件重置來代替)。 在IRQ處理程序中,我想打印(UART)堆棧跟蹤,以了解看門狗超時發生的確切位置。
我在網上查看,但沒有找到該功能的任何實現。
有人對如何處理這種事情有想法嗎?
編輯:好的,我設法從堆棧中獲取返回地址,所以我確切地知道WDT超時發生的位置。 展開整個堆棧並不像它初看起來那樣簡單,因為每個函數會將不同數量的局部變量壓入堆棧。
我最終得到的代碼是這樣的(對於其他人,可能會覺得有用)
void WDT_IrqHandler( void )
{
uint32_t * WDT_Address;
Wdt *pWdt = WDT ;
volatile uint32_t dummy ;
WDT_Address = (uint32_t *) __get_MSP() + 16 ;
LogFatal ("Watchdog Timer timeout,The Return Address is %#X", *WDT_Address);
/* Clear status bit to acknowledge interrupt */
dummy = pWdt->WDT_SR ;
}
ARM定義了.ARM.exidx和.ARM.extbl這對節,它們包含足夠的信息來展開堆棧而沒有調試符號。 這些部分用於異常處理,但是您也可以使用它們執行回溯。 添加-funwind-tables以強制GCC包括這些部分。
我聽到我的名字了嗎? :)
您可能需要一點點內聯匯編。 只需弄清楚堆棧幀的格式,以及哪個寄存器保存普通的1堆棧指針,然后將相關值傳輸到C變量中,您就可以從中格式化字符串以輸出到UART。
它不應該太棘手,但是當然(相當低級),您需要注意細節。
1如“非例外”中所述; 實際上,不確定ARM是否具有用於普通代碼和異常的不同堆棧。
為此,對於ARM,您將需要告訴編譯器生成堆棧幀。 例如,對於gcc,請檢查選項-mapcs-frame
。 它可能不是您所需要的,但這只是一個開始。
如果您沒有此功能,則幾乎不可能“展開”堆棧,因為根據參數和局部變量,每個函數都需要確切的堆棧用法。
如果您正在尋找一些dump_stack()
代碼,則可以在Linux內核源代碼中檢查dump_stack()
,並找到為ARM執行的相關代碼段。
跟隨執行應該很簡單。 不在您的島中以編程方式...
從ARM ARM知道,在Cortex-M3上它將xPSR,ReturnAddress,LR(R14),R12,R3,R2,R1和R0推入堆棧。 修改lr,以便它可以檢測到中斷返回,然后調用向量表中列出的入口點。 如果您在asm中實現isr來控制堆棧,則可以有一個簡單的循環來禁用中斷源(關閉wdt,無論如何,這將需要一些時間),然后進入循環以轉儲部分中斷。堆。
從該轉儲中,您將看到lr /返回地址,即被中斷的函數/指令,從程序的反匯編中,您可以看到編譯器為每個函數放置在堆棧上的內容,然后在每個階段減去該值並繼續執行盡可能遠的距離或打印堆棧內容的距離。
您也可以在ram中復制堆棧並稍后對其進行解剖,而不是在isr中進行此類操作(該副本仍然花費太多時間,但比等待uart更具干擾性)。
如果您所需要的只是被中斷的指令的地址,那是最瑣碎的任務,只需從堆棧中讀取該地址,它將位於已知位置,然后將其打印出來。
您的看門狗定時器可以隨時觸發,即使堆棧中沒有足夠的信息來釋放(例如,堆棧空間已分配用於寄存器溢出,但尚未復制寄存器)。
對於正確優化的代碼,您需要調試信息,期限。 看門狗定時器所能做的就是以機械可讀的格式進行寄存器和堆棧轉儲,以允許轉換為gdb
的核心轉儲。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.