王 洋,申 彪,彭 亮,戴麗虹,武詠晗
北京航天自動(dòng)控制研究所,北京 100854
嵌入式軟件虛擬化仿真技術(shù)是通過(guò)模擬目標(biāo)機(jī)嵌入式處理器及外設(shè)指令級(jí)行為,結(jié)合軟件調(diào)試信息解析和使用技術(shù),使得軟件調(diào)試和測(cè)試擺脫對(duì)嵌入式目標(biāo)硬件設(shè)備的依賴。
通過(guò)對(duì)航天控制領(lǐng)域虛擬化仿真和程序調(diào)試相關(guān)文獻(xiàn)的檢索,發(fā)現(xiàn)文獻(xiàn)[1]基于SPARC的嵌入式處理器研究了操作系統(tǒng)的移植方法;文獻(xiàn)[2]利用數(shù)據(jù)分發(fā)服務(wù)技術(shù)構(gòu)建了數(shù)據(jù)通路,提出一種處理器之間的通訊解決方案;文獻(xiàn)[3]探索了多核虛擬處理器不同核之間的通信方式,提供了一種快速的多核同步技術(shù);與本文面向通用嵌入式處理器不同,文獻(xiàn)[4]提出了一種針對(duì)PLC(可編程邏輯控制器)這類(lèi)專(zhuān)用嵌入式軟件的斷點(diǎn)控制技術(shù)。
仿真技術(shù)和調(diào)試技術(shù)是現(xiàn)代軟件調(diào)試的重要技術(shù),通常目標(biāo)文件代碼段、數(shù)據(jù)段是仿真器的輸入,目標(biāo)文件代碼段反匯編生成匯編指令序列,仿真模型完成匯編指令的取指、翻譯、執(zhí)行以及處理器外設(shè)的仿真。調(diào)試器以目標(biāo)文件中調(diào)試信息段作為輸入,通過(guò)解析和識(shí)別源代碼中行信息、符號(hào)信息配合仿真器完成調(diào)試工作。
條件斷點(diǎn)技術(shù)是軟件調(diào)試技術(shù)的重要技術(shù)分支,通常應(yīng)用于某一種處理器架構(gòu)下的程序調(diào)試功能。與基于X86處理器和Windows操作系統(tǒng)API的程序斷點(diǎn)技術(shù)不同[5],基于軟件仿真技術(shù)的條件斷點(diǎn)運(yùn)行在嵌入式虛擬處理器上而非真實(shí)的處理器。如何實(shí)現(xiàn)面向不同編譯器、嵌入式虛擬處理器的程序條件斷點(diǎn)控制是一個(gè)重要的技術(shù)問(wèn)題,本文提出的面向多虛擬處理器的程序條件斷點(diǎn)技術(shù)支持多種編譯器、多種嵌入式處理器架構(gòu),主要?jiǎng)?chuàng)新內(nèi)容如下:
1)提出一種通用的調(diào)試信息存儲(chǔ)結(jié)構(gòu);
2)提出一種條件斷點(diǎn)控制技術(shù);
3)提出一種通用架構(gòu)條件斷點(diǎn)控制模型;
4)基于通用條件斷點(diǎn)控制模型開(kāi)發(fā)調(diào)試器DIP并完成了功能測(cè)試。
嵌入式軟件目標(biāo)文件格式的組合方式有多種,運(yùn)行嵌入式軟件的目標(biāo)處理器架構(gòu)也不同,例如CC編譯器生成目標(biāo)文件為COFF加DWARF組合,目標(biāo)處理器為DPS架構(gòu)、GCC編譯器生成目標(biāo)文件為ELF加STABS組合,目標(biāo)處理器為SPARC架構(gòu)、ARM某編譯器采用ELF加DWARF組合,目標(biāo)處理器為ARM架構(gòu)。如何構(gòu)建通用的仿真調(diào)試模型來(lái)兼容多種編譯器和多種處理器,如何構(gòu)建通用的條件斷點(diǎn)模型,實(shí)現(xiàn)不同嵌入式軟件深層次缺陷快速定位成為重要問(wèn)題,為解決上述問(wèn)題,本文提出了面向多虛擬處理器的程序條件斷點(diǎn)技術(shù)。
DWARF[6](Debug with Arbitrary Record Format)調(diào)試信息保存在目標(biāo)文件原始信息數(shù)據(jù)結(jié)構(gòu)中,該數(shù)據(jù)結(jié)構(gòu)定義如表1所示。
表1 DWARF主要節(jié)區(qū)定義
DWARF以樹(shù)狀結(jié)構(gòu)保存各個(gè)編譯單元的序言數(shù)據(jù)、符號(hào)調(diào)試信息數(shù)據(jù)、行號(hào)調(diào)試信息數(shù)據(jù)。此時(shí),全部調(diào)試信息是未經(jīng)過(guò)重新組織的,編譯單元、函數(shù)、局部變量、全局變量、數(shù)據(jù)類(lèi)型的壓縮信息分散在不同的數(shù)據(jù)結(jié)構(gòu)中。
調(diào)試信息單元DIE(Debugging Information Entry)是符號(hào)結(jié)構(gòu)信息(.debug_info)的基本單位,DIE中包括一個(gè)標(biāo)簽和多個(gè)屬性,每個(gè)DIE節(jié)點(diǎn)與它的兄弟節(jié)點(diǎn)或子節(jié)點(diǎn)連接構(gòu)成樹(shù)形結(jié)構(gòu)。假設(shè)在main.c中定義兩個(gè)函數(shù)function1和function2,function1函數(shù)中定義了變量var1。則main.c具備編譯單元標(biāo)簽以及名稱屬性、編譯路徑屬性、目標(biāo)碼覆蓋范圍等屬性,function1和function2是main.c的子節(jié)點(diǎn)且互為兄弟節(jié)點(diǎn),function1和function2具備子程序標(biāo)簽以及函數(shù)名屬性、函數(shù)起地址范圍等屬性。Var1作為function1的子節(jié)點(diǎn)具備變量標(biāo)簽、局部存儲(chǔ)屬性、變量名屬性、變量位置等屬性,因此不難發(fā)現(xiàn)main.c中的DIE構(gòu)成具有2個(gè)兄弟節(jié)點(diǎn)的3級(jí)樹(shù)形結(jié)構(gòu)。
DIE中描述的函數(shù)、全局變量、局部變量等保存的位置可能在內(nèi)存、堆棧、寄存器中。符號(hào)的位置信息(.debug_loc)保存函數(shù)的棧幀信息和全局變量的靜態(tài)位置信息、局部變量的動(dòng)態(tài)位置變化信息。
行號(hào)調(diào)試信息(.debug_line)構(gòu)建了源代碼行信息與目標(biāo)碼行信息的對(duì)應(yīng)關(guān)系,當(dāng)處理器運(yùn)行至特點(diǎn)目標(biāo)碼時(shí),用戶可以根據(jù)上述對(duì)應(yīng)關(guān)系,確定程序運(yùn)行的源碼行。
STABS[7](String Tables)調(diào)試信息中符號(hào)和行號(hào)調(diào)試信息是以條目化的數(shù)據(jù)項(xiàng)形式存在的,STABS分為符號(hào)和行號(hào)調(diào)試信息,分別用.stabs條目和.stabn條目表示。
.stabs條目包括string,type,desc和value字段,其中string表示符號(hào)名稱(例如上文中main.c,function1,function2和var1),desc表示符號(hào)屬性(例如全局、局部、靜態(tài)等屬性),value表示符號(hào)尋址方式和尋址內(nèi)容(例如內(nèi)存、堆棧偏移、寄存器等)。
.stabn條目包括type,desc,value和type表示行號(hào)類(lèi)型標(biāo)識(shí),desc標(biāo)識(shí)源代碼行,value標(biāo)識(shí)目標(biāo)碼地址或目標(biāo)碼地址序列的起始地址。
本文提出了一種如圖1所示的通用調(diào)試信息存儲(chǔ)結(jié)構(gòu),該存儲(chǔ)結(jié)構(gòu)是一種與目標(biāo)文件格式無(wú)關(guān)的結(jié)構(gòu)。存儲(chǔ)結(jié)構(gòu)中一個(gè)源程序的全部調(diào)試信息存儲(chǔ)在CModule對(duì)象中,CModule對(duì)象中實(shí)例化
一個(gè)CModuleInfo對(duì)象中保存一個(gè)編譯單元全部調(diào)試信息,包括:
1)函數(shù)信息Map
2)局部變量Map
3)全局變量Map
4)行號(hào)信息Map
5)數(shù)據(jù)類(lèi)型信息Map
6)當(dāng)前編譯單元的編號(hào)、名稱、起始PC值和結(jié)束PC值。
CFunctionInfo對(duì)象包括函數(shù)名、函數(shù)起始PC值、函數(shù)結(jié)束PC值、函數(shù)名所在的源代碼行、CSymbolX對(duì)象,該對(duì)象保存函數(shù)名對(duì)應(yīng)的符號(hào)信息,包括:
1)符號(hào)名稱;
2)符號(hào)的類(lèi)型CTypeX*;
3)符號(hào)的寄存器偏移(局部變量寄存器存儲(chǔ));
4)符號(hào)的棧幀偏移(局部變量堆棧存儲(chǔ));
5)符號(hào)的物理地址(全局變量);
6)符號(hào)的存儲(chǔ)類(lèi)型(寄存器、堆棧、內(nèi)存)。
CSymbolX*保存局部變量和全局變量的符號(hào)信息。CSymbolX對(duì)象中保存了當(dāng)前變量的類(lèi)型信息CTypeX*,CTypeX包括:
1)類(lèi)型名稱、編號(hào);
2)類(lèi)型的種類(lèi),包括基本類(lèi)型和結(jié)構(gòu)體、枚舉等多種類(lèi)型;
3)指向CTypeX*的對(duì)象,此對(duì)象非空則表示該類(lèi)型為指向其他類(lèi)型的typedef類(lèi)型;
4)類(lèi)型的屬性,包括靜態(tài)屬性、寄存器存儲(chǔ)、參數(shù)存儲(chǔ)、全局存儲(chǔ)、枚舉成員、結(jié)構(gòu)體;
5)成員、聯(lián)合體成員、函數(shù)成員等;
6)復(fù)合類(lèi)型如結(jié)構(gòu)體中各個(gè)元素的索引系數(shù),包括位索引和字節(jié)索引。
CSymbolX*的哈希表,用以保存當(dāng)前類(lèi)型下引用到得新的符號(hào)信息。
CLineInfo*保存行號(hào)調(diào)試信息,CLineInfo對(duì)象包括:
1)源代碼行;
2)當(dāng)前源代碼行對(duì)應(yīng)的目標(biāo)碼序列。
圖1 通用的調(diào)試信息存儲(chǔ)結(jié)構(gòu)
嵌入式處理器仿真技術(shù)是在宿主機(jī)上模擬目標(biāo)處理器行為,實(shí)現(xiàn)圖2所示的嵌入式軟件仿真,一般執(zhí)行過(guò)程包括:
1)反匯編器對(duì)嵌入式程序的二進(jìn)制目標(biāo)文件的代碼段進(jìn)行反匯編,生成匯編指令碼;
2)處理器仿真模型中PC控制邏輯取程序入口PC后,匯編指令執(zhí)行器開(kāi)始執(zhí)行指令周期循環(huán)(取指、譯碼、執(zhí)行);
3)仿存模型中保存程序執(zhí)行過(guò)程中的靜態(tài)內(nèi)存、堆內(nèi)存、??臻g和寄存器數(shù)據(jù);
4)斷點(diǎn)控制器注冊(cè)處理器外部回調(diào)函數(shù),回調(diào)函數(shù)處理?xiàng)l件斷點(diǎn)事件。
圖2 虛擬處理器仿真行為模型
在虛擬處理器架構(gòu)下,實(shí)現(xiàn)條件斷點(diǎn)方式如圖2中程序所示,假設(shè)條件斷點(diǎn)的觸發(fā)條件是structX.stFoo.iBar==5,觸發(fā)位置為圖3中第13行。實(shí)現(xiàn)條件斷點(diǎn)的控制過(guò)程則如下:
首先,需要對(duì)表達(dá)式進(jìn)行詞法和語(yǔ)法分析。本文利用Flex&bsion構(gòu)建語(yǔ)法樹(shù),語(yǔ)法樹(shù)葉子節(jié)點(diǎn)為iBar,iBar的父節(jié)點(diǎn)為stFoo,stFoo的父節(jié)點(diǎn)為structX;
圖3 條件斷點(diǎn)程序偽代碼
其次,通用的調(diào)試信息存儲(chǔ)結(jié)構(gòu)CSymbolX*中保存有structX.stFoo.iBar數(shù)據(jù)結(jié)構(gòu)信息, CTypeX*保存有structX和stFoo的結(jié)構(gòu)體類(lèi)型信息,通過(guò)尋址解析邏輯可以獲取iBar的地址;
最后,行號(hào)調(diào)試信息CLineInfo中存有語(yǔ)句structX.stFoo.iBar==i表達(dá)式所在圖3所示的源碼行(13行)和該語(yǔ)句對(duì)應(yīng)目標(biāo)碼的PC,當(dāng)處理器模型判斷當(dāng)前處理器的PC與structX.stFoo.iBar==i行所處PC相同時(shí),斷點(diǎn)控制器觸發(fā)函數(shù)回調(diào):
1)斷點(diǎn)控制器通過(guò)iBar地址查詢當(dāng)前的iBar值,將iBar值傳入回調(diào)函數(shù);
2)回調(diào)函數(shù)判斷iBar值是否等于5,如果等于5則處理器PC保持,程序暫停;如果不等于5則程序PC增加后繼續(xù)運(yùn)行。
利用圖4所示的條件斷點(diǎn)控制技術(shù),可以構(gòu)建圖5所示的通用條件斷點(diǎn)控制模型,該模型包括4個(gè)主要部分:
圖4 條件斷點(diǎn)控制原理圖
圖5 通用條件斷點(diǎn)控制模型
第1部分,調(diào)試信息解析邏輯和通用調(diào)試信息存儲(chǔ)模型,調(diào)試信息解析邏輯支持對(duì)不同編譯器的調(diào)試信息格式解析,解析格式包括ELF、COFF、Stab、DWARF-v2、DWARF-v3、DWARF-v4以及自定義的調(diào)試信息格式,通用調(diào)試信息存儲(chǔ)模型中保存統(tǒng)一的調(diào)試信息,通用調(diào)試信息包含行號(hào)信息、符號(hào)信息[8]。
第2部分,模塊化的虛擬處理器模型和通用的條件斷點(diǎn)控制接口,通用的條件斷點(diǎn)控制接口適配不同處理器,接口中統(tǒng)一處理來(lái)自FLEX&BISON注冊(cè)的回調(diào)函數(shù),處理過(guò)程如圖6所示。
圖6 調(diào)試器DIP架構(gòu)圖
第3部分,FLEX&BISON引擎,引擎具備3個(gè)主要功能:
1)FLEX&BISON引擎將條件斷點(diǎn)表達(dá)式解析為符號(hào)樹(shù),符號(hào)樹(shù)種全部變量的地址和類(lèi)型等信息通過(guò)查詢通用調(diào)試信息存儲(chǔ)結(jié)構(gòu)獲取;
2)FLEX&BISON引擎解析條件表達(dá)式,以函數(shù)回調(diào)的形式,注冊(cè)在通用斷點(diǎn)控制接口中,滿足斷點(diǎn)表達(dá)式條件時(shí),虛擬處理器暫停運(yùn)行;
3)FLEX&BISON引擎收到虛擬處理器暫停運(yùn)行消息后,通知前端調(diào)試器暫停在條件斷點(diǎn)所在的源碼行。
第4部分,前端調(diào)試器。前端調(diào)試器用于顯示條件斷點(diǎn),顯示當(dāng)前調(diào)試的源代碼等。
基于通用架構(gòu)條件斷點(diǎn)控制模型開(kāi)發(fā)了調(diào)試DIP,軟件實(shí)現(xiàn)架構(gòu)如圖6所示[9]。
調(diào)試器實(shí)現(xiàn)了對(duì)DWARF和STABS調(diào)試信息的解析,支持通用的調(diào)試信息存儲(chǔ)格式,支持SPARC、DPS、ARM的處理器的仿真,支持前端用戶界面,實(shí)現(xiàn)面向多編譯器和多處理器的條件斷點(diǎn)控制。
為了考核條件斷點(diǎn)調(diào)試解析功能的正確性、多編譯器和虛擬處理器兼容能力,在表2所示的硬件場(chǎng)景進(jìn)行了測(cè)試。
表2 測(cè)試平臺(tái)硬件指標(biāo)
考核7項(xiàng)內(nèi)容,設(shè)計(jì)功能測(cè)試用例1203個(gè),詳細(xì)考核情況如表3所示。
表3 條件斷點(diǎn)支持情況
例如針對(duì)通用條件斷點(diǎn)處理功能,如表4所示,測(cè)試用例考核了等于、大于、小于條件判斷,考核結(jié)構(gòu)體、聯(lián)合體成員的符號(hào)判斷邏輯,考核程序特定語(yǔ)句命中次數(shù)的判斷邏輯,通過(guò)條件斷點(diǎn)功能發(fā)現(xiàn)了多個(gè)載人航天型號(hào)控制系統(tǒng)嵌入式軟件問(wèn)題。
表4 通用條件斷點(diǎn)處理邏輯支持情況
隨著航天領(lǐng)域嵌入式軟件種類(lèi)和復(fù)雜度增加,調(diào)試器從面向單一編譯器發(fā)展為面向多編譯器架構(gòu),為滿足航天領(lǐng)域多種類(lèi)型嵌入式軟件的研發(fā)和測(cè)試需求,提出了一種通用的調(diào)試信息存儲(chǔ)結(jié)構(gòu)、一種條件斷點(diǎn)控制技術(shù)和一種通用架構(gòu)條件斷點(diǎn)控制模型,基于通用架構(gòu)條件斷點(diǎn)控制模型開(kāi)發(fā)了調(diào)試器DIP,將條件斷點(diǎn)技術(shù)應(yīng)用于載人航天、探月工程等多個(gè)核心關(guān)鍵嵌入式軟件測(cè)試中。通過(guò)使用通用的條件斷點(diǎn)功能,更容易發(fā)現(xiàn)不同嵌入式軟件中的深層軟件問(wèn)題,在未來(lái),以上技術(shù)將在更多航天型號(hào)嵌入式軟件測(cè)試中得到驗(yàn)證和應(yīng)用。