林廣棟,黃光紅,耿銳
(中國(guó)電子科技集團(tuán)公司 第三十八研究所,合肥230088)
本文提出的方案充分考慮了C語(yǔ)言單步調(diào)試需要面臨的問(wèn)題,可以實(shí)現(xiàn)任意復(fù)雜程序的C語(yǔ)言代碼行的單步調(diào)試功能。方案原理簡(jiǎn)單,容易理解,并經(jīng)過(guò)大量BWDSP芯片調(diào)試過(guò)程的檢驗(yàn),已經(jīng)證明了其正確性。
單步調(diào)試是指以源代碼行為單位對(duì)被調(diào)試程序的運(yùn)行進(jìn)行控制的調(diào)試功能。單步調(diào)試不需要用戶(hù)顯式地設(shè)置斷點(diǎn),可以控制程序運(yùn)行一個(gè)或若干個(gè)代碼行。通過(guò)這種方式,用戶(hù)可以結(jié)合變量查看、堆棧查看、觀察點(diǎn)等調(diào)試功能,把潛在的程序錯(cuò)誤定位至某個(gè)代碼行。
單步調(diào)試功能一般分為兩大類(lèi):匯編級(jí)單步調(diào)試功能和源代碼級(jí)單步調(diào)試功能。匯編級(jí)單步調(diào)試功能指單步調(diào)試控制運(yùn)行的單位是匯編語(yǔ)言的代碼行。源代碼級(jí)單步調(diào)試指單步調(diào)試控制運(yùn)行的單位是高級(jí)語(yǔ)言源代碼中的代碼行。每類(lèi)單步調(diào)試功能一般又包括三種:跳入、跳過(guò)、跳出。
對(duì)于匯編級(jí)單步調(diào)試,3種單步調(diào)試功能的實(shí)現(xiàn)較為簡(jiǎn)單,其功能概述如下:
①跳入調(diào)試功能控制被調(diào)試程序運(yùn)行至當(dāng)前代碼行中調(diào)用的函數(shù)內(nèi)部。若當(dāng)前代碼行中無(wú)函數(shù)調(diào)用,則控制被調(diào)試程序運(yùn)行完當(dāng)前代碼行。
②跳過(guò)調(diào)試功能控制被調(diào)試程序運(yùn)行完當(dāng)前代碼行。若當(dāng)前代碼行中有函數(shù)調(diào)用,則控制被調(diào)試程序執(zhí)行完該函數(shù)調(diào)用并繼續(xù)運(yùn)行完當(dāng)前代碼行。
③跳出調(diào)試功能控制被調(diào)試程序運(yùn)行至當(dāng)前函數(shù)的返回地址處。
對(duì)于高級(jí)語(yǔ)言(如C語(yǔ)言),其3種單步調(diào)試功能從總體概念上與匯編級(jí)單步調(diào)試功能類(lèi)似。但由于C語(yǔ)言一行代碼經(jīng)編譯后生成一段匯編指令,且一行代碼中的語(yǔ)句可能非常復(fù)雜,其單步調(diào)試功能相對(duì)于匯編級(jí)單步調(diào)試更為復(fù)雜。C語(yǔ)言單步調(diào)試功能的實(shí)現(xiàn)要面對(duì)的問(wèn)題略——編者注。
目前,單步調(diào)試功能的實(shí)現(xiàn)方案分為兩大類(lèi):一類(lèi)通過(guò)不斷控制程序流按匯編指令行逐行執(zhí)行,進(jìn)行匯編級(jí)單步執(zhí)行,每執(zhí)行一行匯編代碼就控制被調(diào)試程序停下來(lái),分析程序地址,根據(jù)當(dāng)前程序地址判斷單步調(diào)試功能是否完成;另一類(lèi)通過(guò)反匯編當(dāng)前源代碼行生成的匯編程序段,尋找其中的函數(shù)調(diào)用、出口地址,在這些位置設(shè)置臨時(shí)斷點(diǎn)。
第一種方案的優(yōu)點(diǎn)是實(shí)現(xiàn)簡(jiǎn)單,容易理解。但是,若源代碼行中的代碼很復(fù)雜,生成的匯編程序段內(nèi)容很多,使用第一種方案將使程序反復(fù)處于運(yùn)行和停止?fàn)顟B(tài),調(diào)試效率不高。本文介紹的單步調(diào)試功能實(shí)現(xiàn)方法屬于第二類(lèi)方案。
國(guó)內(nèi)已經(jīng)有少數(shù)研究機(jī)構(gòu)開(kāi)展單步調(diào)試功能的研究,但這些研究并未能完全解決C語(yǔ)言單步調(diào)試功能面臨的所有問(wèn)題。參考文獻(xiàn)[4-5]按第一種方案實(shí)現(xiàn)了一款調(diào)試器的單步調(diào)試功能,顯然這種實(shí)現(xiàn)方式具有不可避免的通信負(fù)擔(dān)。參考文獻(xiàn)[6]實(shí)現(xiàn)了一款基于串口通信的嵌入式調(diào)試系統(tǒng),其單步調(diào)試功能也是基于第一種方案。參考文獻(xiàn)[7]較為完整地介紹了一款調(diào)試器中單步調(diào)試功能的實(shí)現(xiàn),其實(shí)現(xiàn)方案屬于第二類(lèi)方案,基本完成了C語(yǔ)言調(diào)試的主要功能。但該項(xiàng)工作并未考慮到C語(yǔ)言中單步調(diào)試功能的復(fù)雜性,若被調(diào)試代碼中包含較為復(fù)雜的代碼,該款調(diào)試器的單步調(diào)試功能將不能正確完成。
BWDSP芯片調(diào)試系統(tǒng)軟件在充分調(diào)研了國(guó)內(nèi)外前人工作的基礎(chǔ)上,參考已經(jīng)成功實(shí)現(xiàn)的方案,自主實(shí)現(xiàn)了C語(yǔ)言單步調(diào)試功能。BWDSP芯片配套調(diào)試系統(tǒng)軟件的單步調(diào)試功能基于在代碼行出口處設(shè)置臨時(shí)斷點(diǎn)的方案實(shí)現(xiàn)。與國(guó)內(nèi)外已有工作相比,該方案充分考慮了C語(yǔ)言代碼行中的代碼復(fù)雜性,可以解決很多問(wèn)題。
BWDSP芯片配套調(diào)試系統(tǒng)把一行C語(yǔ)言代碼行的出口分為如下幾類(lèi):
①通過(guò)for、while循環(huán)、break、continue語(yǔ)句跳轉(zhuǎn)至其他代碼行,該類(lèi)出口稱(chēng)為L(zhǎng)(Label)類(lèi)出口,其出口地址集記為L(zhǎng)。C語(yǔ)言中的這些跳轉(zhuǎn)指令最終編碼為BWDSP芯片指令集中的跳轉(zhuǎn)指令。BWDSP芯片指令集中的跳轉(zhuǎn)指令分為4類(lèi):
(a)條件跳轉(zhuǎn)。跳轉(zhuǎn)有可能發(fā)生,也可能不發(fā)生,根據(jù)運(yùn)行時(shí)的計(jì)算結(jié)果或寄存器值確定。
(b)絕對(duì)跳轉(zhuǎn)。跳轉(zhuǎn)一定會(huì)發(fā)生,跳轉(zhuǎn)目的地址在指令機(jī)器碼中編碼。
(c)相對(duì)跳轉(zhuǎn)。跳轉(zhuǎn)一定會(huì)發(fā)生,跳轉(zhuǎn)目的地址是當(dāng)前地址加上一個(gè)偏移。
(d)寄存器跳轉(zhuǎn)。跳轉(zhuǎn)一定會(huì)發(fā)生,跳轉(zhuǎn)目的地址是某個(gè)寄存器中的值,不能從可執(zhí)行文件程序段獲取。
對(duì)于前面3類(lèi)跳轉(zhuǎn),其目的地址可以從程序段反匯編得到。而對(duì)第4類(lèi)跳轉(zhuǎn),其目的地址不能從程序段得到,需要在運(yùn)行時(shí)從某個(gè)寄存器中讀取。
②通過(guò)函數(shù)調(diào)用跳轉(zhuǎn)至其他行,這類(lèi)出口稱(chēng)為F(Function)類(lèi)出口,這些函數(shù)的入口地址集記為F。C語(yǔ)言中的函數(shù)調(diào)用最終被編碼為BWDSP芯片指令集中的函數(shù)調(diào)用指令。BWDSP指令集中的函數(shù)調(diào)用指令分為兩類(lèi):
(a)絕對(duì)地址函數(shù)調(diào)用。函數(shù)調(diào)用的入口地址編碼在指令中,可以從程序段得到。
(b)寄存器函數(shù)調(diào)用。函數(shù)調(diào)用的入口地址是調(diào)用時(shí)某個(gè)寄存器中的值。
一般,直接調(diào)用C語(yǔ)言中的函數(shù)會(huì)編譯為第一類(lèi)函數(shù)調(diào)用指令;通過(guò)函數(shù)指針調(diào)用函數(shù)會(huì)編譯為第二類(lèi)函數(shù)調(diào)用指令。同樣,第一類(lèi)函數(shù)調(diào)用的入口地址可以通過(guò)反匯編程序段得到,而第二類(lèi)函數(shù)調(diào)用的入口地址只能在運(yùn)行時(shí)讀取某個(gè)寄存器中的值獲得。
③通過(guò)return語(yǔ)句跳轉(zhuǎn)至本幀的返回地址,這類(lèi)出口稱(chēng)為R(Return)類(lèi)出口,返回地址記為R。一個(gè)函數(shù)可能有多個(gè)retrun語(yǔ)句,一行C語(yǔ)言代碼中也可能有多處函數(shù)返回。但由于程序流一定處于函數(shù)調(diào)用棧中的棧頂,該函數(shù)返回后肯定返回至上一幀的現(xiàn)場(chǎng),所以當(dāng)前PC所處的函數(shù)中的多處return語(yǔ)句其實(shí)返回到同一個(gè)地址。而且,由于函數(shù)可能在多處被調(diào)用,所以該返回地址不能通過(guò)反匯編程序段獲得,只能通過(guò)運(yùn)行時(shí)函數(shù)調(diào)用棧獲得。
④直接運(yùn)行完本行代碼來(lái)到的程序地址,這類(lèi)出口稱(chēng)為N(Next),其出口地址記為N。程序運(yùn)行完當(dāng)前行后,會(huì)自然地運(yùn)行下一行的指令,因此下一行指令的開(kāi)始地址也是本行代碼的一個(gè)出口地址。對(duì)于部分C語(yǔ)言代碼行,并沒(méi)有下一行出口地址。例如,若一個(gè)代碼行是一函數(shù)的最后一行,若執(zhí)行該行代碼時(shí),或者跳轉(zhuǎn)至其他行,或返回調(diào)用函數(shù),肯定不會(huì)進(jìn)入下一行代碼執(zhí)行。所以,本類(lèi)出口可能存在,也可能不存在。
在將一行C語(yǔ)言代碼行的出口分為以上4類(lèi)的基礎(chǔ)上,BWDSP調(diào)試系統(tǒng)通過(guò)在這些出口上設(shè)置臨時(shí)斷點(diǎn)實(shí)現(xiàn)單步調(diào)試功能。設(shè)置的臨時(shí)斷點(diǎn)位置不同,實(shí)現(xiàn)的單步調(diào)試功能也不同。對(duì)有些特殊的出口,除了設(shè)置臨時(shí)斷點(diǎn),還要做一些特殊處理。
跳出是實(shí)現(xiàn)方式最簡(jiǎn)單的單步調(diào)試功能,其功能是跳出當(dāng)前函數(shù),來(lái)到其返回地址處。由于一個(gè)函數(shù)在運(yùn)行時(shí)返回地址只有一個(gè),即R,所以只需要在R處設(shè)置一個(gè)臨時(shí)斷點(diǎn),然后讓被調(diào)試程序正常運(yùn)行即可。當(dāng)程序遇到斷點(diǎn)停下時(shí),若該斷點(diǎn)為用戶(hù)設(shè)置的斷點(diǎn),說(shuō)明單步調(diào)試過(guò)程中用戶(hù)斷點(diǎn)被觸發(fā),跳出單步調(diào)試結(jié)束。若該斷點(diǎn)為臨時(shí)斷點(diǎn)R,說(shuō)明跳出功能正常實(shí)現(xiàn),單步調(diào)試結(jié)束。若當(dāng)前函數(shù)是main函數(shù),則函數(shù)棧中只有一幀,無(wú)需設(shè)置臨時(shí)斷點(diǎn),直接運(yùn)行即可。
跳出單步調(diào)試功能的實(shí)現(xiàn)方案流程如圖1所示。
圖1 跳出單步調(diào)試功能實(shí)現(xiàn)流程圖
跳過(guò)功能使程序執(zhí)行完當(dāng)前代碼行。若本代碼行中有函數(shù)調(diào)用,則執(zhí)行完該函數(shù),并返回本代碼行繼續(xù)運(yùn)行,直至程序自然地跳出該代碼行為止。所以,跳過(guò)單步調(diào)試功能應(yīng)在L、N類(lèi)出口設(shè)置臨時(shí)斷點(diǎn)。
一般,C語(yǔ)言程序在進(jìn)入函數(shù)和跳出函數(shù)時(shí)會(huì)有一小段代碼用來(lái)進(jìn)行函數(shù)棧入棧和出棧的操作。這一小段代碼在調(diào)試信息中一般與源代碼中函數(shù)開(kāi)始和結(jié)束時(shí)的正反大括號(hào)對(duì)應(yīng)。單步調(diào)試時(shí),若代碼行中有return語(yǔ)句,該語(yǔ)句實(shí)際上被編譯為一個(gè)跳轉(zhuǎn)語(yǔ)句,跳轉(zhuǎn)至函數(shù)結(jié)尾的大括號(hào)處,并不會(huì)真正返回上一層調(diào)用函數(shù)。若代碼行中有函數(shù)結(jié)束時(shí)的大括號(hào),則程序在該代碼行中真正有可能返回調(diào)用函數(shù)。返回上一層調(diào)用函數(shù)的指令在BWDSP指令集中被編碼為RET指令,因此可以通過(guò)檢查代碼行中是否有RET指令判斷該代碼行是否有可能返回調(diào)用函數(shù)。若代碼行中有RET指令,還要在R類(lèi)出口處設(shè)置斷點(diǎn)。
程序PC即使在一行代碼中間某個(gè)位置,也有可能跳回到該行代碼的開(kāi)始位置繼續(xù)執(zhí)行。設(shè)置臨時(shí)斷點(diǎn)時(shí),需要在該行代碼中的全部L類(lèi)出口處都設(shè)置斷點(diǎn),不管該跳轉(zhuǎn)指令是在當(dāng)前PC之前,還是之后。
對(duì)于L類(lèi)出口中的第一類(lèi)跳轉(zhuǎn)(條件跳轉(zhuǎn))出口,不論該跳轉(zhuǎn)是否會(huì)發(fā)生,都在該出口處設(shè)置臨時(shí)斷點(diǎn)。若程序執(zhí)行了該條件跳轉(zhuǎn),本方案可以使跳過(guò)單步調(diào)試功能正常結(jié)束。若程序沒(méi)有執(zhí)行該條件跳轉(zhuǎn),設(shè)置的該臨時(shí)斷點(diǎn)也不會(huì)對(duì)單步調(diào)試功能產(chǎn)生影響。
對(duì)于L類(lèi)出口中的第4類(lèi)跳轉(zhuǎn)(寄存器跳轉(zhuǎn)),其出口地址不能在運(yùn)行之前獲得,因此也不能在出口處設(shè)置臨時(shí)斷點(diǎn)。對(duì)于這類(lèi)跳轉(zhuǎn),需要在其跳轉(zhuǎn)指令處設(shè)置臨時(shí)斷點(diǎn),若該臨時(shí)斷點(diǎn)觸發(fā),則讀取其跳轉(zhuǎn)目的地址寄存器的值。若讀到的跳轉(zhuǎn)目的地址在本行代碼中,則保留所有已經(jīng)設(shè)置的臨時(shí)斷點(diǎn),繼續(xù)運(yùn)行程序。若該跳轉(zhuǎn)的目的地址不在本行代碼中,則控制程序進(jìn)行一次匯編級(jí)指令行單步以執(zhí)行該跳轉(zhuǎn),然后結(jié)束本次單步調(diào)試過(guò)程。
由于本方案沒(méi)有在函數(shù)調(diào)用出口處設(shè)置斷點(diǎn),若源代碼行中有多個(gè)函數(shù)調(diào)用,則這些函數(shù)調(diào)用會(huì)依次執(zhí)行,不會(huì)觸發(fā)斷點(diǎn)。
被調(diào)試程序觸發(fā)以上設(shè)置的臨時(shí)斷點(diǎn)中的任意一個(gè),都意味著單步跳過(guò)調(diào)試過(guò)程的結(jié)束。所以,只要臨時(shí)斷點(diǎn)位置是代碼行的合法可能出口,設(shè)置多個(gè)臨時(shí)斷點(diǎn)就不會(huì)對(duì)單步調(diào)試功能的正確性產(chǎn)生影響。
本方案解決了第1節(jié)中介紹的第1、2、3、4、5、7、8、9問(wèn)題,而第6個(gè)問(wèn)題不會(huì)對(duì)跳過(guò)單步調(diào)試功能產(chǎn)生影響。跳過(guò)單步調(diào)試的實(shí)現(xiàn)方案流程如圖2所示。
跳入調(diào)試功能使程序可以進(jìn)入代碼行中調(diào)用的函數(shù)內(nèi)部。若程序在當(dāng)前代碼行中的執(zhí)行過(guò)程中沒(méi)有遇到函數(shù)調(diào)用,則執(zhí)行完本代碼行即完成單步調(diào)試功能,此時(shí)其調(diào)試功能與跳過(guò)單步調(diào)試類(lèi)似。顯然,實(shí)現(xiàn)單步跳入調(diào)試功能需要在L、F、R、N處都設(shè)置臨時(shí)斷點(diǎn)。
對(duì)于F類(lèi)出口中的第二類(lèi)函數(shù)調(diào)用(寄存器函數(shù)調(diào)用),同樣需要在函數(shù)調(diào)用指令處設(shè)置臨時(shí)斷點(diǎn)。當(dāng)該臨時(shí)斷點(diǎn)觸發(fā)時(shí),控制程序進(jìn)行一次匯編級(jí)指令行單步,使程序進(jìn)入調(diào)用函數(shù)。
由于本方案在所有函數(shù)調(diào)用處都設(shè)置了斷點(diǎn),所以程序會(huì)停止在執(zhí)行過(guò)程中的第一個(gè)函數(shù)調(diào)用出口。調(diào)試行為表現(xiàn)為程序會(huì)跳入執(zhí)行過(guò)程中遇到的第一個(gè)函數(shù)。
第1節(jié)中介紹的所有問(wèn)題都對(duì)跳入單步調(diào)試功能有影響,而本方案可以解決所有9個(gè)問(wèn)題。跳入調(diào)試功能的實(shí)現(xiàn)流程如圖3所示。
圖2 跳過(guò)單步調(diào)試功能實(shí)現(xiàn)流程圖
BWDSP芯片配套調(diào)試系統(tǒng)的C語(yǔ)言單步調(diào)試功能按照本文介紹的方案實(shí)施。開(kāi)發(fā)人員以任意復(fù)雜的C語(yǔ)言代碼行在各種復(fù)雜的調(diào)試場(chǎng)景下對(duì)單步調(diào)試功能進(jìn)行測(cè)試,調(diào)試系統(tǒng)均可按單步調(diào)試預(yù)定義的功能完成調(diào)試過(guò)程。目前,在BWDSP芯片的模擬器、編譯器、操作系統(tǒng)開(kāi)發(fā)過(guò)程中,均已經(jīng)在項(xiàng)目組內(nèi)部試用本調(diào)試器進(jìn)行C語(yǔ)言級(jí)調(diào)試。
經(jīng)過(guò)反復(fù)測(cè)試、試用、修改,本方案已經(jīng)證實(shí)是一個(gè)理想的實(shí)施方案,可以實(shí)現(xiàn)任意復(fù)雜C語(yǔ)言代碼行的單步調(diào)試功能。
本文介紹了BWDSP芯片調(diào)試系統(tǒng)中C語(yǔ)言單步調(diào)試功能的實(shí)現(xiàn)方案。該方案充分研究了C語(yǔ)言一行源代碼中可能對(duì)單步調(diào)試功能產(chǎn)生影響的各種情況,充分考慮了C語(yǔ)言代碼行的復(fù)雜性,可以實(shí)現(xiàn)任意復(fù)雜C語(yǔ)言代碼行的單步調(diào)試功能。經(jīng)BWDSP芯片調(diào)試過(guò)程的驗(yàn)證,證實(shí)了本方案的有效性。
圖3 跳入單步調(diào)試功能實(shí)現(xiàn)流程圖
編者注:本文為期刊縮略版,全文見(jiàn)本刊網(wǎng)站www.mesnet.com.cn。
[1]黃光紅,劉冠南.可配置多核處理器的調(diào)試器模塊化分層設(shè)計(jì)[J].單片機(jī)與嵌入式系統(tǒng)應(yīng)用,2014,14(7):13-15.
[2]向征.基于C30的嵌入式計(jì)算機(jī)自主調(diào)試環(huán)境的建立和軟件設(shè)計(jì)[J].微電子學(xué)與計(jì)算機(jī),1999(3):18-20,56.
[3]文躍榮.基于UART的電能芯片在線調(diào)試設(shè)計(jì)[D].長(zhǎng)沙:湖南大學(xué),2012.
[4]劉曉升,王宜懷.HC08系列微控制器在線調(diào)試的關(guān)鍵技術(shù)分析[J].計(jì)算機(jī)工程與設(shè)計(jì),2009,30(3):532-535.
[5]龔蘭蘭,劉曉升,朱巧明.遠(yuǎn)程調(diào)試系統(tǒng)的關(guān)鍵技術(shù)分析[J].計(jì)算機(jī)應(yīng)用與軟件,2010,27(10):258-261.
[6]梁泉.嵌入式系統(tǒng)交叉調(diào)試器的設(shè)計(jì)與實(shí)現(xiàn)[D].成都:電子科技大學(xué),2008.
[7]趙民棟.嵌入式軟件集成開(kāi)發(fā)環(huán)境中調(diào)試器的設(shè)計(jì)與實(shí)現(xiàn)[D].西安:西北工業(yè)大學(xué),2004.