解析基于ELF的嵌入式軟件源碼級(jí)交叉調(diào)試技術(shù)
三、源碼級(jí)交叉調(diào)試器實(shí)現(xiàn)的技術(shù)要點(diǎn)
在設(shè)計(jì)交叉調(diào)試器JDBG時(shí),首先完成與目標(biāo)文件無關(guān)的部分:連接目標(biāo)機(jī),查看修改目標(biāo)機(jī)寄存器和內(nèi)存;然后實(shí)現(xiàn)與目標(biāo)文件有關(guān)的部分:下載目標(biāo)文件到目標(biāo)機(jī),源碼級(jí)調(diào)試功能,包括斷點(diǎn)控制、執(zhí)行控制、變量觀察等,以下重點(diǎn)討論各項(xiàng)功能的設(shè)計(jì)與實(shí)現(xiàn)。
1、 下載目標(biāo)文件
目標(biāo)文件中包含多種類型的內(nèi)容,目標(biāo)程序在目標(biāo)機(jī)上運(yùn)行時(shí)只需要程序的二進(jìn)制指令代碼與相關(guān)數(shù)據(jù),這些內(nèi)容包含在文件中的可執(zhí)行程序段中。下載目標(biāo)文件時(shí)在宿主機(jī)上提取目標(biāo)文件中的代碼與數(shù)據(jù)段,根據(jù)其地址映射關(guān)系利用remote協(xié)議中寫內(nèi)存的功能在目標(biāo)機(jī)上建立程序的遠(yuǎn)程映像。
2、 斷點(diǎn)
斷點(diǎn)是調(diào)試器控制程序執(zhí)行的基本手段。各種機(jī)器有其特殊的斷點(diǎn)指令(如X86的int3指令),設(shè)置斷點(diǎn)就是將機(jī)器斷點(diǎn)指令替換所指定程序單元中的指令,使得程序運(yùn)行到斷點(diǎn)指令處時(shí),產(chǎn)生“斷點(diǎn)異常”,用戶程序不再繼續(xù)執(zhí)行下去,目標(biāo)機(jī)向宿主機(jī)返回?cái)帱c(diǎn)停止信號(hào),由宿主機(jī)調(diào)試器接管對(duì)用戶程序的控制。
斷點(diǎn)分為邏輯斷點(diǎn)與物理斷點(diǎn),兩者是多對(duì)一的關(guān)系。邏輯斷點(diǎn)與源代碼對(duì)應(yīng),提供源級(jí)斷點(diǎn)信息(源文件名+行號(hào)或物理地址等);物理斷點(diǎn)與目標(biāo)碼對(duì)應(yīng),提供斷點(diǎn)的目標(biāo)碼地址及斷點(diǎn)處的指令內(nèi)容。插入一個(gè)斷點(diǎn)即根據(jù)邏輯斷點(diǎn)信息確定物理斷點(diǎn)地址,將該地址對(duì)應(yīng)指令用機(jī)器斷點(diǎn)指令替代;刪除斷點(diǎn)即恢復(fù)斷點(diǎn)指令處預(yù)先保存的原指令,使得程序可繼續(xù)執(zhí)行。
檢查點(diǎn)是一種條件斷點(diǎn),使程序在條件滿足時(shí)停止執(zhí)行。通常條件都涉及表達(dá)式的值變化,利用寫內(nèi)存保護(hù)來檢查表達(dá)式的值是最常用的方法,但這種方法不適用于不具備MMU功能的處理器。某些處理器(如i386)提供了專門的調(diào)試控制寄存器,通過在調(diào)試控制寄存器中設(shè)置相應(yīng)線性地址及中止條件(讀或?qū)?即可中止程序的運(yùn)行。通過查詢方式檢查表達(dá)式的值也是一種可行的方法,其效率相對(duì)較低。當(dāng)檢查點(diǎn)的條件滿足時(shí),檢查點(diǎn)的操作與普通斷點(diǎn)類似。
對(duì)一個(gè)斷點(diǎn)應(yīng)具有基本的插入、刪除、使能、使不能等基本操作功能。在設(shè)計(jì)中采用雙向鏈表結(jié)構(gòu)作為斷點(diǎn)的數(shù)據(jù)結(jié)構(gòu),使得斷點(diǎn)控制更加方便高效。
3、 啟動(dòng)程序運(yùn)行
啟動(dòng)程序運(yùn)行首先從目標(biāo)文件的ELF頭中得到應(yīng)用程序的入口,將目標(biāo)機(jī)的PC寄存器置為該入口地址,從入口處開始執(zhí)行程序指令。如果程序中沒有設(shè)置任何斷點(diǎn)或檢查點(diǎn),則程序一直運(yùn)行到結(jié)束;如果程序中有斷點(diǎn),則程序運(yùn)行到第一個(gè)斷點(diǎn)處停止并返回其停止位置。
4、 源碼級(jí)單步調(diào)試
源碼級(jí)單步以行為單位,一行源代碼對(duì)應(yīng)多條機(jī)器指令,因此一個(gè)源語句的單步執(zhí)行需要多個(gè)機(jī)器指令的單步執(zhí)行。最簡單的實(shí)現(xiàn)方法就是從源語句對(duì)應(yīng)目標(biāo)代碼的起始地址開始逐條單步執(zhí)行機(jī)器指令。顯然這種方法效率很低,尤其調(diào)試嵌入式軟件需要大量宿主機(jī)/目標(biāo)機(jī)間的通訊,而且有的處理器自身并不提供機(jī)器單步執(zhí)行指令。因此,更有效的方法是用“內(nèi)部臨時(shí)斷點(diǎn)+連續(xù)執(zhí)行”的方式來實(shí)現(xiàn)。
用機(jī)器單步執(zhí)行時(shí),每執(zhí)行完一條機(jī)器指令立即讀取當(dāng)前PC,判斷程序停止位置。調(diào)試器對(duì)程序的控制是即時(shí)交互的,當(dāng)單步執(zhí)行結(jié)束、跳轉(zhuǎn)或進(jìn)入函數(shù)調(diào)用時(shí),調(diào)試器都會(huì)即時(shí)得知。不采用機(jī)器單步,則不具有這種即時(shí)掌握程序運(yùn)行狀態(tài)的便利,需要在運(yùn)行前反匯編目標(biāo)代碼,通過分析匯編指令預(yù)測程序單步執(zhí)行可能的出口位置,并在該處設(shè)上斷點(diǎn)??赡艿某隹谖恢冒ㄔ撔兄噶畹慕K止地址、跳轉(zhuǎn)、分枝跳轉(zhuǎn)、函數(shù)調(diào)用等指令。對(duì)于跳轉(zhuǎn)指令,能得到絕對(duì)地址則直接在跳轉(zhuǎn)地址處設(shè)斷點(diǎn),不能得到跳轉(zhuǎn)地址則在指令處設(shè)斷點(diǎn),再執(zhí)行跳轉(zhuǎn)指令由當(dāng)前PC值確定程序停止的位置。對(duì)于函數(shù)調(diào)用指令,如果采用單步跳過(stepover)方式,則將其作為普通指令看待,直接執(zhí)行調(diào)用函數(shù);如果采用單步進(jìn)入(stepinto)方式,則需在指令處設(shè)斷點(diǎn),再執(zhí)行調(diào)用指令,以進(jìn)入函數(shù)內(nèi)部讓用戶繼續(xù)跟蹤程序的執(zhí)行。
以單步跳出方式(stepout)執(zhí)行程序時(shí),以子程序?yàn)閱挝?,需?zhí)行完當(dāng)前子程序的所有代碼,在調(diào)用該子程序的下一條語句處停止。通過反匯編當(dāng)前子程序的所有指令,可得到該子程序所有可能的函數(shù)返回出口,在這些函數(shù)返回指令處設(shè)臨時(shí)斷點(diǎn),程序運(yùn)行到斷點(diǎn)處再執(zhí)行該返回指令跳出當(dāng)前子程序,處理調(diào)用該子程序的語句行的后繼信息,最終確定程序停止位置。
5、數(shù)據(jù)瀏覽
數(shù)據(jù)與指令同樣是構(gòu)成程序的根本。數(shù)據(jù)類型繁多,不同的類型處理起來有所不同,其基本原理是由數(shù)據(jù)名找到存放該數(shù)據(jù)的地址,再從地址中取出數(shù)據(jù)的值。關(guān)鍵在于找到名與地址的映射關(guān)系。這些信息可從.debug,.symtab等節(jié)中得到。全局變量一般可得到直接的地址信息,而局部變量采用堆棧方式存放在內(nèi)存中,需根據(jù)從.debug中得到的該變量在堆棧中的位置信息來確定地址。采用表結(jié)構(gòu)來管理變量,將每個(gè)變量的名、地址等信息登記在表中,將對(duì)數(shù)據(jù)值的操作轉(zhuǎn)化為對(duì)相應(yīng)地址的內(nèi)存單元操作,如查看變量即為讀取該變量所在內(nèi)存單元的內(nèi)容。
四、交叉調(diào)試器JDBG簡述
JDBG采用圖形用戶界面,相應(yīng)的命令提供圖形按鈕或菜單,并提供快捷鍵。進(jìn)入調(diào)試之前,先連接目標(biāo)機(jī),在連接時(shí)設(shè)置連接參數(shù)并保存,在以后的連接中可直接使用已保存的設(shè)置參數(shù)。當(dāng)宿主機(jī)/目標(biāo)機(jī)處于連接狀態(tài)時(shí),下載目標(biāo)文件,啟動(dòng)調(diào)試器。調(diào)試器啟動(dòng)后,用戶可在打開的源文件中設(shè)置斷點(diǎn),運(yùn)行下載的目標(biāo)程序,查看/修改寄存器、內(nèi)存的內(nèi)容。當(dāng)運(yùn)行的目標(biāo)程序停止后,返回停止點(diǎn)源碼信息,用戶可以觀察數(shù)據(jù),添加新的斷點(diǎn)或刪除已設(shè)斷點(diǎn),控制程序的單步執(zhí)行或連續(xù)執(zhí)行,或退出調(diào)試狀態(tài)。
linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)
評(píng)論