女人被狂躁到高潮视频免费无遮挡,内射人妻骚骚骚,免费人成小说在线观看网站,九九影院午夜理论片少妇,免费av永久免费网址

當(dāng)前位置:首頁(yè) > > 嵌入式IoT

前言


我們往往在進(jìn)行嵌入式開(kāi)發(fā)的過(guò)程中,需要借助一些調(diào)試手段進(jìn)行相關(guān)調(diào)試,比如在調(diào)試stm32的時(shí)候,可以在keil中利用jtag或者stlink進(jìn)行硬件上的仿真與調(diào)試,一些高頻的arm芯片也會(huì)使用jtag之類(lèi)的硬件調(diào)試工具,還有trace32等等,但是這些往往需要借助一些硬件工具進(jìn)行分析。當(dāng)然,我們可以進(jìn)行軟件層面的分析。定位問(wèn)題的方式通常有以下三點(diǎn):

1.通過(guò)串口打印信息進(jìn)行業(yè)務(wù)邏輯的梳理,結(jié)合代碼設(shè)計(jì)進(jìn)行分析

2.在程序死機(jī)的時(shí)候,輸出的函數(shù)調(diào)用棧關(guān)系進(jìn)行分析,結(jié)合符號(hào)文件進(jìn)行跟蹤定位

3.在程序死機(jī)時(shí)輸出內(nèi)存鏡像,利用gdb還原死機(jī)現(xiàn)場(chǎng)

一般來(lái)講,這三種方法都有一定的優(yōu)缺點(diǎn)。

第一種靠串口輸出信息一般比較有限,而且對(duì)于有些情況,串口輸出沒(méi)辦法進(jìn)行準(zhǔn)確的定位,但是比較方便,實(shí)現(xiàn)起來(lái)比較容易。

第二種可以查看到函數(shù)調(diào)用的關(guān)系,根據(jù)這些調(diào)用關(guān)系,就可以非常方便的跟蹤到出問(wèn)題的地方,然后進(jìn)行一定的跟蹤。但是需要理解寄存和匯編之類(lèi)的知識(shí)。

第三種的信息最全,調(diào)用關(guān)系和參數(shù)信息都有,但是對(duì)工具鏈和系統(tǒng)都提出了一些要求。往往在嵌入式開(kāi)發(fā)過(guò)程中,涉及到業(yè)務(wù)邏輯非常復(fù)雜的時(shí)候可以進(jìn)行分析。但是一般的情況不會(huì)用到coredump。

第一種可以不用講,現(xiàn)在主要講一下backtrace。

01

backtrace簡(jiǎn)介

backtrace就是回溯堆棧,簡(jiǎn)單的說(shuō)就是可以列出當(dāng)前函數(shù)調(diào)用關(guān)系。在理解backtrace之前我們需要理解一下函數(shù)執(zhí)行過(guò)程的中的壓棧過(guò)程。

1.1 寄存器與匯編指令

ARM微處理器共有37個(gè)寄存器,其中31個(gè)為通用寄存器,6個(gè)為狀態(tài)寄存器。但是往往這些寄存器都不能同時(shí)被訪(fǎng)問(wèn),需要在特定的模式下訪(fǎng)問(wèn)特定的指令。

但在任何時(shí)候,通用寄存器R0~R15、一個(gè)或兩個(gè)狀態(tài)寄存器都是可訪(fǎng)問(wèn)的。有三個(gè)特殊的通用寄存器:R13:在A(yíng)RM指令中常用作堆棧指針SPR14:也稱(chēng)作子程序連接寄存器(Subroutine Link Register)即連接寄存器LRR15:也稱(chēng)作程序計(jì)數(shù)器PC

還有一個(gè)寄存器

R11:棧基址FP

THUMB2下為R7。

1.2 函數(shù)的壓棧與入棧操作

當(dāng)函數(shù)main調(diào)用func1的時(shí)候其棧的過(guò)程如上圖所示,每個(gè)函數(shù)都有自己的??臻g,這一部分我們稱(chēng)為棧幀,在函數(shù)被調(diào)用的時(shí)候創(chuàng)建,在函數(shù)返回后銷(xiāo)毀。

其中我們看到這其中涉及到四個(gè)比較關(guān)鍵的寄存器:PC、LR、SP、FP。需要注意的是,每個(gè)棧幀中的PC、LR、SP、FP都是寄存器的歷史值,而不是當(dāng)前值。

PC寄存器和LR寄存器均指向代碼段,PC表示當(dāng)前的代碼指向到何處,LR表示當(dāng)前函數(shù)返回后要到哪里去繼續(xù)執(zhí)行。

SP和FP用于維護(hù)函數(shù)的??臻g,其中SP指向棧頂,F(xiàn)P指向上一個(gè)函數(shù)棧幀的棧頂。

如上圖所示

依次為當(dāng)前函數(shù)指針PC、返回指針LR、棧指針SP、?;稦P、傳入?yún)?shù)個(gè)數(shù)及指針、本地變量和臨時(shí)變量。如果函數(shù)準(zhǔn)備調(diào)用另一個(gè)函數(shù),跳轉(zhuǎn)之前臨時(shí)變量區(qū)先要保存另一個(gè)函數(shù)的參數(shù)。

1.3 棧回溯過(guò)程原理

在?;厮莸倪^(guò)程中,我們主要是利用的是這個(gè)FP寄存器進(jìn)行回溯,因?yàn)楦鶕?jù)FP寄存器就可以找到下一個(gè)FP寄存器的棧底,獲得PC指針,然后固定偏移,又可以回溯到上個(gè)PC指針,這樣回溯下去,然后就可以完全的跟蹤到函數(shù)的運(yùn)行過(guò)程了。然后利用addr2line工具,就可以詳細(xì)跟蹤到函數(shù)的執(zhí)行過(guò)程了。

02

backtrace的過(guò)程詳解

當(dāng)程序出現(xiàn)異常或者死機(jī)的時(shí)候,我們可以讀取當(dāng)前寄存器的狀態(tài),找到當(dāng)前pc指針的情況,但是這些往往還不能說(shuō)明問(wèn)題,我們有時(shí)需要跟蹤函數(shù)的執(zhí)行過(guò)程。

棧的回溯又分為兩種:APCS(ARM Procedure Call Standard)與unwind。

棧回溯的實(shí)現(xiàn)依賴(lài)編譯器的特性,與特定的平臺(tái)相關(guān)。以linux內(nèi)核實(shí)現(xiàn)arm?;厮轂槔?通過(guò)向gcc傳遞選項(xiàng)-mapcs或-funwind-tables,可選擇APCS或unwind的任一方 式實(shí)現(xiàn)?;厮荨?

gcc的有些編譯優(yōu)化命令,會(huì)讓FP寄存器優(yōu)化掉,比如-fomit-frame-pointer這個(gè)優(yōu)化會(huì)讓fp寄存器節(jié)省下來(lái)給其他的地方使用。所以要充分考慮這些問(wèn)題。

2.1 APCS

ARM過(guò)程調(diào)用標(biāo)準(zhǔn)規(guī)范了arm寄存器的使用、過(guò)程調(diào)用時(shí) 出棧和入棧的約定。如下圖示意。

?;厮葜休敵龅募拇嫫鞯闹凳侨霔r(shí)保存起來(lái)的寄存器值。它通過(guò)解析指令碼得到哪個(gè) 寄存器壓棧了,在棧中的位置。

如果編譯器遵循APCS,形成結(jié)構(gòu)化的函數(shù)調(diào)用棧,就可以解析當(dāng)前棧(callee)結(jié)構(gòu),從 而得到調(diào)用棧(caller)的結(jié)構(gòu),這樣就輸出了整個(gè)回溯棧。

2.2 unwind

對(duì)于A(yíng)PCS來(lái)說(shuō),優(yōu)點(diǎn)是分析起來(lái)比較簡(jiǎn)單,跟蹤起來(lái)也可以很容易。缺點(diǎn)就是指令過(guò)多,棧消耗大,占用的寄存器也過(guò)多,比如每次調(diào)用 都必須將r11,r12,lr,pc入棧。為了解決這個(gè)問(wèn)題,提出了第二種方案:

使用unwind就能避免這些問(wèn)題,生產(chǎn)指令的效率要有用的多。unwind是最新的編譯器(>gcc-4.5)為arm支持的新特性。它的原理是記錄每個(gè)函數(shù)的入棧指令(一般比APCS的入棧要少的多)到特殊的段.ARM.unwind_idx .ARM.unwind_tab。

所以如果我們要使用unwind,就必須在鏈接文件中定義這個(gè)段

.ARM.exidx : {

__exidx_start = .;

*(.ARM.exidx* .gnu.linkonce.armexidx.*)

__exidx_end = .;

}

我們也可以通過(guò)arm-none-eabi-readelf -u xxxxx.elf查看其內(nèi)容。

以上面兩個(gè)為例,set_date的函數(shù)的地址是0xc007c4a0,而set_time的函數(shù)的地址是0xc00a0fb0。

而r11也就是fp地址在unwind_tab段中,也就是位于0xc00a0fa4地址處。

回溯時(shí)根據(jù)pc值到段中得到對(duì)應(yīng)的編碼,解析這些編碼計(jì)算出lr在棧中的位置,進(jìn)而計(jì)算得到調(diào)用者的執(zhí)行地址。

一般來(lái)說(shuō),我們使用unwind優(yōu)勢(shì)比使用apcs更好,因?yàn)椴捎胊pcs時(shí),會(huì)產(chǎn)生更多的代碼指令,對(duì)性能有影響,但是使用unwind方式只會(huì)產(chǎn)生一個(gè)額外的段空間,并不會(huì)影響性能,所以大多數(shù)情況下,使用unwind更加有利。

unwind回溯的過(guò)程可以總結(jié)為三部分:

1.根據(jù)pc找到函數(shù)unwind的段內(nèi)存地址

2.根據(jù)unwind段中信息找到指令相關(guān)的編碼數(shù)據(jù)

3.根據(jù)入棧地址,分析函數(shù)上一級(jí)的棧底保存的sp和lr。

03

函數(shù)符號(hào)表

?;厮莸倪^(guò)程中,往往需要符號(hào)表來(lái)進(jìn)行操作,此時(shí)需要開(kāi)啟-mpoke-function-name這個(gè)編譯選項(xiàng)。

使用這個(gè)選項(xiàng)編譯出的二進(jìn)制程序中可以包含 C 語(yǔ)言函數(shù)名稱(chēng)的信息,以方便函數(shù)調(diào)用鏈回溯時(shí)記錄信息的可讀性。

比如在Linux中,系統(tǒng)死機(jī)后,可以打印出棧的地址和函數(shù)的名稱(chēng),根據(jù)這個(gè)進(jìn)行回溯操作就可以進(jìn)行使用了。

基本原理就是加上-mpoke-function-name后,在每段代碼段后面,都會(huì)附加一個(gè)函數(shù)的符號(hào),我們需要使用的時(shí)候,就根據(jù)函數(shù)的pc指針,然后找到相關(guān)的偏移量,之后將這個(gè)代碼段的符號(hào)獲取到了。

04

總結(jié)

對(duì)于arm32體系架構(gòu)的backtrace基本原理可以參考如上的描述,其中最核心的部分是每個(gè)函數(shù)的棧中寄存器地址指向的是上個(gè)函數(shù)的地址,所以利用這個(gè)特性,就可以一級(jí)一級(jí)的跟蹤下去,從而實(shí)現(xiàn)棧的回溯功能。這樣我們?cè)诜治龊投ㄎ粏?wèn)題的時(shí)候,就會(huì)更加的高效。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀(guān)點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
關(guān)閉